summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Fornal <jakub.fornal@intel.com>2017-09-19 01:19:32 -0700
committerGitHub <noreply@github.com>2017-09-19 01:19:32 -0700
commit213adddc09bbb5a17aa6450a4d47754970bb76fc (patch)
treee4e852ffc9757221612d06a48c49605264898acc
parent10309b48d18740e11736be69d92e069450ac673b (diff)
parent6cd1bffd000c24c4b6298442d77a2253960bfdfb (diff)
downloadOpen-AVB-213adddc09bbb5a17aa6450a4d47754970bb76fc.tar.gz
Merge pull request #15 from AVnu/open-avb-next
Open avb next
-rw-r--r--.gitignore2
-rw-r--r--.travis.yml21
-rw-r--r--CMakeLists.txt3
-rw-r--r--Makefile45
-rw-r--r--README.rst50
-rw-r--r--daemons/gptp/CMakeLists.txt4
-rw-r--r--daemons/gptp/README_GENIVI_DLT.txt48
-rw-r--r--daemons/gptp/README_SYSTEMD_WATCHDOG.txt28
-rw-r--r--daemons/gptp/common/ap_message.cpp6
-rw-r--r--daemons/gptp/common/avbap_message.hpp10
-rw-r--r--daemons/gptp/common/avbts_clock.hpp76
-rw-r--r--daemons/gptp/common/avbts_message.hpp218
-rw-r--r--daemons/gptp/common/avbts_oscondition.hpp2
-rw-r--r--daemons/gptp/common/avbts_osipc.hpp63
-rw-r--r--daemons/gptp/common/avbts_oslock.hpp2
-rw-r--r--daemons/gptp/common/avbts_osnet.hpp16
-rw-r--r--daemons/gptp/common/avbts_osthread.hpp3
-rw-r--r--daemons/gptp/common/avbts_ostimer.hpp2
-rw-r--r--daemons/gptp/common/avbts_port.hpp1690
-rw-r--r--daemons/gptp/common/common_port.cpp751
-rw-r--r--daemons/gptp/common/common_port.hpp1455
-rw-r--r--daemons/gptp/common/common_tstamper.hpp153
-rw-r--r--daemons/gptp/common/ether_port.cpp864
-rw-r--r--daemons/gptp/common/ether_port.hpp636
-rw-r--r--daemons/gptp/common/ether_tstamper.hpp73
-rw-r--r--daemons/gptp/common/gptp_cfg.cpp119
-rw-r--r--daemons/gptp/common/gptp_cfg.hpp62
-rw-r--r--daemons/gptp/common/gptp_log.cpp55
-rw-r--r--daemons/gptp/common/gptp_log.hpp46
-rw-r--r--daemons/gptp/common/ieee1588.hpp251
-rw-r--r--daemons/gptp/common/ieee1588clock.cpp110
-rw-r--r--daemons/gptp/common/ieee1588port.cpp1437
-rw-r--r--daemons/gptp/common/ipcdef.hpp41
-rw-r--r--daemons/gptp/common/ptp_message.cpp258
-rw-r--r--daemons/gptp/common/ptptypes.hpp11
-rw-r--r--daemons/gptp/gptp_cfg.ini27
-rw-r--r--daemons/gptp/linux/build/Makefile40
-rw-r--r--daemons/gptp/linux/shm_test/shm_test.cpp27
-rw-r--r--daemons/gptp/linux/src/daemon_cl.cpp175
-rw-r--r--daemons/gptp/linux/src/linux_hal_common.cpp255
-rw-r--r--daemons/gptp/linux/src/linux_hal_common.hpp90
-rw-r--r--daemons/gptp/linux/src/linux_hal_generic.cpp74
-rw-r--r--daemons/gptp/linux/src/linux_hal_generic.hpp22
-rw-r--r--daemons/gptp/linux/src/linux_hal_generic_adj.cpp2
-rw-r--r--daemons/gptp/linux/src/linux_hal_i210.cpp4
-rw-r--r--daemons/gptp/linux/src/linux_hal_intelce.cpp8
-rw-r--r--daemons/gptp/linux/src/linux_hal_intelce.hpp8
-rw-r--r--daemons/gptp/linux/src/linux_hal_persist_file.cpp15
-rw-r--r--daemons/gptp/linux/src/watchdog.cpp46
-rw-r--r--daemons/gptp/linux/src/watchdog.hpp21
-rw-r--r--daemons/gptp/windows/daemon_cl/IPCListener.hpp15
-rw-r--r--daemons/gptp/windows/daemon_cl/daemon_cl.cpp103
-rw-r--r--daemons/gptp/windows/daemon_cl/gptp.manifest31
-rw-r--r--daemons/gptp/windows/daemon_cl/tsc.hpp19
-rw-r--r--daemons/gptp/windows/daemon_cl/windows_hal.cpp100
-rw-r--r--daemons/gptp/windows/daemon_cl/windows_hal.hpp133
-rw-r--r--daemons/gptp/windows/daemon_cl/windows_ipc.hpp52
-rw-r--r--daemons/gptp/windows/gptp.sln38
-rw-r--r--daemons/maap/CMakeLists.txt39
-rw-r--r--daemons/maap/README.rst403
-rw-r--r--daemons/maap/common/intervals.c220
-rw-r--r--daemons/maap/common/intervals.h207
-rw-r--r--daemons/maap/common/maap.c1091
-rw-r--r--daemons/maap/common/maap.h253
-rw-r--r--daemons/maap/common/maap_iface.h108
-rw-r--r--daemons/maap/common/maap_log.h253
-rw-r--r--daemons/maap/common/maap_log_queue.c207
-rw-r--r--daemons/maap/common/maap_log_queue.h78
-rw-r--r--daemons/maap/common/maap_net.c258
-rw-r--r--daemons/maap/common/maap_net.h99
-rw-r--r--daemons/maap/common/maap_packet.c205
-rw-r--r--daemons/maap/common/maap_packet.h117
-rw-r--r--daemons/maap/common/maap_parse.c222
-rw-r--r--daemons/maap/common/maap_parse.h70
-rw-r--r--daemons/maap/common/maap_protocol.c334
-rw-r--r--daemons/maap/common/maap_protocol.h175
-rw-r--r--daemons/maap/common/maap_timer.h146
-rw-r--r--daemons/maap/common/platform.h74
-rw-r--r--daemons/maap/doc/CMakeLists.txt24
-rw-r--r--daemons/maap/doc/Doxyfile.in2431
-rw-r--r--daemons/maap/doc/mainpage.dox24
-rw-r--r--daemons/maap/linux/Makefile15
-rw-r--r--daemons/maap/linux/build/Makefile47
-rw-r--r--daemons/maap/linux/maap_linux.c279
-rw-r--r--daemons/maap/linux/src/maap_daemon.c1020
-rw-r--r--daemons/maap/linux/src/maap_helper_linux.h183
-rw-r--r--daemons/maap/linux/src/maap_log_linux.c439
-rw-r--r--daemons/maap/linux/src/maap_timer_linux.c157
-rw-r--r--daemons/maap/test/CMakeLists.txt15
-rw-r--r--daemons/maap/test/maap_log_dummy.c127
-rw-r--r--daemons/maap/test/maap_log_dummy.h57
-rw-r--r--daemons/maap/test/maap_test.c648
-rw-r--r--daemons/maap/test/maap_timer_dummy.c165
-rw-r--r--daemons/maap/test/maap_timer_dummy.h47
-rw-r--r--daemons/maap/test/test_intervals.c223
-rw-r--r--daemons/maap/tests/AllTests.cpp39
-rw-r--r--daemons/maap/tests/CMakeLists.txt38
-rw-r--r--daemons/maap/tests/maap_net_tests.cpp135
-rw-r--r--daemons/maap/tests/maap_packet_tests.cpp184
-rw-r--r--daemons/maap/tests/maap_tests.cpp1467
-rw-r--r--daemons/maap/windows/src/maap_log_windows.c452
-rw-r--r--daemons/maap/windows/src/maap_main.c3
-rw-r--r--daemons/maap/windows/src/maap_timer_windows.c165
-rw-r--r--daemons/mrpd/mmrp.c6
-rw-r--r--daemons/mrpd/mrp.c15
-rw-r--r--daemons/mrpd/mrp.h1
-rw-r--r--daemons/mrpd/mrpctl.c6
-rw-r--r--daemons/mrpd/msrp.c11
-rw-r--r--daemons/mrpd/msrp.h2
-rw-r--r--daemons/mrpd/mvrp.c6
-rw-r--r--daemons/mrpd/tests/simple/CMakeLists.txt16
-rw-r--r--daemons/mrpd/tests/simple/mrp_doubles.c9
-rw-r--r--daemons/mrpd/tests/simple/mrp_doubles.h15
-rw-r--r--daemons/mrpd/tests/simple/mvrp_pdu_tests.cpp157
-rw-r--r--daemons/mrpd/tests/simple/parse_tests.cpp16
-rw-r--r--daemons/mrpd/tests/simple/sample_mvrp_packets.h117
-rw-r--r--daemons/shaper/LICENSE25
-rw-r--r--daemons/shaper/Makefile37
-rw-r--r--daemons/shaper/README.rst38
-rw-r--r--daemons/shaper/src/platform.h74
-rw-r--r--daemons/shaper/src/shaper_daemon.c986
-rw-r--r--daemons/shaper/src/shaper_helper_linux.h182
-rw-r--r--daemons/shaper/src/shaper_log.h267
-rw-r--r--daemons/shaper/src/shaper_log_linux.c445
-rw-r--r--daemons/shaper/src/shaper_log_queue.c200
-rw-r--r--daemons/shaper/src/shaper_log_queue.h78
-rw-r--r--examples/common/Makefile8
-rw-r--r--examples/gstreamer-avb-plugins/gst-plugin/src/gstavbsink.c2
-rw-r--r--examples/jackd-listener/Makefile18
-rw-r--r--examples/jackd-talker/Makefile32
-rw-r--r--examples/live_stream/Makefile39
-rw-r--r--examples/live_stream/listener.c5
-rw-r--r--examples/simple_listener/Makefile18
-rw-r--r--examples/simple_listener/simple_listener.c222
-rw-r--r--examples/simple_rx/Makefile30
-rw-r--r--examples/simple_rx/simple_rx.c8
-rw-r--r--examples/simple_talker/Makefile31
-rw-r--r--kmod/igb/Makefile11
-rw-r--r--kmod/igb/e1000_82575.c11
-rw-r--r--kmod/igb/e1000_defines.h67
-rw-r--r--kmod/igb/e1000_regs.h13
-rw-r--r--kmod/igb/igb.h11
-rw-r--r--kmod/igb/igb_ethtool.c8
-rw-r--r--kmod/igb/igb_main.c193
-rw-r--r--kmod/igb/igb_ptp.c349
-rw-r--r--lib/avtp_pipeline/LICENSE15
-rw-r--r--lib/avtp_pipeline/README.md38
-rw-r--r--lib/avtp_pipeline/acmp/CMakeLists.txt9
-rw-r--r--lib/avtp_pipeline/acmp/openavb_acmp.c147
-rw-r--r--lib/avtp_pipeline/acmp/openavb_acmp.h195
-rw-r--r--lib/avtp_pipeline/acmp/openavb_acmp_message.c424
-rw-r--r--lib/avtp_pipeline/acmp/openavb_acmp_message.h50
-rw-r--r--lib/avtp_pipeline/acmp/openavb_acmp_pub.h42
-rw-r--r--lib/avtp_pipeline/acmp/openavb_acmp_sm_controller.c435
-rw-r--r--lib/avtp_pipeline/acmp/openavb_acmp_sm_controller.h67
-rw-r--r--lib/avtp_pipeline/acmp/openavb_acmp_sm_listener.c982
-rw-r--r--lib/avtp_pipeline/acmp/openavb_acmp_sm_listener.h94
-rw-r--r--lib/avtp_pipeline/acmp/openavb_acmp_sm_talker.c682
-rw-r--r--lib/avtp_pipeline/acmp/openavb_acmp_sm_talker.h76
-rw-r--r--lib/avtp_pipeline/adp/CMakeLists.txt9
-rw-r--r--lib/avtp_pipeline/adp/openavb_adp.c181
-rw-r--r--lib/avtp_pipeline/adp/openavb_adp.h93
-rw-r--r--lib/avtp_pipeline/adp/openavb_adp_message.c464
-rw-r--r--lib/avtp_pipeline/adp/openavb_adp_message.h50
-rw-r--r--lib/avtp_pipeline/adp/openavb_adp_pub.h90
-rw-r--r--lib/avtp_pipeline/adp/openavb_adp_sm_advertise_entity.c252
-rw-r--r--lib/avtp_pipeline/adp/openavb_adp_sm_advertise_entity.h63
-rw-r--r--lib/avtp_pipeline/adp/openavb_adp_sm_advertise_interface.c341
-rw-r--r--lib/avtp_pipeline/adp/openavb_adp_sm_advertise_interface.h73
-rw-r--r--lib/avtp_pipeline/adp/openavb_adp_sm_discovery.c45
-rw-r--r--lib/avtp_pipeline/adp/openavb_adp_sm_discovery.h48
-rw-r--r--lib/avtp_pipeline/aecp/CMakeLists.txt8
-rw-r--r--lib/avtp_pipeline/aecp/openavb_aecp.c98
-rw-r--r--lib/avtp_pipeline/aecp/openavb_aecp.h408
-rw-r--r--lib/avtp_pipeline/aecp/openavb_aecp_cmd_get_counters.c223
-rw-r--r--lib/avtp_pipeline/aecp/openavb_aecp_cmd_get_counters.h103
-rw-r--r--lib/avtp_pipeline/aecp/openavb_aecp_message.c1049
-rw-r--r--lib/avtp_pipeline/aecp/openavb_aecp_message.h50
-rw-r--r--lib/avtp_pipeline/aecp/openavb_aecp_pub.h42
-rw-r--r--lib/avtp_pipeline/aecp/openavb_aecp_sm_entity_model_entity.c1378
-rw-r--r--lib/avtp_pipeline/aecp/openavb_aecp_sm_entity_model_entity.h71
-rw-r--r--lib/avtp_pipeline/aem/CMakeLists.txt21
-rw-r--r--lib/avtp_pipeline/aem/openavb_aem.c534
-rw-r--r--lib/avtp_pipeline/aem/openavb_aem.h103
-rw-r--r--lib/avtp_pipeline/aem/openavb_aem_pub.h80
-rw-r--r--lib/avtp_pipeline/aem/openavb_aem_types_pub.h1339
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_audio_cluster.c179
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_audio_cluster.h46
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_audio_cluster_pub.h65
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_audio_map.c180
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_audio_map.h47
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_audio_map_pub.h69
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_audio_unit.c297
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_audio_unit.h47
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_audio_unit_pub.h99
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_avb_interface.c244
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_avb_interface.h46
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_avb_interface_pub.h73
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_clock_domain.c209
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_clock_domain.h47
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_clock_domain_pub.h66
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_clock_source.c205
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_clock_source.h46
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_clock_source_pub.h65
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_configuration.c197
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_configuration.h46
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_configuration_pub.h70
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_control.c502
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_control.h46
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_control_pub.h111
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_entity.c411
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_entity.h46
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_entity_pub.h108
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_external_port_io.c209
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_external_port_io.h46
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_external_port_io_pub.h66
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_jack_io.c235
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_jack_io.h46
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_jack_io_pub.h66
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_locale.c208
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_locale.h46
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_locale_pub.h69
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_locale_strings_handler.c230
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_locale_strings_handler.h44
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_locale_strings_handler_pub.h91
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_stream_io.c572
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_stream_io.h47
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_stream_io_pub.h111
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_stream_port_io.c207
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_stream_port_io.h46
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_stream_port_io_pub.h65
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_strings.c193
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_strings.h46
-rw-r--r--lib/avtp_pipeline/aem/openavb_descriptor_strings_pub.h65
-rw-r--r--lib/avtp_pipeline/avdecc/CMakeLists.txt12
-rw-r--r--lib/avtp_pipeline/avdecc/avdecc.ini82
-rw-r--r--lib/avtp_pipeline/avdecc/openavb_avdecc.c509
-rw-r--r--lib/avtp_pipeline/avdecc/openavb_avdecc.h210
-rw-r--r--lib/avtp_pipeline/avdecc/openavb_avdecc_pipeline_interaction_pub.h71
-rw-r--r--lib/avtp_pipeline/avdecc/openavb_avdecc_pub.h145
-rw-r--r--lib/avtp_pipeline/avdecc/openavb_avdecc_read_ini_pub.h197
-rwxr-xr-xlib/avtp_pipeline/avdecc/shutdown_openavb_avdecc.sh18
-rw-r--r--lib/avtp_pipeline/avdecc_msg/CMakeLists.txt2
-rw-r--r--lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg.c192
-rw-r--r--lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg.h216
-rw-r--r--lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_client.c723
-rw-r--r--lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_client.h60
-rw-r--r--lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_server.c470
-rw-r--r--lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_server.h57
-rw-r--r--lib/avtp_pipeline/avtp/openavb_avtp.c108
-rw-r--r--lib/avtp_pipeline/avtp/openavb_avtp.h6
-rw-r--r--lib/avtp_pipeline/avtp/openavb_avtp_time.c1
-rw-r--r--lib/avtp_pipeline/avtp/openavb_avtp_time_pub.h11
-rw-r--r--lib/avtp_pipeline/avtp_avdecc.mk23
-rw-r--r--lib/avtp_pipeline/avtp_pipeline.mk9
-rw-r--r--lib/avtp_pipeline/documents/sdk_avtp_interface_module_dev.md7
-rw-r--r--lib/avtp_pipeline/documents/sdk_avtp_stream_cfg.md163
-rw-r--r--lib/avtp_pipeline/documents/sdk_eavb_integration.md2
-rw-r--r--lib/avtp_pipeline/documents/sdk_notes_media_queue_usage.md6
-rw-r--r--lib/avtp_pipeline/documents/sdk_overview.md17
-rw-r--r--lib/avtp_pipeline/endpoint/CMakeLists.txt4
-rw-r--r--lib/avtp_pipeline/endpoint/endpoint.ini29
-rw-r--r--lib/avtp_pipeline/endpoint/openavb_endpoint.c60
-rw-r--r--lib/avtp_pipeline/endpoint/openavb_endpoint.h46
-rw-r--r--lib/avtp_pipeline/endpoint/openavb_endpoint_client.c35
-rw-r--r--lib/avtp_pipeline/endpoint/openavb_endpoint_server.c75
-rw-r--r--lib/avtp_pipeline/include/avb_sched.h1
-rw-r--r--lib/avtp_pipeline/include/openavb_audio_pub.h1
-rwxr-xr-xlib/avtp_pipeline/include/openavb_intf_pub.h52
-rw-r--r--lib/avtp_pipeline/include/openavb_log.h1
-rw-r--r--lib/avtp_pipeline/include/openavb_log_pub.h522
-rwxr-xr-xlib/avtp_pipeline/include/openavb_map_pub.h19
-rw-r--r--lib/avtp_pipeline/include/openavb_platform.h1
-rw-r--r--lib/avtp_pipeline/include/openavb_platform_pub.h85
-rw-r--r--lib/avtp_pipeline/include/openavb_pub.h13
-rw-r--r--lib/avtp_pipeline/include/openavb_trace.h1
-rw-r--r--lib/avtp_pipeline/include/openavb_trace_pub.h1
-rw-r--r--lib/avtp_pipeline/include/openavb_types.h1
-rw-r--r--lib/avtp_pipeline/include/openavb_types_base.h1
-rw-r--r--lib/avtp_pipeline/include/openavb_types_base_pub.h241
-rw-r--r--lib/avtp_pipeline/include/openavb_types_pub.h1
-rw-r--r--lib/avtp_pipeline/inih/ini.c594
-rw-r--r--lib/avtp_pipeline/inih/ini.h144
-rw-r--r--lib/avtp_pipeline/intf_ctrl/ctrl_listener.ini6
-rw-r--r--lib/avtp_pipeline/intf_ctrl/ctrl_mux_listener.ini6
-rw-r--r--lib/avtp_pipeline/intf_ctrl/ctrl_mux_talker.ini6
-rw-r--r--lib/avtp_pipeline/intf_ctrl/ctrl_talker.ini6
-rwxr-xr-xlib/avtp_pipeline/intf_ctrl/openavb_intf_ctrl.c1
-rwxr-xr-xlib/avtp_pipeline/intf_ctrl/openavb_intf_ctrl_pub.h1
-rw-r--r--lib/avtp_pipeline/intf_echo/echo_listener.ini6
-rw-r--r--lib/avtp_pipeline/intf_echo/echo_listener_auto.ini6
-rw-r--r--lib/avtp_pipeline/intf_echo/echo_talker.ini6
-rw-r--r--lib/avtp_pipeline/intf_echo/echo_talker_auto.ini6
-rwxr-xr-xlib/avtp_pipeline/intf_echo/openavb_intf_echo.c38
-rw-r--r--lib/avtp_pipeline/intf_logger/openavb_intf_logger.c403
-rw-r--r--lib/avtp_pipeline/intf_null/null_listener.ini6
-rw-r--r--lib/avtp_pipeline/intf_null/null_talker.ini6
-rwxr-xr-xlib/avtp_pipeline/intf_null/openavb_intf_null.c1
-rw-r--r--lib/avtp_pipeline/intf_tonegen/openavb_intf_tonegen.c1231
-rw-r--r--lib/avtp_pipeline/intf_tonegen/openavb_intf_tonegen.md22
-rw-r--r--lib/avtp_pipeline/intf_tonegen/tonegen_talker.ini16
-rw-r--r--lib/avtp_pipeline/intf_tonegen/tonegen_talker_lowlatency.ini174
-rw-r--r--lib/avtp_pipeline/intf_viewer/latency_listener.ini6
-rw-r--r--lib/avtp_pipeline/intf_viewer/latency_talker.ini6
-rwxr-xr-xlib/avtp_pipeline/intf_viewer/openavb_intf_viewer.c1041
-rw-r--r--lib/avtp_pipeline/intf_viewer/viewer_listener.ini6
-rw-r--r--lib/avtp_pipeline/maap/openavb_maap.h27
-rwxr-xr-xlib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio.c263
-rwxr-xr-xlib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio_pub.h17
-rwxr-xr-xlib/avtp_pipeline/map_ctrl/openavb_map_ctrl.c1
-rwxr-xr-xlib/avtp_pipeline/map_ctrl/openavb_map_ctrl_pub.h1
-rwxr-xr-xlib/avtp_pipeline/map_h264/openavb_map_h264.c1
-rwxr-xr-xlib/avtp_pipeline/map_h264/openavb_map_h264_pub.h1
-rwxr-xr-xlib/avtp_pipeline/map_mjpeg/openavb_map_mjpeg.c1
-rwxr-xr-xlib/avtp_pipeline/map_mjpeg/openavb_map_mjpeg_pub.h1
-rw-r--r--lib/avtp_pipeline/map_mpeg2ts/demo_listener.ini6
-rw-r--r--lib/avtp_pipeline/map_mpeg2ts/demo_talker.ini6
-rwxr-xr-xlib/avtp_pipeline/map_mpeg2ts/openavb_map_mpeg2ts.c1
-rwxr-xr-xlib/avtp_pipeline/map_mpeg2ts/openavb_map_mpeg2ts_pub.h1
-rw-r--r--lib/avtp_pipeline/map_mpeg2ts/ts_packet_size.c1
-rwxr-xr-xlib/avtp_pipeline/map_null/openavb_map_null.c1
-rwxr-xr-xlib/avtp_pipeline/map_null/openavb_map_null_pub.h1
-rwxr-xr-xlib/avtp_pipeline/map_pipe/openavb_map_pipe.c3
-rwxr-xr-xlib/avtp_pipeline/map_pipe/openavb_map_pipe_pub.h1
-rwxr-xr-xlib/avtp_pipeline/map_uncmp_audio/openavb_map_uncmp_audio.c64
-rwxr-xr-xlib/avtp_pipeline/map_uncmp_audio/openavb_map_uncmp_audio_pub.h41
-rw-r--r--lib/avtp_pipeline/map_uncmp_audio/uncmp_audio_map.md2
-rw-r--r--lib/avtp_pipeline/mcr/CMakeLists.txt5
-rw-r--r--lib/avtp_pipeline/mcr/openavb_mcr_hal_pub.h131
-rw-r--r--lib/avtp_pipeline/mcs/CMakeLists.txt5
-rw-r--r--lib/avtp_pipeline/mcs/openavb_mcs.c77
-rw-r--r--lib/avtp_pipeline/mcs/openavb_mcs.h52
-rw-r--r--lib/avtp_pipeline/mediaq/openavb_mediaq.c79
-rw-r--r--lib/avtp_pipeline/mediaq/openavb_mediaq.h1
-rw-r--r--lib/avtp_pipeline/mediaq/openavb_mediaq_pub.h27
-rw-r--r--lib/avtp_pipeline/openavb_common/CMakeLists.txt12
-rw-r--r--lib/avtp_pipeline/openavb_common/mrp_client.c391
-rw-r--r--lib/avtp_pipeline/platform/Linux/CMakeLists.txt261
-rw-r--r--lib/avtp_pipeline/platform/Linux/arm_imx6sx_linux.cmake26
-rw-r--r--lib/avtp_pipeline/platform/Linux/avb_avdecc/CMakeLists.txt25
-rw-r--r--lib/avtp_pipeline/platform/Linux/avb_avdecc/openavb_avdecc.c178
-rw-r--r--lib/avtp_pipeline/platform/Linux/avb_host/CMakeLists.txt20
-rw-r--r--lib/avtp_pipeline/platform/Linux/avb_host/openavb_harness.c57
-rw-r--r--lib/avtp_pipeline/platform/Linux/avb_host/openavb_host.c49
-rw-r--r--lib/avtp_pipeline/platform/Linux/avdecc/CMakeLists.txt2
-rw-r--r--lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_cfg.c279
-rw-r--r--lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_cfg.h50
-rw-r--r--lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_osal.c203
-rw-r--r--lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_osal.h45
-rw-r--r--lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_pipeline_interaction.c513
-rw-r--r--lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_read_ini.c620
-rw-r--r--lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_save_state.c363
-rw-r--r--lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_save_state.h70
-rw-r--r--lib/avtp_pipeline/platform/Linux/avdecc_msg/CMakeLists.txt2
-rw-r--r--lib/avtp_pipeline/platform/Linux/avdecc_msg/openavb_avdecc_msg_client_osal.c181
-rw-r--r--lib/avtp_pipeline/platform/Linux/avdecc_msg/openavb_avdecc_msg_osal.h64
-rw-r--r--lib/avtp_pipeline/platform/Linux/avdecc_msg/openavb_avdecc_msg_server_osal.c271
-rw-r--r--lib/avtp_pipeline/platform/Linux/avtp/openavb_avtp_time_osal.c1
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.c129
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.h30
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_client_osal.c3
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal.c477
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal.h1
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_maap.c596
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_ptp.c (renamed from lib/avtp_pipeline/platform/x86_i210/openavb_time_hal.c)147
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_shaper.c426
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_srp.c412
-rw-r--r--lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_server_osal.c10
-rw-r--r--lib/avtp_pipeline/platform/Linux/generic.cmake16
-rw-r--r--lib/avtp_pipeline/platform/Linux/gst_al/gst_al.h1
-rw-r--r--lib/avtp_pipeline/platform/Linux/gst_al/gst_al_01.c1
-rw-r--r--lib/avtp_pipeline/platform/Linux/gst_al/gst_al_10.c1
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_file_talker.ini10
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener.ini21
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener_auto.ini17
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_talker.ini20
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_intf.md31
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_listener.ini6
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_talker.ini6
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_alsa/openavb_intf_alsa.c220
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_h264_gst/h264_gst_listener.ini6
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_h264_gst/h264_gst_talker.ini6
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_h264_gst/openavb_intf_h264_gst.c32
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_gst_listener.ini6
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_gst_talker.ini6
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/openavb_intf_mjpeg_gst.c1
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/mpeg2ts_file_listener.ini6
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/mpeg2ts_file_talker.ini6
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/openavb_intf_mpeg2ts_file.c1
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/mpeg2ts_gst_listener.ini6
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/mpeg2ts_gst_talker.ini6
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/openavb_intf_mpeg2ts_gst.c1
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_wav_file/openavb_intf_wav_file.c69
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_wav_file/wav_file_listener.ini6
-rw-r--r--lib/avtp_pipeline/platform/Linux/intf_wav_file/wav_file_talker.ini6
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_grandmaster_osal.c152
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_grandmaster_osal.h (renamed from lib/avtp_pipeline/platform/x86_i210/openavb_time_hal.h)73
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_grandmaster_osal_pub.h62
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_os_services_osal.h35
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_os_services_osal_pub.h2
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_osal.c110
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_osal.h1
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_osal_avdecc.c58
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_osal_endpoint.c112
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_osal_pub.h6
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_poll_osal.h1
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_tasks.h8
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_time_osal.c404
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_time_osal.h61
-rw-r--r--lib/avtp_pipeline/platform/Linux/openavb_time_osal_pub.h3
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/avtp_rx.c1
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/igb_rawsock.c7
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/igb_rawsock.h3
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/openavb_rawsock.c40
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/pcap_rawsock.c74
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/pcap_rawsock.h8
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/rawsock_rx.c1
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/rawsock_tx.c13
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/ring_rawsock.c28
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/ring_rawsock.h3
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/sendmmsg_rawsock.c503
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/sendmmsg_rawsock.h110
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.c54
-rw-r--r--lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.h12
-rw-r--r--lib/avtp_pipeline/platform/Linux/tl/openavb_tl_osal.c120
-rw-r--r--lib/avtp_pipeline/platform/Linux/x86_i210_linux.cmake43
-rw-r--r--lib/avtp_pipeline/platform/generic/include/linux/ptp_clock.h29
-rw-r--r--lib/avtp_pipeline/platform/generic/mcr/openavb_mcr_hal.c (renamed from lib/avtp_pipeline/platform/Linux/openavb_ether_osal.h)103
-rw-r--r--lib/avtp_pipeline/platform/generic/mcr/openavb_mcr_hal.h (renamed from lib/avtp_pipeline/platform/Linux/openavb_ether_osal.c)77
-rw-r--r--lib/avtp_pipeline/platform/generic/openavb_hal.h1
-rw-r--r--lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal.c79
-rw-r--r--lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal.h75
-rw-r--r--lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal_pub.h77
-rw-r--r--lib/avtp_pipeline/platform/platTCAL/GNU/openavb_tcal_pub.h77
-rw-r--r--lib/avtp_pipeline/platform/platTCAL/GNU/openavb_time_tcal_pub.h99
-rw-r--r--lib/avtp_pipeline/platform/platTCAL/GNU/openavb_types_base_tcal_pub.h81
-rw-r--r--lib/avtp_pipeline/platform/platTCAL/GNU/openavb_warnings_tcal.h75
-rw-r--r--lib/avtp_pipeline/platform/platTCAL/GNU/rawsock/openavb_rawsock_tcal.h119
-rw-r--r--lib/avtp_pipeline/platform/x86_i210/mcr/openavb_mcr_hal.c125
-rw-r--r--lib/avtp_pipeline/platform/x86_i210/mcr/openavb_mcr_hal.h75
-rw-r--r--lib/avtp_pipeline/platform/x86_i210/openavb_hal.h77
-rw-r--r--lib/avtp_pipeline/platform/x86_i210/openavb_igb.c (renamed from lib/avtp_pipeline/platform/x86_i210/openavb_ether_hal.c)7
-rw-r--r--lib/avtp_pipeline/platform/x86_i210/openavb_igb.h (renamed from lib/avtp_pipeline/platform/x86_i210/openavb_ether_hal.h)9
-rw-r--r--lib/avtp_pipeline/qmgr/openavb_qmgr.c37
-rw-r--r--lib/avtp_pipeline/qmgr/openavb_qmgr.h1
-rw-r--r--lib/avtp_pipeline/rawsock/CMakeLists.txt19
-rw-r--r--lib/avtp_pipeline/rawsock/openavb_rawsock.h5
-rw-r--r--lib/avtp_pipeline/rawsock/rawsock_impl.c27
-rw-r--r--lib/avtp_pipeline/rawsock/rawsock_impl.h3
-rw-r--r--lib/avtp_pipeline/shaper/openavb_shaper.h49
-rwxr-xr-xlib/avtp_pipeline/srp/openavb_srp.h21
-rwxr-xr-xlib/avtp_pipeline/srp/openavb_srp_api.h7
-rw-r--r--lib/avtp_pipeline/tl/CMakeLists.txt3
-rw-r--r--lib/avtp_pipeline/tl/openavb_listener.c88
-rw-r--r--lib/avtp_pipeline/tl/openavb_listener.h4
-rw-r--r--lib/avtp_pipeline/tl/openavb_listener_endpoint.c25
-rw-r--r--lib/avtp_pipeline/tl/openavb_listener_no_endpoint.c161
-rw-r--r--lib/avtp_pipeline/tl/openavb_talker.c133
-rw-r--r--lib/avtp_pipeline/tl/openavb_talker.h21
-rw-r--r--lib/avtp_pipeline/tl/openavb_talker_endpoint.c68
-rw-r--r--lib/avtp_pipeline/tl/openavb_talker_no_endpoint.c315
-rwxr-xr-xlib/avtp_pipeline/tl/openavb_tl.c1501
-rwxr-xr-xlib/avtp_pipeline/tl/openavb_tl.h31
-rw-r--r--lib/avtp_pipeline/tl/openavb_tl_endpoint.c126
-rw-r--r--lib/avtp_pipeline/tl/openavb_tl_no_endpoint.c269
-rwxr-xr-xlib/avtp_pipeline/tl/openavb_tl_pub.h86
-rw-r--r--lib/avtp_pipeline/util/CMakeLists.txt1
-rw-r--r--lib/avtp_pipeline/util/openavb_array.c1
-rw-r--r--lib/avtp_pipeline/util/openavb_array.h1
-rw-r--r--lib/avtp_pipeline/util/openavb_debug.c1
-rw-r--r--lib/avtp_pipeline/util/openavb_debug.h1
-rw-r--r--lib/avtp_pipeline/util/openavb_list.c1
-rw-r--r--lib/avtp_pipeline/util/openavb_list.h21
-rw-r--r--lib/avtp_pipeline/util/openavb_log.c263
-rw-r--r--lib/avtp_pipeline/util/openavb_plugin.c1
-rw-r--r--lib/avtp_pipeline/util/openavb_plugin.h1
-rw-r--r--lib/avtp_pipeline/util/openavb_printbuf.c1
-rw-r--r--lib/avtp_pipeline/util/openavb_printbuf.h1
-rw-r--r--lib/avtp_pipeline/util/openavb_queue.c393
-rw-r--r--lib/avtp_pipeline/util/openavb_queue.h1
-rwxr-xr-xlib/avtp_pipeline/util/openavb_result_codes.c2
-rw-r--r--lib/avtp_pipeline/util/openavb_result_codes.h14
-rw-r--r--lib/avtp_pipeline/util/openavb_time.c32
-rw-r--r--lib/avtp_pipeline/util/openavb_time.h5
-rw-r--r--lib/avtp_pipeline/util/openavb_timestamp.c1
-rw-r--r--lib/avtp_pipeline/util/openavb_timestamp.h1
-rw-r--r--lib/common/Makefile23
-rw-r--r--lib/common/avb.h200
-rw-r--r--lib/common/avb_avtp.c (renamed from lib/common/avb.c)345
-rw-r--r--lib/common/avb_avtp.h151
-rw-r--r--lib/common/avb_gptp.c149
-rw-r--r--lib/common/avb_gptp.h50
-rw-r--r--lib/common/avb_igb.c77
-rw-r--r--lib/common/avb_igb.h10
-rw-r--r--lib/common/avb_srp.h6
-rw-r--r--lib/igb/igb.c373
-rw-r--r--lib/igb/igb_internal.h3
-rwxr-xr-xrun_maap.sh10
-rwxr-xr-xrun_shaper.sh4
-rwxr-xr-xrun_srp.sh2
m---------thirdparty/cpputest0
-rwxr-xr-xtravis.sh1
502 files changed, 55195 insertions, 12133 deletions
diff --git a/.gitignore b/.gitignore
index d01289e0..d328bdcc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,7 @@
*.o
*.swp
*build/
-*.cmake
+*build_avdecc/
*CMakeFiles/
CMakeCache.txt
diff --git a/.travis.yml b/.travis.yml
index f06e4416..8eb91588 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,3 +1,7 @@
+
+dist: trusty
+sudo: required
+
language: c
# git submodules workaround
git:
@@ -6,16 +10,23 @@ git:
before_install:
- sed -i 's/git@github.com:/https:\/\/github.com\//' .gitmodules
- git submodule update --init --recursive
+ - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
- sudo apt-get update -qq
- - sudo apt-get install doxygen graphviz
+ - sudo apt-get install doxygen graphviz gcc-4.8 g++-4.8
+ - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 20
+ - sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 20
+ - sudo update-alternatives --install /usr/bin/cc cc /usr/bin/gcc 30
+ - sudo update-alternatives --set cc /usr/bin/gcc
+ - sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++ 30
+ - sudo update-alternatives --set c++ /usr/bin/g++
compiler:
- gcc
-env: BUILD_KERNEL=3.13.0-36-generic
+env: BUILD_KERNEL=4.4.0-75-generic
install:
- sudo apt-get update -qq
- - sudo apt-get install -y libpcap-dev libpci-dev libsndfile1-dev libjack-dev linux-headers-3.13.0-36-generic cmake
+ - sudo apt-get install -y libpcap-dev libpci-dev libsndfile1-dev libjack-dev linux-headers-4.4.0-75-generic cmake
- sudo apt-get install -y libgstreamer0.10-dev libgstreamer-plugins-base0.10-dev libasound2-dev
- - sudo cp /usr/src/linux-headers-3.13.0-36/include/uapi/linux/ethtool.h /usr/include/linux
- - sudo cp /usr/src/linux-headers-3.13.0-36/include/uapi/linux/ptp_clock.h /usr/include/linux
+ - sudo cp /usr/src/linux-headers-4.4.0-75/include/uapi/linux/ethtool.h /usr/include/linux
+ - sudo cp /usr/src/linux-headers-4.4.0-75/include/uapi/linux/ptp_clock.h /usr/include/linux
script: ./travis.sh
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cba5d830..555d9db3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,9 @@
cmake_minimum_required (VERSION 2.8)
project (open-avb)
enable_testing()
+
+set(C++11 ON CACHE BOOL "Compile with C++11 support" FORCE)
add_subdirectory("thirdparty/cpputest")
add_subdirectory("daemons/common/tests")
add_subdirectory("daemons/mrpd")
+add_subdirectory("daemons/maap")
diff --git a/Makefile b/Makefile
index 2cfe159b..2a931c3a 100644
--- a/Makefile
+++ b/Makefile
@@ -9,13 +9,16 @@ help:
@echo ''
@echo ' lib - igb library'
@echo ''
- @echo ' daemons_all - build all daemons (mrpd gptp maap)'
+ @echo ' daemons_all - build all daemons (mrpd gptp maap shaper)'
@echo ' mrpd - mrpd daemon'
@echo ' gptp - gptp daemon for linux'
@echo ' maap - maap daemon'
+ @echo ' shaper - shaper daemon for linux'
@echo ''
@echo ' avtp_pipeline - AVTP pipeline'
@echo ' avtp_pipeline_doc - AVTP pipeline doc'
+ @echo ' avtp_avdecc - AVTP avdecc'
+ @echo ' avtp_avdecc_doc - AVTP avdecc doc'
@echo ''
@echo ' examples_all - build all examples (simple_talker simple_listener mrp_client live_stream jackd-talker jackd-listener)'
@echo ' simple_talker - simple_talker application'
@@ -44,6 +47,7 @@ lib: FORCE
lib_clean:
$(call descend,lib/igb/,clean)
+ $(call descend,lib/common/,clean)
mrpd:
$(call descend,daemons/$@)
@@ -58,14 +62,26 @@ gptp_clean:
$(call descend,daemons/gptp/linux/build/,clean)
maap:
- $(call descend,daemons/$@/linux/)
+ $(call descend,daemons/$@/linux/build/)
maap_clean:
- $(call descend,daemons/maap/linux/,clean)
+ $(call descend,daemons/maap/linux/build/,clean)
+
+shaper:
+ $(call descend,daemons/$@)
+
+shaper_clean:
+ $(call descend,daemons/shaper/,clean)
+
+daemons_all: mrpd maap gptp shaper
-daemons_all: mrpd maap gptp
+daemons_all_clean: mrpd_clean gptp_clean maap_clean shaper_clean
-daemons_all_clean: mrpd_clean gptp_clean maap_clean
+examples_common:
+ $(call descend,examples/common)
+
+examples_common_clean:
+ $(call descend,examples/common/,clean)
simple_talker:
$(MAKE) lib
@@ -79,7 +95,7 @@ simple_listener:
$(call descend,examples/$@)
simple_listener_clean:
- $(call descend,examples/simple_rx/,clean)
+ $(call descend,examples/simple_listener/,clean)
simple_rx:
$(MAKE) lib
@@ -124,14 +140,23 @@ avtp_pipeline_clean:
avtp_pipeline_doc: lib
$(MAKE) -s -C lib/avtp_pipeline -f avtp_pipeline.mk doc
-examples_all: simple_talker simple_listener mrp_client live_stream jackd-talker \
+avtp_avdecc: lib
+ $(MAKE) -s -C lib/avtp_pipeline -f avtp_avdecc.mk
+
+avtp_avdecc_clean:
+ $(MAKE) -s -C lib/avtp_pipeline -f avtp_avdecc.mk clean
+
+avtp_avdecc_doc: lib
+ $(MAKE) -s -C lib/avtp_pipeline -f avtp_avdecc.mk doc
+
+examples_all: examples_common simple_talker simple_listener mrp_client live_stream jackd-talker \
jackd-listener simple_rx
-examples_all_clean: simple_talker_clean simple_listener_clean mrp_client_clean \
+examples_all_clean: examples_common_clean simple_talker_clean simple_listener_clean mrp_client_clean \
jackd-talker_clean jackd-listener_clean live_stream_clean simple_rx_clean
-all: igb lib daemons_all examples_all avtp_pipeline
+all: igb lib daemons_all examples_all avtp_pipeline avtp_avdecc
-clean: igb_clean lib_clean daemons_all_clean examples_all_clean avtp_pipeline_clean
+clean: igb_clean lib_clean daemons_all_clean examples_all_clean avtp_pipeline_clean avtp_avdecc_clean
.PHONY: FORCE
diff --git a/README.rst b/README.rst
index f4d77cac..e9635b1b 100644
--- a/README.rst
+++ b/README.rst
@@ -3,39 +3,39 @@
|
-.. image:: https://travis-ci.org/AVnu/Open-AVB.svg?branch=open-avb-next
- :target: https://travis-ci.org/AVnu/Open-AVB
+.. image:: https://travis-ci.org/AVnu/OpenAvnu.svg?branch=open-avb-next
+ :target: https://travis-ci.org/AVnu/OpenAvnu
-Open AVB
+OpenAvnu
========
-The Open AVB project is sponsored by the AVnu Alliance.
+The OpenAvnu project is sponsored by the Avnu Alliance.
-The intent is to provide components for building AVB systems. The repository
+The intent is to provide components for building AVB/TSN systems. The repository
contains primarily network building block components - drivers, libraries,
-\example applications and daemon source code - required to build an AVB system.
+\example applications and daemon source code - required to build an AVB/TSN system.
It is planned to eventually include the various packet encapsulation types,
protocol discovery daemons, libraries to convert media clocks to AVB clocks
and vice versa), and drivers.
-This repository does not include all components required to build a full
-production AVB system (e.g. a turnkey solution to stream stored or live audio
-or video content). Some simple example applications are provided which
-illustrate the flow - but a professional AVB system requires a full media stack
-- including audio and video inputs and outputs, media processing elements, and
-various graphical user interfaces. Various companies provide such integrated
+This repository does not include all components required to build a full
+production AVB/TSN system (e.g. a turnkey solution to stream stored or live audio
+or video content). Some simple example applications are provided which
+illustrate the flow - but a professional Audio/Video system requires a full media stack
+- including audio and video inputs and outputs, media processing elements, and
+various graphical user interfaces. Various companies provide such integrated
solutions.
-For more information about AVB, see also the AVnu Alliance webpage at
+For more information about AVB/TSN, see also the Avnu Alliance webpage at
www.avnu.org.
BACKGROUND
===========
-Intel created the Open AVB repository to encourage collaborative source code
-development for AVB technology enabling. By publishing the source code, our
-intent is to encourage standardization, stability and inter-operability between
-multiple vendors. This repository - created by the Intel LAN Access Division -
+Intel created the OpenAvnu repository to encourage collaborative source code
+development for AVB/TSN technology enabling. By publishing the source code, our
+intent is to encourage standardization, stability and inter-operability between
+multiple vendors. This repository - created by the Intel LAN Access Division -
is open for contributions from other vendors.
LICENSING AND CONTRIBUTION GUIDELINES
@@ -62,20 +62,20 @@ will be asked to correct any detected issues prior to a commit. Owners
of submitted third-party content are free to apply changes without supervision
by Intel.
-The Open AVB project has a development mailing list. To subscribe, visit
+The OpenAvnu project has a development mailing list. To subscribe, visit
https://lists.sourceforge.net/lists/listinfo/open-avb-devel to sign up.
WEBSITE
=======
-A github based website for Open-AVB can be found here.
+A github based website for OpenAvnu can be found here.
-+ http://avnu.github.io/Open-AVB
++ http://avnu.github.io/OpenAvnu
GIT SUBMODULES
==============
-After checking out the Open-AVB git repository submodules should be
+After checking out the OpenAvnu git repository submodules should be
configured by going::
git submodule init
@@ -89,14 +89,14 @@ currently available to build mrpd in Windows and linux and CppUTest unit
tests for mrpd. The recommended usage for cmake is to create an out-of-tree
directory for cmake output of generated makefiles or MSVC project files.
-Starting from the Open-AVB dir, one would go::
+Starting from the OpenAvnu dir, one would go::
mkdir tmp
cd tmp
cmake .. -G "Unix Makefiles"
make
-to build in Open-AVB/tmp
+to build in OpenAvnu/tmp
RELATED OPEN SOURCE PROJECTS
============================
@@ -105,7 +105,7 @@ AVDECC
------
Jeff Koftinoff maintains a repository of AVDECC example open
source code. AVDECC is a management layer, similar to SNMP MIB formats,
-which enables remote devices to detect, enumerate and configure AVB-related
+which enables remote devices to detect, enumerate and configure AVB/TSN-related
devices based on their standardized management properties.
+ https://github.com/jdkoftinoff/jdksavdecc-c
@@ -116,7 +116,7 @@ AudioScience has created a 1722.1 C++ controller library which builds on jdkadve
XMOS
----
-XMOS is a semiconductor company providing a reference design for AVB
+XMOS is a semiconductor company providing a reference design for AVB/TSN
endpoints in pro audio and automotive. XMOS endpoint source code is open source
and available on Github - https://github.com/xcore/sw_avb
diff --git a/daemons/gptp/CMakeLists.txt b/daemons/gptp/CMakeLists.txt
index 1cb6d980..4935e665 100644
--- a/daemons/gptp/CMakeLists.txt
+++ b/daemons/gptp/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required (VERSION 2.8)
+cmake_minimum_required (VERSION 3.4)
project (gptp)
include_directories( "./common" )
@@ -18,7 +18,7 @@ elseif(WIN32)
# HAVE_REMOTE change pcap include options
add_definitions(-D_CRT_SECURE_NO_WARNINGS -DHAVE_REMOTE)
include_directories( include "./windows/daemon_cl" $ENV{WPCAP_DIR}/Include )
- file(GLOB GPTP_OS "./windows/daemon_cl/*.cpp")
+ file(GLOB GPTP_OS "./windows/daemon_cl/*.cpp" "./windows/daemon_cl/gptp.manifest")
add_executable (gptp ${GPTP_COMMON} ${GPTP_OS})
target_link_libraries(gptp wpcap Iphlpapi Ws2_32)
diff --git a/daemons/gptp/README_GENIVI_DLT.txt b/daemons/gptp/README_GENIVI_DLT.txt
new file mode 100644
index 00000000..8c40354d
--- /dev/null
+++ b/daemons/gptp/README_GENIVI_DLT.txt
@@ -0,0 +1,48 @@
+## Introduction
+This readme covers the **optional** feature to use GENIVI DLT (Diagnostic Log and Trace)
+for logging withiin gPTP. General information about GENIVI DLT can be found at:
+
+Primary DLT site:
+https://at.projects.genivi.org/wiki/display/PROJ/Diagnostic+Log+and+Trace
+
+DLT on GitHub:
+https://github.com/GENIVI/dlt-daemon
+
+
+## Build Related
+
+DLT support in gPTP is a build time option.
+
+### DLT must be built separately first before it can be used within gPTP.
+- Get the latest DLT from github
+ - https://github.com/GENIVI/dlt-daemon.git
+- Follow instructions in INSTALL file.
+- For example (Building with Shared libraries off)
+ - mkdir build
+ - cd build
+ - cmake -DBUILD_SHARED_LIBS=OFF ..
+ - make
+ - sudo make install
+ - Install places static lib in: /usr/local/lib/x86_64-linux-gnu/static/libdlt.a
+ - Install places header files in: /usr/local/include/dlt/dlt.h
+
+### Building gPTP with DLT loggging enabled.
+- May need to update the gptp Makefile to specify location of DLT headers and lib
+- GENIVI_DLT=1 make gptp
+
+
+## Running
+### DLT
+- See the DLT documentaion about how to run the dlt-daemon.
+- For example
+ - dlt-daemon -d
+ - Runs the daemon
+ - dlt-receive -a localhost
+ - Simple test client included in DLT to recieve DLT messages.
+ - dlt-user-example "Test message"
+ - Test the DLT client and daemon.
+
+### gPTP
+- Run as normal.
+
+
diff --git a/daemons/gptp/README_SYSTEMD_WATCHDOG.txt b/daemons/gptp/README_SYSTEMD_WATCHDOG.txt
new file mode 100644
index 00000000..7cf002b8
--- /dev/null
+++ b/daemons/gptp/README_SYSTEMD_WATCHDOG.txt
@@ -0,0 +1,28 @@
+## Introduction
+This readme covers the **optional** feature to update systemd watchdog during gPTP daemon operation.
+System on which the feature will be used must support systemd.
+
+The solution reads WatchdogSec parameter from service configuration file and notifies watchdog
+every 0.5*WatchdogSec that gPTP daemon is alive.
+If there is no watchdog configuration available or WatchdogSec == 0, watchdog notification won't run.
+
+Watchdog configuration is read once during gPTP daemon startup.
+
+
+## Build Related
+
+Systemd watchdog support in gPTP is a build time option.
+
+### Systemd headers and library must be present in the system while building gPTP with this feature enabled.
+
+
+### Building gPTP with Systemd watchdog handling enabled.
+- SYSTEMD_WATCHDOG=1 make gptp
+
+
+## Running
+
+### gPTP
+- Run as normal.
+
+
diff --git a/daemons/gptp/common/ap_message.cpp b/daemons/gptp/common/ap_message.cpp
index c216e6b3..df121838 100644
--- a/daemons/gptp/common/ap_message.cpp
+++ b/daemons/gptp/common/ap_message.cpp
@@ -26,7 +26,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <ieee1588.hpp>
#include <avbts_clock.hpp>
#include <avbap_message.hpp>
-#include <avbts_port.hpp>
+#include <ether_port.hpp>
#include <avbts_ostimer.hpp>
#include <gptp_log.hpp>
@@ -55,11 +55,11 @@ APMessageTestStatus::~APMessageTestStatus()
{
}
-APMessageTestStatus::APMessageTestStatus(IEEE1588Port * port)
+APMessageTestStatus::APMessageTestStatus( EtherPort *port )
{
}
-void APMessageTestStatus::sendPort(IEEE1588Port * port)
+void APMessageTestStatus::sendPort( EtherPort * port )
{
static uint16_t sequenceId = 0;
diff --git a/daemons/gptp/common/avbap_message.hpp b/daemons/gptp/common/avbap_message.hpp
index fc72c0f5..4c66f758 100644
--- a/daemons/gptp/common/avbap_message.hpp
+++ b/daemons/gptp/common/avbap_message.hpp
@@ -88,9 +88,9 @@ class APMessageTestStatus {
public:
/**
* @brief Default constructor. Creates APMessageTestStatus
- * @param port IEEE1588Port
+ * @param port EtherPort
*/
- APMessageTestStatus(IEEE1588Port * port);
+ APMessageTestStatus( EtherPort *port );
/**
* @brief Destroys APMessageTestStatus interface
@@ -99,11 +99,11 @@ class APMessageTestStatus {
/**
* @brief Assembles APMessageTestStatus message on the
- * IEEE1588Port payload
- * @param port IEEE1588Port where the message will be assembled
+ * EtherPort payload
+ * @param port EtherPort where the message will be assembled
* @return void
*/
- void sendPort(IEEE1588Port * port);
+ void sendPort( EtherPort *port );
};
diff --git a/daemons/gptp/common/avbts_clock.hpp b/daemons/gptp/common/avbts_clock.hpp
index 3e6d686a..feb8d9d1 100644
--- a/daemons/gptp/common/avbts_clock.hpp
+++ b/daemons/gptp/common/avbts_clock.hpp
@@ -36,7 +36,7 @@
#include <stdint.h>
#include <ieee1588.hpp>
-#include <avbts_port.hpp>
+#include <common_port.hpp>
#include <avbts_ostimerq.hpp>
#include <avbts_osipc.hpp>
@@ -61,6 +61,9 @@
adjustment is performed */
#define PHASE_ERROR_MAX_COUNT (6)
+/* Value returned by calcMasterLocalClockRateDifference() to indicate
+ detection of negative time jump in follow_up message */
+#define NEGATIVE_TIME_JUMP 0.0
/**
* @brief Provides the clock quality abstraction.
@@ -121,7 +124,7 @@ private:
float _ppm;
int _phase_error_violation;
- IEEE1588Port *port_list[MAX_PORTS];
+ CommonPort *port_list[MAX_PORTS];
static Timestamp start_time;
Timestamp last_sync_time;
@@ -134,8 +137,6 @@ private:
Timestamp _prev_local_time;
Timestamp _prev_system_time;
- HWTimestamper *_timestamper;
-
OS_IPC *ipc;
OSTimerQueue *timerq;
@@ -163,12 +164,13 @@ private:
/**
* @brief Add a new event to the timer queue
- * @param target IEEE1588Port target
+ * @param target EtherPort target
* @param e Event to be added
* @param time_ns Time in nanoseconds
*/
void addEventTimer
- ( IEEE1588Port * target, Event e, unsigned long long time_ns );
+ ( CommonPort *target, Event e,
+ unsigned long long time_ns );
/**
* @brief Deletes an event from the timer queue
@@ -176,22 +178,21 @@ private:
* @param e Event to be removed
* @return void
*/
- void deleteEventTimer(IEEE1588Port * target, Event e);
+ void deleteEventTimer( CommonPort *target, Event e );
public:
/**
* @brief Instantiates a IEEE 1588 Clock
* @param forceOrdinarySlave Forces it to be an ordinary slave
* @param syntonize if TRUE, clock will syntonize to the master clock
- * @param priority1 It is used in the execution of BCMA. See IEEE 802.1AS Clause 10.3
- * @param timestamper [in] Provides an object for hardware timestamp
+ * @param priority1 It is used in the execution of BCMA. See IEEE 802.1AS-2011 Clause 10.3
* @param timerq_factory [in] Provides a factory object for creating timer queues (managing events)
* @param ipc [in] Inter process communication object
* @param lock_factory [in] Provides a factory object for creating locking a locking mechanism
*/
IEEE1588Clock
(bool forceOrdinarySlave, bool syntonize, uint8_t priority1,
- HWTimestamper *timestamper, OSTimerQueueFactory * timerq_factory,
- OS_IPC * ipc, OSLockFactory *lock_factory );
+ OSTimerQueueFactory * timerq_factory, OS_IPC * ipc,
+ OSLockFactory *lock_factory );
/*
* Destroys the IEEE 1588 clock entity
@@ -325,7 +326,7 @@ public:
}
/**
- * @brief Gets grandmaster priority1 attribute (IEEE 802.1AS clause 10.5.3.2.2)
+ * @brief Gets grandmaster priority1 attribute (IEEE 802.1AS-2011 Clause 10.5.3.2.2)
* @return Grandmaster priority1
*/
unsigned char getGrandmasterPriority1(void) {
@@ -333,7 +334,7 @@ public:
}
/**
- * @brief Gets grandmaster priotity2 attribute (IEEE 802.1AS clause 10.5.3.2.4)
+ * @brief Gets grandmaster priotity2 attribute (IEEE 802.1AS-2011 Clause 10.5.3.2.4)
* @return Grandmaster priority2
*/
unsigned char getGrandmasterPriority2(void) {
@@ -341,7 +342,7 @@ public:
}
/**
- * @brief Sets grandmaster's priority1 attribute (IEEE 802.1AS clause 10.5.3.2.2)
+ * @brief Sets grandmaster's priority1 attribute (IEEE 802.1AS-2011 Clause 10.5.3.2.2)
* @param priority1 value to be set
* @return void
*/
@@ -350,7 +351,7 @@ public:
}
/**
- * @brief Sets grandmaster's priority2 attribute (IEEE 802.1AS clause 10.5.3.2.4)
+ * @brief Sets grandmaster's priority2 attribute (IEEE 802.1AS-2011 Clause 10.5.3.2.4)
* @param priority2 Value to be set
* @return void
*/
@@ -359,7 +360,7 @@ public:
}
/**
- * @brief Gets master steps removed (IEEE 802.1AS clause 10.3.3)
+ * @brief Gets master steps removed (IEEE 802.1AS-2011 Clause 10.3.3)
* @return steps removed value
*/
uint16_t getMasterStepsRemoved(void) {
@@ -367,7 +368,7 @@ public:
}
/**
- * @brief Gets the currentUtcOffset attribute (IEEE 802.1AS clause 10.3.8.9)
+ * @brief Gets the currentUtcOffset attribute (IEEE 802.1AS-2011 Clause 10.3.8.9)
* @return currentUtcOffset
*/
uint16_t getCurrentUtcOffset(void) {
@@ -383,7 +384,7 @@ public:
}
/**
- * @brief Gets IEEE1588Clock priority1 value (IEEE 802.1AS clause 8.6.2.1)
+ * @brief Gets IEEE1588Clock priority1 value (IEEE 802.1AS-2011 Clause 8.6.2.1)
* @return Priority1 value
*/
unsigned char getPriority1(void) {
@@ -391,7 +392,7 @@ public:
}
/**
- * @brief Gets IEEE1588Clock priority2 attribute (IEEE 802.1AS clause 8.6.2.5)
+ * @brief Gets IEEE1588Clock priority2 attribute (IEEE 802.1AS-2011 Clause 8.6.2.5)
* @return Priority2 value
*/
unsigned char getPriority2(void) {
@@ -451,7 +452,7 @@ public:
/**
* @brief Updates the follow up info internal object with the current clock source time
* status values. This method should be called whenever the clockSource entity time
- * base changes (IEEE 802.1AS clause 9.2)
+ * base changes (IEEE 802.1AS-2011 Clause 9.2)
* @return void
*/
void updateFUPInfo(void)
@@ -467,12 +468,13 @@ public:
* @param index Port's index
* @return void
*/
- void registerPort(IEEE1588Port * port, uint16_t index) {
+ void registerPort( CommonPort *port, uint16_t index )
+ {
if (index < MAX_PORTS) {
port_list[index - 1] = port;
}
++number_ports;
- }
+ }
/**
* @brief Gets the current port list instance
@@ -480,7 +482,7 @@ public:
* @param ports [out] Pointer to the port list
* @return
*/
- void getPortList(int &count, IEEE1588Port ** &ports) {
+ void getPortList(int &count, CommonPort ** &ports) {
ports = this->port_list;
count = number_ports;
return;
@@ -494,13 +496,13 @@ public:
/**
* @brief Adds an event to the timer queue using a lock
- * @param target IEEE1588Port target
+ * @param target EtherPort target
* @param e Event to be added
- * @param time_ns current time in nanoseconds
+ * @param time_ns event time in nanoseconds
* @return void
*/
void addEventTimerLocked
- ( IEEE1588Port * target, Event e, unsigned long long time_ns );
+ ( CommonPort *target, Event e, unsigned long long time_ns );
/**
* @brief Deletes and event from the timer queue using a lock
@@ -508,7 +510,7 @@ public:
* @param e Event to be deleted
* @return
*/
- void deleteEventTimerLocked(IEEE1588Port * target, Event e);
+ void deleteEventTimerLocked( CommonPort *target, Event e );
/**
* @brief Calculates the master to local clock rate difference
@@ -542,15 +544,11 @@ public:
* @param asCapable asCapable flag
*/
void setMasterOffset
- ( IEEE1588Port * port, int64_t master_local_offset, Timestamp local_time,
- FrequencyRatio master_local_freq_offset,
- int64_t local_system_offset,
- Timestamp system_time,
- FrequencyRatio local_system_freq_offset,
- unsigned sync_count,
- unsigned pdelay_count,
- PortState port_state,
- bool asCapable );
+ ( CommonPort *port, int64_t master_local_offset,
+ Timestamp local_time, FrequencyRatio master_local_freq_offset,
+ int64_t local_system_offset, Timestamp system_time,
+ FrequencyRatio local_system_freq_offset, unsigned sync_count,
+ unsigned pdelay_count, PortState port_state, bool asCapable );
/**
* @brief Get the IEEE1588Clock identity value
@@ -574,7 +572,7 @@ public:
*/
void restartPDelayAll() {
int number_ports, i, j = 0;
- IEEE1588Port **ports;
+ CommonPort **ports;
getPortList( number_ports, ports );
@@ -590,7 +588,7 @@ public:
*/
int getTxLockAll() {
int number_ports, i, j = 0;
- IEEE1588Port **ports;
+ CommonPort **ports;
getPortList( number_ports, ports );
@@ -610,7 +608,7 @@ public:
*/
int putTxLockAll() {
int number_ports, i, j = 0;
- IEEE1588Port **ports;
+ CommonPort **ports;
getPortList( number_ports, ports );
diff --git a/daemons/gptp/common/avbts_message.hpp b/daemons/gptp/common/avbts_message.hpp
index 1e8220a1..f18d1213 100644
--- a/daemons/gptp/common/avbts_message.hpp
+++ b/daemons/gptp/common/avbts_message.hpp
@@ -165,6 +165,44 @@ enum MulticastType {
MCAST_OTHER
};
+class PTPMessageId {
+ MessageType _messageType;
+ uint16_t _sequenceId;
+public:
+ PTPMessageId() { };
+ PTPMessageId(MessageType messageType, uint16_t sequenceId) :
+ _messageType(messageType),_sequenceId(sequenceId) { }
+ PTPMessageId(const PTPMessageId& a) {
+ _messageType = a._messageType;
+ _sequenceId = a._sequenceId;
+ }
+
+ MessageType getMessageType(void) {
+ return _messageType;
+ }
+ void setMessageType(MessageType messageType) {
+ _messageType = messageType;
+ }
+
+ uint16_t getSequenceId(void) {
+ return _sequenceId;
+ }
+ void setSequenceId(uint16_t sequenceId) {
+ _sequenceId = sequenceId;
+ }
+
+ bool operator!=(const PTPMessageId & cmp) const {
+ return
+ this->_sequenceId != cmp._sequenceId ||
+ this->_messageType != cmp._messageType ? true : false;
+ }
+ bool operator==(const PTPMessageId & cmp)const {
+ return
+ this->_sequenceId == cmp._sequenceId &&
+ this->_messageType == cmp._messageType ? true : false;
+ }
+};
+
/**
* @brief Provides the PTPMessage common interface used during building of
* PTP messages.
@@ -197,9 +235,10 @@ protected:
public:
/**
* @brief Creates the PTPMessageCommon interface
- * @param port IEEE1588Port where the message interface is connected to.
+ * @param port EtherPort where the message interface is
+ * connected to.
*/
- PTPMessageCommon(IEEE1588Port * port);
+ PTPMessageCommon( CommonPort *port );
/**
* @brief Destroys PTPMessageCommon interface
*/
@@ -238,6 +277,29 @@ protected:
}
/**
+ * @brief Check if message type is event
+ * @return true if an event message
+ */
+ bool isEvent( void )
+ {
+ return (( messageType >> 3) & 0x1 ) == 0;
+ }
+
+ /**
+ * @brief Get TX timestamp
+ * @param port used to send message
+ * @param link_speed link speed of message
+ */
+ bool getTxTimestamp( EtherPort *port, uint32_t link_speed );
+
+ /**
+ * @brief Gets the MessageID of the PTP message.
+ * @return MessageId
+ */
+ PTPMessageId getMessageId(void) {
+ return PTPMessageId(messageType, sequenceId);
+ }
+ /**
* @brief Gets the correctionField value in a Little-Endian format.
* @return correctionField
* @todo Little endian format could be removed by adding endianess discovery on
@@ -314,7 +376,7 @@ protected:
* @param port IEEE1588 port
* @return void
*/
- virtual void processMessage(IEEE1588Port * port);
+ virtual void processMessage( EtherPort *port );
/**
* @brief Builds PTP common header
@@ -324,7 +386,8 @@ protected:
void buildCommonHeader(uint8_t * buf);
friend PTPMessageCommon *buildPTPMessage
- (char *buf, int size, LinkLayerAddress * remote, IEEE1588Port * port);
+ ( char *buf, int size, LinkLayerAddress * remote,
+ EtherPort *port );
};
/*Exact fit. No padding*/
@@ -460,7 +523,7 @@ class PTPMessageAnnounce:public PTPMessageCommon {
/**
* @brief Creates the PTPMessageAnnounce interface
*/
- PTPMessageAnnounce(IEEE1588Port * port);
+ PTPMessageAnnounce( CommonPort * port );
/**
* @brief Destroys the PTPMessageAnnounce interface
@@ -500,7 +563,7 @@ class PTPMessageAnnounce:public PTPMessageCommon {
}
/**
- * @brief Gets the steps removed value. See IEEE 802.1AS clause 10.3.3
+ * @brief Gets the steps removed value. See IEEE 802.1AS-2011 Clause 10.3.3
* @return steps removed value
*/
uint16_t getStepsRemoved(void) {
@@ -528,22 +591,25 @@ class PTPMessageAnnounce:public PTPMessageCommon {
/**
* @brief Processes PTP message
- * @param port IEEE1588Port
+ * @param port EtherPort
* @return void
*/
- void processMessage(IEEE1588Port * port);
+ void processMessage( EtherPort *port );
/**
- * @brief Assembles PTPMessageAnnounce message on the IEEE1588Port payload
- * @param port IEEE1588Port where the message will be assembled
+ * @brief Assembles PTPMessageAnnounce message on the
+ * EtherPort payload
+ * @param port EtherPort where the message will be
+ * assembled
* @param destIdentity [in] Destination PortIdentity
- * @return void
+ * @return true on success
*/
- void sendPort(IEEE1588Port * port, PortIdentity * destIdentity);
+ bool sendPort
+ ( CommonPort *port, PortIdentity *destIdentity);
- friend PTPMessageCommon *buildPTPMessage(char *buf, int size,
- LinkLayerAddress * remote,
- IEEE1588Port * port);
+ friend PTPMessageCommon *buildPTPMessage
+ ( char *buf, int size, LinkLayerAddress *remote,
+ EtherPort *port );
};
/**
@@ -557,9 +623,9 @@ class PTPMessageSync : public PTPMessageCommon {
public:
/**
* @brief Default constructor. Creates PTPMessageSync
- * @param port IEEE1588Port
+ * @param port EtherPort
*/
- PTPMessageSync(IEEE1588Port * port);
+ PTPMessageSync( EtherPort *port );
/**
* @brief Destroys PTPMessageSync interface
@@ -568,10 +634,10 @@ class PTPMessageSync : public PTPMessageCommon {
/**
* @brief Processes PTP messages
- * @param port [in] IEEE1588Port
+ * @param port [in] EtherPort
* @return void
*/
- void processMessage(IEEE1588Port * port);
+ void processMessage( EtherPort *port );
/**
* @brief Gets origin timestamp value
@@ -582,15 +648,19 @@ class PTPMessageSync : public PTPMessageCommon {
}
/**
- * @brief Assembles PTPMessageSync message on the IEEE1588Port payload
- * @param port IEEE1588Port where the message will be assembled
+ * @brief Assembles PTPMessageSync message on the
+ * EtherPort payload
+ * @param port EtherPort where the message will be
+ * assembled
* @param destIdentity [in] Destination PortIdentity
- * @return void
+ * @return true on success
*/
- void sendPort(IEEE1588Port * port, PortIdentity * destIdentity);
+ bool sendPort
+ (EtherPort *port, PortIdentity *destIdentity );
friend PTPMessageCommon *buildPTPMessage
- (char *buf, int size, LinkLayerAddress * remote, IEEE1588Port * port);
+ ( char *buf, int size, LinkLayerAddress * remote,
+ EtherPort *port );
};
/* Exact fit. No padding*/
@@ -796,22 +866,26 @@ public:
/**
* @brief Builds the PTPMessageFollowUP object
*/
- PTPMessageFollowUp(IEEE1588Port * port);
+ PTPMessageFollowUp( EtherPort *port );
/**
- * @brief Assembles PTPMessageFollowUp message on the IEEE1588Port payload
- * @param port IEEE1588Port where the message will be assembled
+ * @brief Assembles PTPMessageFollowUp message on the
+ * EtherPort payload
+ * @param port EtherPort where the message will be
+ * assembled
* @param destIdentity [in] Destination PortIdentity
- * @return void
+ * @return true on success
*/
- void sendPort(IEEE1588Port * port, PortIdentity * destIdentity);
+ bool sendPort
+ ( EtherPort *port, PortIdentity *destIdentity );
/**
* @brief Processes PTP messages
- * @param port [in] IEEE1588Port
+ * @param port [in] EtherPort
* @return void
*/
- void processMessage(IEEE1588Port * port);
+ void processMessage( EtherPort *port );
+
/**
* @brief Gets the precise origin timestamp value
* @return preciseOriginTimestamp value
@@ -842,7 +916,8 @@ public:
}
friend PTPMessageCommon *buildPTPMessage
- (char *buf, int size, LinkLayerAddress * remote, IEEE1588Port * port);
+ ( char *buf, int size, LinkLayerAddress *remote,
+ EtherPort *port );
};
/**
@@ -865,22 +940,25 @@ class PTPMessagePathDelayReq : public PTPMessageCommon {
/**
* @brief Builds the PTPMessagePathDelayReq message
*/
- PTPMessagePathDelayReq(IEEE1588Port * port);
+ PTPMessagePathDelayReq( EtherPort *port );
/**
- * @brief Assembles PTPMessagePathDelayReq message on the IEEE1588Port payload
- * @param port IEEE1588Port where the message will be assembled
+ * @brief Assembles PTPMessagePathDelayReq message on the
+ * EtherPort payload
+ * @param port EtherPort where the message will be
+ * assembled
* @param destIdentity [in] Destination PortIdentity
- * @return void
+ * @return true on success
*/
- void sendPort(IEEE1588Port * port, PortIdentity * destIdentity);
+ bool sendPort
+ ( EtherPort *port, PortIdentity *destIdentity );
/**
* @brief Processes PTP messages
- * @param port [in] IEEE1588Port
+ * @param port [in] EtherPort
* @return void
*/
- void processMessage(IEEE1588Port * port);
+ void processMessage( EtherPort *port );
/**
* @brief Gets origin timestamp value
@@ -891,7 +969,8 @@ class PTPMessagePathDelayReq : public PTPMessageCommon {
}
friend PTPMessageCommon *buildPTPMessage
- (char *buf, int size, LinkLayerAddress * remote, IEEE1588Port * port);
+ ( char *buf, int size, LinkLayerAddress *remote,
+ EtherPort *port );
};
/**
@@ -912,22 +991,25 @@ public:
/**
* @brief Builds the PTPMessagePathDelayResp object
*/
- PTPMessagePathDelayResp(IEEE1588Port * port);
+ PTPMessagePathDelayResp( EtherPort *port );
/**
- * @brief Assembles PTPMessagePathDelayResp message on the IEEE1588Port payload
- * @param port IEEE1588Port where the message will be assembled
+ * @brief Assembles PTPMessagePathDelayResp message on the
+ * EtherPort payload
+ * @param port EtherPort where the message will be
+ * assembled
* @param destIdentity [in] Destination PortIdentity
- * @return void
+ * @return true on success
*/
- void sendPort(IEEE1588Port * port, PortIdentity * destIdentity);
+ bool sendPort
+ ( EtherPort *port, PortIdentity *destIdentity );
/**
* @brief Processes PTP messages
- * @param port [in] IEEE1588Port
+ * @param port [in] EtherPort
* @return void
*/
- void processMessage(IEEE1588Port * port);
+ void processMessage( EtherPort *port );
/**
* @brief Sets the request receipt timestamp
@@ -960,7 +1042,8 @@ public:
}
friend PTPMessageCommon *buildPTPMessage
- (char *buf, int size, LinkLayerAddress * remote, IEEE1588Port * port);
+ ( char *buf, int size, LinkLayerAddress *remote,
+ EtherPort *port );
};
/**
@@ -977,7 +1060,7 @@ public:
/**
* @brief Builds the PTPMessagePathDelayRespFollowUp object
*/
- PTPMessagePathDelayRespFollowUp(IEEE1588Port * port);
+ PTPMessagePathDelayRespFollowUp( EtherPort *port );
/**
* @brief Destroys the PTPMessagePathDelayRespFollowUp object
@@ -985,19 +1068,22 @@ public:
~PTPMessagePathDelayRespFollowUp();
/**
- * @brief Assembles PTPMessageRespFollowUp message on the IEEE1588Port payload
- * @param port IEEE1588Port where the message will be assembled
+ * @brief Assembles PTPMessageRespFollowUp message on the
+ * EtherPort payload
+ * @param port EtherPort where the message will be
+ * assembled
* @param destIdentity [in] Destination PortIdentity
- * @return void
+ * @return true on success
*/
- void sendPort(IEEE1588Port * port, PortIdentity * destIdentity);
+ bool sendPort
+ ( EtherPort *port, PortIdentity *destIdentity );
/**
* @brief Processes PTP messages
- * @param port [in] IEEE1588Port
+ * @param port [in] EtherPort
* @return void
*/
- void processMessage(IEEE1588Port * port);
+ void processMessage( EtherPort *port );
/**
* @brief Sets the response origin timestamp
@@ -1030,7 +1116,8 @@ public:
}
friend PTPMessageCommon *buildPTPMessage
- (char *buf, int size, LinkLayerAddress * remote, IEEE1588Port * port);
+ ( char *buf, int size, LinkLayerAddress *remote,
+ EtherPort *port );
};
/*Exact fit. No padding*/
@@ -1153,7 +1240,7 @@ public:
/**
* @brief Builds the PTPMessageSignalling object
*/
- PTPMessageSignalling(IEEE1588Port * port);
+ PTPMessageSignalling( EtherPort *port );
/**
* @brief Destroys the PTPMessageSignalling object
@@ -1171,22 +1258,25 @@ public:
/**
* @brief Assembles PTPMessageSignalling message on the
- * IEEE1588Port payload
- * @param port IEEE1588Port where the message will be assembled
+ * EtherPort payload
+ * @param port EtherPort where the message will be
+ * assembled
* @param destIdentity [in] Destination PortIdentity
- * @return void
+ * @return true on success
*/
- void sendPort(IEEE1588Port * port, PortIdentity * destIdentity);
+ bool sendPort
+ ( EtherPort *port, PortIdentity *destIdentity );
/**
* @brief Processes PTP messages
- * @param port [in] IEEE1588Port
+ * @param port [in] EtherPort
* @return void
*/
- void processMessage(IEEE1588Port * port);
+ void processMessage( EtherPort *port );
friend PTPMessageCommon *buildPTPMessage
- (char *buf, int size, LinkLayerAddress * remote, IEEE1588Port * port);
+ ( char *buf, int size, LinkLayerAddress *remote,
+ EtherPort * port);
};
#endif
diff --git a/daemons/gptp/common/avbts_oscondition.hpp b/daemons/gptp/common/avbts_oscondition.hpp
index 5072cfab..93511391 100644
--- a/daemons/gptp/common/avbts_oscondition.hpp
+++ b/daemons/gptp/common/avbts_oscondition.hpp
@@ -109,7 +109,7 @@ public:
* @brief Creates OSCondition class
* @return Pointer to OSCondition object
*/
- virtual OSCondition * createCondition() = 0;
+ virtual OSCondition *createCondition() const = 0;
/**
* @brief Destroys OSCondition objects
diff --git a/daemons/gptp/common/avbts_osipc.hpp b/daemons/gptp/common/avbts_osipc.hpp
index 4d3daf3a..00bac5dd 100644
--- a/daemons/gptp/common/avbts_osipc.hpp
+++ b/daemons/gptp/common/avbts_osipc.hpp
@@ -36,7 +36,7 @@
#include <stdint.h>
#include <ptptypes.hpp>
-#include <avbts_port.hpp>
+#include <ether_port.hpp>
/**@file*/
@@ -63,6 +63,7 @@ public:
/**
* @brief Updates IPC values
+ *
* @param ml_phoffset Master to local phase offset
* @param ls_phoffset Local to system phase offset
* @param ml_freqoffset Master to local frequency offset
@@ -71,14 +72,62 @@ public:
* @param sync_count Count of syncs
* @param pdelay_count Count of pdelays
* @param port_state Port's state
- * @param asCapable asCapable flag
+ * @param asCapable asCapable flag
+ *
* @return Implementation dependent.
*/
- virtual bool update
- ( int64_t ml_phoffset, int64_t ls_phoffset,
- FrequencyRatio ml_freqoffset, FrequencyRatio ls_freq_offset,
- uint64_t local_time, uint32_t sync_count, uint32_t pdelay_count,
- PortState port_state, bool asCapable ) = 0;
+ virtual bool update(
+ int64_t ml_phoffset,
+ int64_t ls_phoffset,
+ FrequencyRatio ml_freqoffset,
+ FrequencyRatio ls_freq_offset,
+ uint64_t local_time,
+ uint32_t sync_count,
+ uint32_t pdelay_count,
+ PortState port_state,
+ bool asCapable ) = 0;
+
+ /**
+ * @brief Updates grandmaster IPC values
+ *
+ * @param gptp_grandmaster_id Current grandmaster id (all 0's if no grandmaster selected)
+ * @param gptp_domain_number gPTP domain number
+ *
+ * @return Implementation dependent.
+ */
+ virtual bool update_grandmaster(
+ uint8_t gptp_grandmaster_id[],
+ uint8_t gptp_domain_number ) = 0;
+
+ /**
+ * @brief Updates network interface IPC values
+ *
+ * @param clock_identity The clock identity of the interface
+ * @param priority1 The priority1 field of the grandmaster functionality of the interface, or 0xFF if not supported
+ * @param clock_class The clockClass field of the grandmaster functionality of the interface, or 0xFF if not supported
+ * @param offset_scaled_log_variance The offsetScaledLogVariance field of the grandmaster functionality of the interface, or 0x0000 if not supported
+ * @param clock_accuracy The clockAccuracy field of the grandmaster functionality of the interface, or 0xFF if not supported
+ * @param priority2 The priority2 field of the grandmaster functionality of the interface, or 0xFF if not supported
+ * @param domain_number The domainNumber field of the grandmaster functionality of the interface, or 0 if not supported
+ * @param log_sync_interval The currentLogSyncInterval field of the grandmaster functionality of the interface, or 0 if not supported
+ * @param log_announce_interval The currentLogAnnounceInterval field of the grandmaster functionality of the interface, or 0 if not supported
+ * @param log_pdelay_interval The currentLogPDelayReqInterval field of the grandmaster functionality of the interface, or 0 if not supported
+ * @param port_number The portNumber field of the interface, or 0x0000 if not supported
+ *
+ * @return Implementation dependent.
+ */
+ virtual bool update_network_interface(
+ uint8_t clock_identity[],
+ uint8_t priority1,
+ uint8_t clock_class,
+ int16_t offset_scaled_log_variance,
+ uint8_t clock_accuracy,
+ uint8_t priority2,
+ uint8_t domain_number,
+ int8_t log_sync_interval,
+ int8_t log_announce_interval,
+ int8_t log_pdelay_interval,
+ uint16_t port_number ) = 0;
/*
* Destroys IPC
diff --git a/daemons/gptp/common/avbts_oslock.hpp b/daemons/gptp/common/avbts_oslock.hpp
index 9de07e58..c53b904b 100644
--- a/daemons/gptp/common/avbts_oslock.hpp
+++ b/daemons/gptp/common/avbts_oslock.hpp
@@ -103,7 +103,7 @@ class OSLockFactory {
* @param type Enumeration OSLockType
* @return Pointer to an enumeration of type OSLock
*/
- virtual OSLock * createLock(OSLockType type) = 0;
+ virtual OSLock *createLock(OSLockType type) const = 0;
virtual ~OSLockFactory() = 0;
};
diff --git a/daemons/gptp/common/avbts_osnet.hpp b/daemons/gptp/common/avbts_osnet.hpp
index 59c239e0..eb3194cb 100644
--- a/daemons/gptp/common/avbts_osnet.hpp
+++ b/daemons/gptp/common/avbts_osnet.hpp
@@ -42,6 +42,8 @@
/**@file*/
+class CommonTimestamper;
+
#define FACTORY_NAME_LENGTH 48 /*!< Factory name maximum length */
#define DEFAULT_TIMEOUT 1 /*!< Default timeout in milliseconds*/
@@ -127,7 +129,7 @@ class LinkLayerAddress:public InterfaceLabel {
*/
bool operator>(const LinkLayerAddress & cmp)const {
return memcmp
- (this->addr, cmp.addr, ETHER_ADDR_OCTETS) < 0 ? true : false;
+ (this->addr, cmp.addr, ETHER_ADDR_OCTETS) > 0 ? true : false;
}
/**
@@ -202,7 +204,7 @@ class InterfaceName: public InterfaceLabel {
* @return TRUE if the interface name is found to be greater than cmd. FALSE otherwise
*/
bool operator>(const InterfaceName & cmp)const {
- return strcmp(name, cmp.name) < 0 ? true : false;
+ return strcmp(name, cmp.name) > 0 ? true : false;
}
/**
@@ -313,7 +315,7 @@ class OSNetworkInterface {
* @return net_result enumeration
*/
virtual net_result nrecv
- (LinkLayerAddress * addr, uint8_t * payload, size_t & length, struct phy_delay *delay) = 0;
+ ( LinkLayerAddress *addr, uint8_t *payload, size_t &length ) = 0;
/**
* @brief Get Link Layer address (mac address)
@@ -325,7 +327,7 @@ class OSNetworkInterface {
/**
* @brief Watch for netlink changes.
*/
- virtual void watchNetLink(IEEE1588Port *pPort) = 0;
+ virtual void watchNetLink( CommonPort *pPort ) = 0;
/**
* @brief Provides generic method for getting the payload offset
@@ -372,12 +374,12 @@ class OSNetworkInterfaceFactory {
* @param iface [out] Pointer to interface name
* @param id Factory name index
* @param iflabel Interface label
- * @param timestamper HWTimestamper class pointer
+ * @param timestamper CommonTimestamper class pointer
* @return TRUE ok, FALSE error.
*/
static bool buildInterface
(OSNetworkInterface ** iface, factory_name_t id, InterfaceLabel * iflabel,
- HWTimestamper * timestamper) {
+ CommonTimestamper * timestamper) {
return factoryMap[id]->createInterface
(iface, iflabel, timestamper);
}
@@ -385,7 +387,7 @@ class OSNetworkInterfaceFactory {
private:
virtual bool createInterface
(OSNetworkInterface ** iface, InterfaceLabel * iflabel,
- HWTimestamper * timestamper) = 0;
+ CommonTimestamper * timestamper) = 0;
static FactoryMap_t factoryMap;
};
diff --git a/daemons/gptp/common/avbts_osthread.hpp b/daemons/gptp/common/avbts_osthread.hpp
index d191b650..9464512f 100644
--- a/daemons/gptp/common/avbts_osthread.hpp
+++ b/daemons/gptp/common/avbts_osthread.hpp
@@ -47,6 +47,7 @@ typedef enum { osthread_ok, osthread_error } OSThreadExitCode;
* @brief Provides the OSThreadExitCode callback format
*/
typedef OSThreadExitCode(*OSThreadFunction) (void *);
+typedef void *OSThreadFunctionArg;
/**
* @brief Provides a generic interface for threads
@@ -81,7 +82,7 @@ public:
* @brief Creates a new thread
* @return Pointer to OSThread object
*/
- virtual OSThread * createThread() = 0;
+ virtual OSThread * createThread() const = 0;
/**
* @brief Destroys the new thread
diff --git a/daemons/gptp/common/avbts_ostimer.hpp b/daemons/gptp/common/avbts_ostimer.hpp
index f416f008..cacdfc95 100644
--- a/daemons/gptp/common/avbts_ostimer.hpp
+++ b/daemons/gptp/common/avbts_ostimer.hpp
@@ -65,7 +65,7 @@ public:
* @brief Creates the OSTimer
* @return Pointer to OSTimer object
*/
- virtual OSTimer * createTimer() = 0;
+ virtual OSTimer *createTimer() const = 0;
/*
* Destroys the OSTimer previsouly created
diff --git a/daemons/gptp/common/avbts_port.hpp b/daemons/gptp/common/avbts_port.hpp
deleted file mode 100644
index 5fd35f4d..00000000
--- a/daemons/gptp/common/avbts_port.hpp
+++ /dev/null
@@ -1,1690 +0,0 @@
-/******************************************************************************
-
- Copyright (c) 2009-2012, Intel Corporation
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- 1. Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- 3. Neither the name of the Intel Corporation nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
-
-******************************************************************************/
-
-#ifndef AVBTS_PORT_HPP
-#define AVBTS_PORT_HPP
-
-#include <ieee1588.hpp>
-#include <avbts_message.hpp>
-#include <avbap_message.hpp>
-
-#include <avbts_ostimer.hpp>
-#include <avbts_oslock.hpp>
-#include <avbts_osnet.hpp>
-#include <avbts_osthread.hpp>
-#include <avbts_oscondition.hpp>
-#include <ipcdef.hpp>
-#include <gptp_log.hpp>
-
-#include <stdint.h>
-
-#include <map>
-#include <list>
-
-/**@file*/
-
-#define GPTP_MULTICAST 0x0180C200000EULL /*!< GPTP multicast adddress */
-#define PDELAY_MULTICAST GPTP_MULTICAST /*!< PDELAY Multicast value */
-#define OTHER_MULTICAST GPTP_MULTICAST /*!< OTHER multicast value */
-#define TEST_STATUS_MULTICAST 0x011BC50AC000ULL /*!< AVnu Automotive profile test status msg Multicast value */
-
-#define PDELAY_RESP_RECEIPT_TIMEOUT_MULTIPLIER 3 /*!< PDelay timeout multiplier*/
-#define SYNC_RECEIPT_TIMEOUT_MULTIPLIER 3 /*!< Sync receipt timeout multiplier*/
-#define ANNOUNCE_RECEIPT_TIMEOUT_MULTIPLIER 3 /*!< Announce receipt timeout multiplier*/
-
-#define LOG2_INTERVAL_INVALID -127 /* Simple out of range Log base 2 value used for Sync and PDelay msg internvals */
-
-/**
- * @brief PortType enumeration. Selects between delay request-response (E2E) mechanism
- * or PTPV1 or PTPV2 P2P (peer delay) mechanism.
- */
-typedef enum {
- V1,
- V2_E2E,
- V2_P2P
-} PortType;
-
-/**
- * @brief PortIdentity interface
- * Defined at IEEE 802.1AS Clause 8.5.2
- */
-class PortIdentity {
-private:
- ClockIdentity clock_id;
- uint16_t portNumber;
-public:
- /**
- * @brief Default Constructor
- */
- PortIdentity() { };
-
- /**
- * @brief Constructs PortIdentity interface.
- * @param clock_id Clock ID value as defined at IEEE 802.1AS Clause 8.5.2.2
- * @param portNumber Port Number
- */
- PortIdentity(uint8_t * clock_id, uint16_t * portNumber) {
- this->portNumber = *portNumber;
- this->portNumber = PLAT_ntohs(this->portNumber);
- this->clock_id.set(clock_id);
- }
-
- /**
- * @brief Implements the operator '!=' overloading method. Compares clock_id and portNumber.
- * @param cmp Constant PortIdentity value to be compared against.
- * @return TRUE if the comparison value differs from the object's PortIdentity value. FALSE otherwise.
- */
- bool operator!=(const PortIdentity & cmp) const {
- return
- !(this->clock_id == cmp.clock_id) ||
- this->portNumber != cmp.portNumber ? true : false;
- }
-
- /**
- * @brief Implements the operator '==' overloading method. Compares clock_id and portNumber.
- * @param cmp Constant PortIdentity value to be compared against.
- * @return TRUE if the comparison value equals to the object's PortIdentity value. FALSE otherwise.
- */
- bool operator==(const PortIdentity & cmp)const {
- return
- this->clock_id == cmp.clock_id &&
- this->portNumber == cmp.portNumber ? true : false;
- }
-
- /**
- * @brief Implements the operator '<' overloading method. Compares clock_id and portNumber.
- * @param cmp Constant PortIdentity value to be compared against.
- * @return TRUE if the comparison value is lower than the object's PortIdentity value. FALSE otherwise.
- */
- bool operator<(const PortIdentity & cmp)const {
- return
- this->clock_id < cmp.clock_id ?
- true : this->clock_id == cmp.clock_id &&
- this->portNumber < cmp.portNumber ? true : false;
- }
-
- /**
- * @brief Implements the operator '>' overloading method. Compares clock_id and portNumber.
- * @param cmp Constant PortIdentity value to be compared against.
- * @return TRUE if the comparison value is greater than the object's PortIdentity value. FALSE otherwise.
- */
- bool operator>(const PortIdentity & cmp)const {
- return
- this->clock_id > cmp.clock_id ?
- true : this->clock_id == cmp.clock_id &&
- this->portNumber > cmp.portNumber ? true : false;
- }
-
- /**
- * @brief Gets the ClockIdentity string
- * @param id [out] Pointer to an array of octets.
- * @return void
- */
- void getClockIdentityString(uint8_t *id) {
- clock_id.getIdentityString(id);
- }
-
- /**
- * @brief Sets the ClockIdentity.
- * @param clock_id Clock Identity to be set.
- * @return void
- */
- void setClockIdentity(ClockIdentity clock_id) {
- this->clock_id = clock_id;
- }
-
- /**
- * @brief Gets the clockIdentity value
- * @return A copy of Clock identity value.
- */
- ClockIdentity getClockIdentity( void ) {
- return this->clock_id;
- }
-
- /**
- * @brief Gets the port number following the network byte order, i.e. Big-Endian.
- * @param id [out] Port number
- * @return void
- */
- void getPortNumberNO(uint16_t * id) { // Network byte order
- uint16_t portNumberNO = PLAT_htons(portNumber);
- *id = portNumberNO;
- }
-
- /**
- * @brief Gets the port number in the host byte order, which can be either Big-Endian
- * or Little-Endian, depending on the processor where it is running.
- * @param id Port number
- * @return void
- */
- void getPortNumber(uint16_t * id) { // Host byte order
- *id = portNumber;
- }
-
- /**
- * @brief Sets the Port number
- * @param id [in] Port number
- * @return void
- */
- void setPortNumber(uint16_t * id) {
- portNumber = *id;
- }
-};
-
-/**
- * @brief Provides a map for the identityMap member of IEEE1588Port class
- */
-typedef std::map < PortIdentity, LinkLayerAddress > IdentityMap_t;
-
-/**
- * @brief Structure for initializing the IEEE1588 class
- */
-typedef struct {
- /* clock IEEE1588Clock instance */
- IEEE1588Clock * clock;
-
- /* index Interface index */
- uint16_t index;
-
- /* forceSlave Forces port to be slave */
- bool forceSlave;
-
- /* accelerated_sync_count If non-zero, then start 16ms sync timer */
- int accelerated_sync_count;
-
- /* timestamper Hardware timestamper instance */
- HWTimestamper * timestamper;
-
- /* offset Initial clock offset */
- int32_t offset;
-
- /* net_label Network label */
- InterfaceLabel * net_label;
-
- /* automotive_profile set the AVnu automotive profile */
- bool automotive_profile;
-
- /* Set to true if the port is the grandmaster. Used for fixed GM in the the AVnu automotive profile */
- bool isGM;
-
- /* Set to true if the port is the grandmaster. Used for fixed GM in the the AVnu automotive profile */
- bool testMode;
-
- /* gPTP 10.2.4.4 */
- char initialLogSyncInterval;
-
- /* gPTP 11.5.2.2 */
- char initialLogPdelayReqInterval;
-
- /* CDS 6.2.1.5 */
- char operLogPdelayReqInterval;
-
- /* CDS 6.2.1.6 */
- char operLogSyncInterval;
-
- /* condition_factory OSConditionFactory instance */
- OSConditionFactory * condition_factory;
-
- /* thread_factory OSThreadFactory instance */
- OSThreadFactory * thread_factory;
-
- /* timer_factory OSTimerFactory instance */
- OSTimerFactory * timer_factory;
-
- /* lock_factory OSLockFactory instance */
- OSLockFactory * lock_factory;
-} IEEE1588PortInit_t;
-
-
-/**
- * @brief Structure for IEE1588Port Counters
- */
-typedef struct {
- int32_t ieee8021AsPortStatRxSyncCount;
- int32_t ieee8021AsPortStatRxFollowUpCount;
- int32_t ieee8021AsPortStatRxPdelayRequest;
- int32_t ieee8021AsPortStatRxPdelayResponse;
- int32_t ieee8021AsPortStatRxPdelayResponseFollowUp;
- int32_t ieee8021AsPortStatRxAnnounce;
- int32_t ieee8021AsPortStatRxPTPPacketDiscard;
- int32_t ieee8021AsPortStatRxSyncReceiptTimeouts;
- int32_t ieee8021AsPortStatAnnounceReceiptTimeouts;
- int32_t ieee8021AsPortStatPdelayAllowedLostResponsesExceeded;
- int32_t ieee8021AsPortStatTxSyncCount;
- int32_t ieee8021AsPortStatTxFollowUpCount;
- int32_t ieee8021AsPortStatTxPdelayRequest;
- int32_t ieee8021AsPortStatTxPdelayResponse;
- int32_t ieee8021AsPortStatTxPdelayResponseFollowUp;
- int32_t ieee8021AsPortStatTxAnnounce;
-} IEEE1588PortCounters_t;
-
-
-/**
- * @brief Provides the IEEE 1588 port interface
- */
-class IEEE1588Port {
- static LinkLayerAddress other_multicast;
- static LinkLayerAddress pdelay_multicast;
- static LinkLayerAddress test_status_multicast;
-
- PortIdentity port_identity;
- /* directly connected node */
- PortIdentity peer_identity;
-
- OSNetworkInterface *net_iface;
- LinkLayerAddress local_addr;
- int link_delay[4];
-
- /* Port Status */
- unsigned sync_count; // 0 for master, ++ for each sync receive as slave
- // set to 0 when asCapable is false, increment for each pdelay recvd
- unsigned pdelay_count;
-
- /* Port Configuration */
- unsigned char delay_mechanism;
- PortState port_state;
- char log_mean_unicast_sync_interval;
- char log_mean_sync_interval;
- char log_mean_announce_interval;
- char log_min_mean_delay_req_interval;
- char log_min_mean_pdelay_req_interval;
- bool burst_enabled;
- int _accelerated_sync_count;
- static const int64_t ONE_WAY_DELAY_DEFAULT = 3600000000000;
- static const int64_t INVALID_LINKDELAY = 3600000000000;
- static const int64_t NEIGHBOR_PROP_DELAY_THRESH = 800;
- static const unsigned int DEFAULT_SYNC_RECEIPT_THRESH = 5;
- static const unsigned int DUPLICATE_RESP_THRESH = 3;
-
- unsigned int duplicate_resp_counter;
- uint16_t last_invalid_seqid;
-
- /* Signed value allows this to be negative result because of inaccurate
- timestamp */
- int64_t one_way_delay;
- int64_t neighbor_prop_delay_thresh;
-
- /*Sync threshold*/
- unsigned int sync_receipt_thresh;
- unsigned int wrongSeqIDCounter;
-
- /* Implementation Specific data/methods */
- IEEE1588Clock *clock;
-
- bool _syntonize;
-
- bool asCapable;
-
- /* Automotive Profile : Static variables */
- // port_state : already defined as port_state
- bool isGM;
- bool testMode;
- // asCapable : already defined as asCapable
- char initialLogPdelayReqInterval;
- char initialLogSyncInterval;
- char operLogPdelayReqInterval;
- char operLogSyncInterval;
- bool automotive_profile;
-
- // Test Status variables
- uint32_t linkUpCount;
- uint32_t linkDownCount;
- StationState_t stationState;
-
-
- /* Automotive Profile : Persistant variables */
- // neighborPropDelay : defined as one_way_delay ??
- // rateRatio : Optional and didn't fine this variable. Will proceed without writing it.
- // neighborRateRatio : defined as _peer_rate_offset ??
-
- // Automotive Profile AVB SYNC state indicator. > 0 will inditate valid AVB SYNC state
- uint32_t avbSyncState;
-
- int32_t *rate_offset_array;
- uint32_t rate_offset_array_size;
- uint32_t rate_offset_count;
- uint32_t rate_offset_index;
-
- FrequencyRatio _peer_rate_offset;
- Timestamp _peer_offset_ts_theirs;
- Timestamp _peer_offset_ts_mine;
- bool _peer_offset_init;
-
- int32_t _initial_clock_offset;
- int32_t _current_clock_offset;
-
- PTPMessageAnnounce *qualified_announce;
-
- uint16_t announce_sequence_id;
- uint16_t signal_sequence_id;
- uint16_t sync_sequence_id;
-
- uint16_t pdelay_sequence_id;
- PTPMessagePathDelayReq *last_pdelay_req;
- PTPMessagePathDelayResp *last_pdelay_resp;
- PTPMessagePathDelayRespFollowUp *last_pdelay_resp_fwup;
-
- /* Network socket description
- physical interface number that object represents */
- uint16_t ifindex;
-
- IdentityMap_t identity_map;
-
- PTPMessageSync *last_sync;
-
- OSThread *listening_thread;
-
- OSThread *link_thread;
-
- OSCondition *port_ready_condition;
-
- OSLock *pdelay_rx_lock;
- OSLock *port_tx_lock;
-
- OSLock *syncReceiptTimerLock;
- OSLock *syncIntervalTimerLock;
- OSLock *announceIntervalTimerLock;
- OSLock *pDelayIntervalTimerLock;
-
- OSThreadFactory *thread_factory;
- OSTimerFactory *timer_factory;
-
- HWTimestamper *_hw_timestamper;
-
- net_result port_send
- (uint16_t etherType, uint8_t * buf, int size, MulticastType mcast_type,
- PortIdentity * destIdentity, bool timestamp);
-
- InterfaceLabel *net_label;
-
- OSLockFactory *lock_factory;
- OSConditionFactory *condition_factory;
-
- bool pdelay_started;
- bool pdelay_halted;
- bool sync_rate_interval_timer_started;
-
- uint16_t lastGmTimeBaseIndicator;
-
- IEEE1588PortCounters_t counters;
-
- public:
- bool forceSlave; //!< Forces port to be slave. Added for testing.
-
- /**
- * @brief Serializes (i.e. copy over buf pointer) the information from
- * the variables (in that order):
- * - asCapable;
- * - Port Sate;
- * - Link Delay;
- * - Neighbor Rate Ratio
- * @param buf [out] Buffer where to put the results.
- * @param count [inout] Length of buffer. It contains maximum length to be written
- * when the function is called, and the value is decremented by the same amount the
- * buf size increases.
- * @return TRUE if it has successfully written to buf all the values or if buf is NULL.
- * FALSE if count should be updated with the right size.
- */
- bool serializeState( void *buf, long *count );
-
- /**
- * @brief Restores the serialized state from the buffer. Copies the information from buffer
- * to the variables (in that order):
- * - asCapable;
- * - Port State;
- * - Link Delay;
- * - Neighbor Rate Ratio
- * @param buf Buffer containing the serialized state.
- * @param count Buffer lenght. It is decremented by the same size of the variables that are
- * being copied.
- * @return TRUE if everything was copied successfully, FALSE otherwise.
- */
- bool restoreSerializedState( void *buf, long *count );
-
- /**
- * @brief Switches port to a gPTP master
- * @param annc If TRUE, starts announce event timer.
- * @return void
- */
- void becomeMaster( bool annc );
-
- /**
- * @brief Switches port to a gPTP slave.
- * @param restart_syntonization if TRUE, restarts the syntonization
- * @return void
- */
- void becomeSlave( bool restart_syntonization );
-
- /**
- * @brief Starts pDelay event timer.
- * @return void
- */
- void startPDelay();
-
- /**
- * @brief Stops PDelay event timer
- * @return void
- */
- void stopPDelay();
-
- /**
- * @brief Enable/Disable PDelay Request messages
- * @param hlt True to HALT (stop sending), False to resume (start sending).
- */
- void haltPdelay(bool hlt)
- {
- pdelay_halted = hlt;
- }
-
- /**
- * @brief Get the status of pdelayHalted condition.
- * @return True PdelayRequest halted. False when PDelay Request is running
- */
- bool pdelayHalted(void)
- {
- return pdelay_halted;
- }
-
- /**
- * @brief Starts Sync Rate Interval event timer. Used for the
- * Automotive Profile.
- * @return void
- */
- void startSyncRateIntervalTimer();
-
- /**
- * @brief Starts announce event timer
- * @return void
- */
- void startAnnounce();
-
- /**
- * @brief Starts pDelay event timer if not yet started.
- * @return void
- */
- void syncDone() {
- GPTP_LOG_VERBOSE("Sync complete");
-
- if (automotive_profile && port_state == PTP_SLAVE) {
- if (avbSyncState > 0) {
- avbSyncState--;
- if (avbSyncState == 0) {
- setStationState(STATION_STATE_AVB_SYNC);
- if (testMode) {
- APMessageTestStatus *testStatusMsg = new APMessageTestStatus(this);
- if (testStatusMsg) {
- testStatusMsg->sendPort(this);
- delete testStatusMsg;
- }
- }
- }
- }
- }
-
- if (automotive_profile) {
- if (!sync_rate_interval_timer_started) {
- if (log_mean_sync_interval != operLogSyncInterval) {
- startSyncRateIntervalTimer();
- }
- }
- }
-
- if( !pdelay_started ) {
- startPDelay();
- }
- }
-
- /**
- * @brief Gets a pointer to timer_factory object
- * @return timer_factory pointer
- */
- OSTimerFactory *getTimerFactory() {
- return timer_factory;
- }
-
- /**
- * @brief Restart PDelay
- * @return void
- */
- void restartPDelay() {
- _peer_offset_init = false;
- }
-
- /**
- * @brief Sets asCapable flag
- * @param ascap flag to be set. If FALSE, marks peer_offset_init as false.
- * @return void
- */
- void setAsCapable(bool ascap) {
- if (ascap != asCapable) {
- GPTP_LOG_STATUS("AsCapable: %s",
- ascap == true ? "Enabled" : "Disabled");
- }
- if(!ascap){
- _peer_offset_init = false;
- }
- asCapable = ascap;
- }
-
- /**
- * @brief Gets the asCapable flag
- * @return asCapable flag.
- */
- bool getAsCapable() { return( asCapable ); }
-
- /**
- * @brief Gets the AVnu automotive profile flag
- * @return automotive_profile flag
- */
- bool getAutomotiveProfile() { return( automotive_profile ); }
-
- /**
- * @brief Destroys a IEEE1588Port
- */
- ~IEEE1588Port();
-
- /**
- * @brief Creates the IEEE1588Port interface. Will be
- * deprecated when the Windows platform suports
- * Automotive profile.
- * @param clock IEEE1588Clock instance
- * @param index Interface index
- * @param forceSlave Forces port to be slave
- * @param accelerated_sync_count If non-zero, then start 16ms sync timer
- * @param timestamper Hardware timestamper instance
- * @param offset Initial clock offset
- * @param net_label Network label
- * @param condition_factory OSConditionFactory instance
- * @param thread_factory OSThreadFactory instance
- * @param timer_factory OSTimerFactory instance
- * @param lock_factory OSLockFactory instance
- */
- IEEE1588Port
- (IEEE1588Clock * clock, uint16_t index,
- bool forceSlave, int accelerated_sync_count,
- HWTimestamper * timestamper,
- int32_t offset, InterfaceLabel * net_label,
- OSConditionFactory * condition_factory,
- OSThreadFactory * thread_factory,
- OSTimerFactory * timer_factory,
- OSLockFactory * lock_factory);
-
- /**
- * @brief Creates the IEEE1588Port interface.
- * @param init IEEE1588PortInit initialization parameters
- */
- IEEE1588Port(IEEE1588PortInit_t *portInit);
-
- /**
- * @brief Initializes the port. Creates network interface, initializes
- * hardware timestamper and create OS locks conditions
- * @return FALSE if error during building the interface. TRUE if success
- */
- bool init_port(int delay[4]);
-
- /**
- * @brief Currently doesnt do anything. Just returns.
- * @return void
- */
- void recoverPort(void);
-
- /**
- * @brief Watch for link up and down events.
- * @return Its an infinite loop. Returns NULL in case of error.
- */
- void *watchNetLink(void);
-
- /**
- * @brief Receives messages from the network interface
- * @return Its an infinite loop. Returns NULL in case of error.
- */
- void *openPort(IEEE1588Port *port);
-
- /**
- * @brief Get the payload offset inside a packet
- * @return 0
- */
- unsigned getPayloadOffset();
-
- /**
- * @brief Sends and event to a IEEE1588 port. It includes timestamp
- * @param buf [in] Pointer to the data buffer
- * @param len Size of the message
- * @param mcast_type Enumeration MulticastType (pdlay, none or other). Depracated.
- * @param destIdentity Destination port identity
- * @return void
- */
- void sendEventPort
- (uint16_t etherType, uint8_t * buf, int len, MulticastType mcast_type,
- PortIdentity * destIdentity);
-
- /**
- * @brief Sends a general message to a port. No timestamps
- * @param buf [in] Pointer to the data buffer
- * @param len Size of the message
- * @param mcast_type Enumeration MulticastType (pdelay, none or other). Depracated.
- * @param destIdentity Destination port identity
- * @return void
- */
- void sendGeneralPort
- (uint16_t etherType, uint8_t * buf, int len, MulticastType mcast_type,
- PortIdentity * destIdentity);
-
- /**
- * @brief Process all events for a IEEE1588Port
- * @param e Event to be processed
- * @return void
- */
- void processEvent(Event e);
-
- /**
- * @brief Gets the "best" announce
- * @return Pointer to PTPMessageAnnounce
- */
- PTPMessageAnnounce *calculateERBest(void);
-
- /**
- * @brief Adds a foreign master.
- * @param msg [in] PTP announce message
- * @return void
- * @todo Currently not implemented
- */
- void addForeignMaster(PTPMessageAnnounce * msg);
-
- /**
- * @brief Remove a foreign master.
- * @param msg [in] PTP announce message
- * @return void
- * @todo Currently not implemented
- */
- void removeForeignMaster(PTPMessageAnnounce * msg);
-
- /**
- * @brief Remove all foreign masters.
- * @return void
- * @todo Currently not implemented
- */
- void removeForeignMasterAll(void);
-
-
- /**
- * @brief Adds a new qualified announce the port. IEEE 802.1AS Clause 10.3.10.2
- * @param msg PTP announce message
- * @return void
- */
- void addQualifiedAnnounce(PTPMessageAnnounce * msg) {
- if( qualified_announce != NULL ) delete qualified_announce;
- qualified_announce = msg;
- }
- /**
- * @brief Gets the local_addr
- * @return LinkLayerAddress
- */
- LinkLayerAddress *getLocalAddr(void) {
- return &local_addr;
- }
-
- /**
- * @brief Gets the sync interval value
- * @return Sync Interval
- */
- char getSyncInterval(void) {
- return log_mean_sync_interval;
- }
-
- /**
- * @brief Sets the sync interval value
- * @param val time interval
- * @return none
- */
- void setSyncInterval(char val) {
- log_mean_sync_interval = val;;
- }
-
- /**
- * @brief Sets the sync interval back to initial value
- * @return none
- */
- void setInitSyncInterval(void) {
- log_mean_sync_interval = initialLogSyncInterval;;
- }
-
- /**
- * @brief Start sync receipt timer
- * @param waitTime time interval
- * @return none
- */
- void startSyncReceiptTimer(long long unsigned int waitTime);
-
- /**
- * @brief Stop sync receipt timer
- * @return none
- */
- void stopSyncReceiptTimer(void);
-
- /**
- * @brief Start sync interval timer
- * @param waitTime time interval
- * @return none
- */
- void startSyncIntervalTimer(long long unsigned int waitTime);
-
- /**
- * @brief Gets the announce interval
- * @return Announce interval
- */
- char getAnnounceInterval(void) {
- return log_mean_announce_interval;
- }
-
- /**
- * @brief Sets the announce interval
- * @param val time interval
- * @return none
- */
- void setAnnounceInterval(char val) {
- log_mean_announce_interval = val;
- }
-
- /**
- * @brief Start announce interval timer
- * @param waitTime time interval
- * @return none
- */
- void startAnnounceIntervalTimer(long long unsigned int waitTime);
-
- /**
- * @brief Gets the pDelay minimum interval
- * @return PDelay interval
- */
- char getPDelayInterval(void) {
- return log_min_mean_pdelay_req_interval;
- }
-
- /**
- * @brief Sets the pDelay minimum interval
- * @param val time interval
- * @return none
- */
- void setPDelayInterval(char val) {
- log_min_mean_pdelay_req_interval = val;
- }
-
- /**
- * @brief Sets the pDelay minimum interval back to initial
- * value
- * @return none */
- void setInitPDelayInterval(void) {
- log_min_mean_pdelay_req_interval = initialLogPdelayReqInterval;
- }
-
- /**
- * @brief Start pDelay interval timer
- * @param waitTime time interval
- * @return none
- */
- void startPDelayIntervalTimer(long long unsigned int waitTime);
-
- /**
- * @brief Gets the portState information
- * @return PortState
- */
- PortState getPortState(void) {
- return port_state;
- }
-
- /**
- * @brief Sets the PortState
- * @param state value to be set
- * @return void
- */
- void setPortState( PortState state ) {
- port_state = state;
- }
-
- /**
- * @brief Gets port identity
- * @param identity [out] Reference to PortIdentity
- * @return void
- */
- void getPortIdentity(PortIdentity & identity) {
- identity = this->port_identity;
- }
-
- /**
- * @brief Gets the burst_enabled flag
- * @return burst_enabled
- */
- bool burstEnabled(void) {
- return burst_enabled;
- }
-
- /**
- * @brief Increments announce sequence id and returns
- * @return Next announce sequence id.
- */
- uint16_t getNextAnnounceSequenceId(void) {
- return announce_sequence_id++;
- }
-
- /**
- * @brief Increments signal sequence id and returns
- * @return Next signal sequence id.
- */
- uint16_t getNextSignalSequenceId(void) {
- return signal_sequence_id++;
- }
-
- /**
- * @brief Increments sync sequence ID and returns
- * @return Next synce sequence id.
- */
- uint16_t getNextSyncSequenceId(void) {
- return sync_sequence_id++;
- }
-
- /**
- * @brief Increments PDelay sequence ID and returns.
- * @return Next PDelay sequence id.
- */
- uint16_t getNextPDelaySequenceId(void) {
- return pdelay_sequence_id++;
- }
-
- /**
- * @brief Gets last sync sequence number from parent
- * @return Parent last sync sequence number
- * @todo Not currently implemented.
- */
- uint16_t getParentLastSyncSequenceNumber(void);
-
- /**
- * @brief Sets last sync sequence number from parent
- * @param num Sequence number
- * @return void
- * @todo Currently not implemented.
- */
- void setParentLastSyncSequenceNumber(uint16_t num);
-
- /**
- * @brief Gets a pointer to IEEE1588Clock
- * @return Pointer to clock
- */
- IEEE1588Clock *getClock(void);
-
- /**
- * @brief Sets last sync ptp message
- * @param msg [in] PTP sync message
- * @return void
- */
- void setLastSync(PTPMessageSync * msg) {
- last_sync = msg;
- }
-
- /**
- * @brief Gets last sync message
- * @return PTPMessageSync last sync
- */
- PTPMessageSync *getLastSync(void) {
- return last_sync;
- }
-
- /**
- * @brief Locks PDelay RX
- * @return TRUE if acquired the lock. FALSE otherwise
- */
- bool getPDelayRxLock() {
- return pdelay_rx_lock->lock() == oslock_ok ? true : false;
- }
-
- /**
- * @brief Do a trylock on the PDelay RX
- * @return TRUE if acquired the lock. FALSE otherwise.
- */
- bool tryPDelayRxLock() {
- return pdelay_rx_lock->trylock() == oslock_ok ? true : false;
- }
-
- /**
- * @brief Unlocks PDelay RX.
- * @return TRUE if success. FALSE otherwise
- */
- bool putPDelayRxLock() {
- return pdelay_rx_lock->unlock() == oslock_ok ? true : false;
- }
-
- /**
- * @brief Locks the TX port
- * @return TRUE if success. FALSE otherwise.
- */
- bool getTxLock() {
- return port_tx_lock->lock() == oslock_ok ? true : false;
- }
-
- /**
- * @brief Unlocks the port TX.
- * @return TRUE if success. FALSE otherwise.
- */
- bool putTxLock() {
- return port_tx_lock->unlock() == oslock_ok ? true : false;
- }
-
- /**
- * @brief Gets the hardware timestamper version
- * @return HW timestamper version
- */
- int getTimestampVersion() {
- return _hw_timestamper->getVersion();
- }
-
- /**
- * @brief Sets the last_pdelay_req message
- * @param msg [in] PTPMessagePathDelayReq message to set
- * @return void
- */
- void setLastPDelayReq(PTPMessagePathDelayReq * msg) {
- last_pdelay_req = msg;
- }
-
- /**
- * @brief Gets the last PTPMessagePathDelayReq message
- * @return Last pdelay request
- */
- PTPMessagePathDelayReq *getLastPDelayReq(void) {
- return last_pdelay_req;
- }
-
- /**
- * @brief Sets the last PTPMessagePathDelayResp message
- * @param msg [in] Last pdelay response
- * @return void
- */
- void setLastPDelayResp(PTPMessagePathDelayResp * msg) {
- last_pdelay_resp = msg;
- }
-
- /**
- * @brief Gets the last PTPMessagePathDelayResp message
- * @return Last pdelay response
- */
- PTPMessagePathDelayResp *getLastPDelayResp(void) {
- return last_pdelay_resp;
- }
-
- /**
- * @brief Sets the last PTPMessagePathDelayRespFollowUp message
- * @param msg [in] last pdelay response follow up
- * @return void
- */
- void setLastPDelayRespFollowUp(PTPMessagePathDelayRespFollowUp * msg) {
- last_pdelay_resp_fwup = msg;
- }
-
- /**
- * @brief Gets the last PTPMessagePathDelayRespFollowUp message
- * @return last pdelay response follow up
- */
- PTPMessagePathDelayRespFollowUp *getLastPDelayRespFollowUp(void) {
- return last_pdelay_resp_fwup;
- }
-
- /**
- * @brief Gets the Peer rate offset. Used to calculate neighbor rate ratio.
- * @return FrequencyRatio peer rate offset
- */
- FrequencyRatio getPeerRateOffset(void) {
- return _peer_rate_offset;
- }
-
- /**
- * @brief Sets the peer rate offset. Used to calculate neighbor rate ratio.
- * @param offset Offset to be set
- * @return void
- */
- void setPeerRateOffset( FrequencyRatio offset ) {
- _peer_rate_offset = offset;
- }
-
- /**
- * @brief Sets peer offset timestamps
- * @param mine Local timestamps
- * @param theirs Remote timestamps
- * @return void
- */
- void setPeerOffset(Timestamp mine, Timestamp theirs) {
- _peer_offset_ts_mine = mine;
- _peer_offset_ts_theirs = theirs;
- _peer_offset_init = true;
- }
-
- /**
- * @brief Gets peer offset timestamps
- * @param mine [out] Reference to local timestamps
- * @param theirs [out] Reference to remote timestamps
- * @return TRUE if peer offset has already been initialized. FALSE otherwise.
- */
- bool getPeerOffset(Timestamp & mine, Timestamp & theirs) {
- mine = _peer_offset_ts_mine;
- theirs = _peer_offset_ts_theirs;
- return _peer_offset_init;
- }
-
- /**
- * @brief Adjusts the clock frequency.
- * @param freq_offset Frequency offset
- * @return TRUE if adjusted. FALSE otherwise.
- */
- bool _adjustClockRate( FrequencyRatio freq_offset ) {
- if( _hw_timestamper ) {
- return _hw_timestamper->HWTimestamper_adjclockrate((float) freq_offset );
- }
- return false;
- }
-
- /**
- * @brief Adjusts the clock frequency.
- * @param freq_offset Frequency offset
- * @return TRUE if adjusted. FALSE otherwise.
- */
- bool adjustClockRate( FrequencyRatio freq_offset ) {
- return _adjustClockRate( freq_offset );
- }
-
- /**
- * @brief Gets extended error message from hardware timestamper
- * @param msg [out] Extended error message
- * @return void
- */
- void getExtendedError(char *msg) {
- if (_hw_timestamper) {
- _hw_timestamper->HWTimestamper_get_extderror(msg);
- } else {
- *msg = '\0';
- }
- }
-
- /**
- * @brief Initializes the hwtimestamper
- */
- void timestamper_init(void);
-
- /**
- * @brief Gets RX timestamp based on port identity
- * @param sourcePortIdentity [in] Source port identity
- * @param sequenceId Sequence ID
- * @param timestamp [out] RX timestamp
- * @param counter_value [out] timestamp count value
- * @param last If true, removes the rx lock.
- * @return GPTP_EC_SUCCESS if no error, GPTP_EC_FAILURE if error and GPTP_EC_EAGAIN to try again.
- */
- int getRxTimestamp
- (PortIdentity * sourcePortIdentity, uint16_t sequenceId,
- Timestamp & timestamp, unsigned &counter_value, bool last);
-
- /**
- * @brief Gets TX timestamp based on port identity
- * @param sourcePortIdentity [in] Source port identity
- * @param sequenceId Sequence ID
- * @param timestamp [out] TX timestamp
- * @param counter_value [out] timestamp count value
- * @param last If true, removes the TX lock
- * @return GPTP_EC_SUCCESS if no error, GPTP_EC_FAILURE if error and GPTP_EC_EAGAIN to try again.
- */
- int getTxTimestamp
- (PortIdentity * sourcePortIdentity, uint16_t sequenceId,
- Timestamp & timestamp, unsigned &counter_value, bool last);
-
- /**
- * @brief Gets TX timestamp based on PTP message
- * @param msg PTPMessageCommon message
- * @param timestamp [out] TX timestamp
- * @param counter_value [out] timestamp count value
- * @param last If true, removes the TX lock
- * @return GPTP_EC_SUCCESS if no error, GPTP_EC_FAILURE if error and GPTP_EC_EAGAIN to try again.
- */
- int getTxTimestamp
- (PTPMessageCommon * msg, Timestamp & timestamp, unsigned &counter_value,
- bool last);
-
- /**
- * @brief Gets RX timestamp based on PTP message
- * @param msg PTPMessageCommon message
- * @param timestamp [out] RX timestamp
- * @param counter_value [out] timestamp count value
- * @param last If true, removes the RX lock
- * @return GPTP_EC_SUCCESS if no error, GPTP_EC_FAILURE if error and GPTP_EC_EAGAIN to try again.
- */
- int getRxTimestamp
- (PTPMessageCommon * msg, Timestamp & timestamp, unsigned &counter_value,
- bool last);
-
- /**
- * @brief Get the cross timestamping information.
- * The gPTP subsystem uses these samples to calculate
- * ratios which can be used to translate or extrapolate
- * one clock into another clock reference. The gPTP service
- * uses these supplied cross timestamps to perform internal
- * rate estimation and conversion functions.
- * @param system_time [out] System time
- * @param device_time [out] Device time
- * @param local_clock [out] Local clock
- * @param nominal_clock_rate [out] Nominal clock rate
- * @return True in case of success. FALSE in case of error
- */
- void getDeviceTime
- (Timestamp & system_time, Timestamp & device_time, uint32_t & local_clock,
- uint32_t & nominal_clock_rate);
-
- /**
- * @brief Gets the link delay information.
- * @return one way delay if delay > 0, or zero otherwise.
- */
- uint64_t getLinkDelay(void) {
- return one_way_delay > 0LL ? one_way_delay : 0LL;
- }
-
- /**
- * @brief Gets the link delay information.
- * @param [in] delay Pointer to the delay information
- * @return True if valid, false if invalid
- */
- bool getLinkDelay(uint64_t *delay) {
- if(delay == NULL) {
- return false;
- }
- *delay = getLinkDelay();
- return *delay < INVALID_LINKDELAY;
- }
-
- /**
- * @brief Sets link delay information.
- * Signed value allows this to be negative result because
- * of inaccurate timestamps.
- * @param delay Link delay
- * @return True if one_way_delay is lower or equal than neighbor propagation delay threshold
- * False otherwise
- */
- bool setLinkDelay(int64_t delay) {
- one_way_delay = delay;
- int64_t abs_delay = (one_way_delay < 0 ? -one_way_delay : one_way_delay);
-
- if (testMode) {
- GPTP_LOG_STATUS("Link delay: %d", delay);
- }
-
- return (abs_delay <= neighbor_prop_delay_thresh);
- }
-
- /**
- * @brief Sets the internal variabl sync_receipt_thresh, which is the
- * flag that monitors the amount of wrong syncs enabled before switching
- * the ptp to master.
- * @param th Threshold to be set
- * @return void
- */
- void setSyncReceiptThresh(unsigned int th)
- {
- sync_receipt_thresh = th;
- }
-
- /**
- * @brief Gets the internal variabl sync_receipt_thresh, which is the
- * flag that monitors the amount of wrong syncs enabled before switching
- * the ptp to master.
- * @return sync_receipt_thresh value
- */
- unsigned int getSyncReceiptThresh(void)
- {
- return sync_receipt_thresh;
- }
-
- /**
- * @brief Sets the wrongSeqIDCounter variable
- * @param cnt Value to be set
- * @return void
- */
- void setWrongSeqIDCounter(unsigned int cnt)
- {
- wrongSeqIDCounter = cnt;
- }
-
- /**
- * @brief Gets the wrongSeqIDCounter value
- * @param [out] cnt Pointer to the counter value. It must be valid
- * @return TRUE if ok and lower than the syncReceiptThreshold value. FALSE otherwise
- */
- bool getWrongSeqIDCounter(unsigned int *cnt)
- {
- if( cnt == NULL )
- {
- return false;
- }
- *cnt = wrongSeqIDCounter;
-
- return( *cnt < getSyncReceiptThresh() );
- }
-
- /**
- * @brief Increments the wrongSeqIDCounter value
- * @param [out] cnt Pointer to the counter value. Must be valid
- * @return TRUE if incremented value is lower than the syncReceiptThreshold. FALSE otherwise.
- */
- bool incWrongSeqIDCounter(unsigned int *cnt)
- {
- if( getAsCapable() )
- {
- wrongSeqIDCounter++;
- }
- bool ret = wrongSeqIDCounter < getSyncReceiptThresh();
-
- if( cnt != NULL)
- {
- *cnt = wrongSeqIDCounter;
- }
-
- return ret;
- }
-
- /**
- * @brief Sets the value of last duplicated SeqID
- * @param seqid Value to set
- * @return void
- */
- void setLastInvalidSeqID(uint16_t seqid)
- {
- last_invalid_seqid = seqid;
- }
-
- /**
- * @brief Get the value of last invalid seqID
- * @return Last invalid seq id
- */
- uint16_t getLastInvalidSeqID(void)
- {
- return last_invalid_seqid;
- }
-
- /**
- * @brief Sets the duplicate pdelay_resp counter.
- * @param cnt Value to be set
- */
- void setDuplicateRespCounter(unsigned int cnt)
- {
- duplicate_resp_counter = cnt;
- }
-
- /**
- * @brief Gets the current value of pdelay_resp duplicate messages counter
- * @return Counter value
- */
- unsigned int getDuplicateRespCounter(void)
- {
- return duplicate_resp_counter;
- }
-
- /**
- * @brief Increment the duplicate PDelayResp message counter
- * @return True if it equals the threshold, False otherwise
- */
- bool incrementDuplicateRespCounter(void)
- {
- return ++duplicate_resp_counter == DUPLICATE_RESP_THRESH;
- }
-
- /**
- * @brief Sets the neighbor propagation delay threshold
- * @param delay Delay in nanoseconds
- * @return void
- */
- void setNeighPropDelayThresh(int64_t delay) {
- neighbor_prop_delay_thresh = delay;
- }
-
- /**
- * @brief Changes the port state
- * @param state Current state
- * @param changed_external_master TRUE if external master has changed, FALSE otherwise
- * @return void
- */
- void recommendState(PortState state, bool changed_external_master);
-
- /**
- * @brief Maps socket addr to the remote link layer address
- * @param destIdentity [in] PortIdentity remote
- * @param remote [in] remote link layer address
- * @return void
- */
- void mapSocketAddr
- (PortIdentity * destIdentity, LinkLayerAddress * remote);
-
- /**
- * @brief Adds New sock addr map
- * @param destIdentity [in] PortIdentity remote
- * @param remote [in] remote link layer address
- * @return void
- */
- void addSockAddrMap
- (PortIdentity * destIdentity, LinkLayerAddress * remote);
-
- /**
- * @brief Sets current pdelay count value.
- * @param cnt [in] pdelay count value
- * @return void
- */
- void setPdelayCount(unsigned int cnt) {
- pdelay_count = cnt;
- }
-
- /**
- * @brief Increments Pdelay count
- * @return void
- */
- void incPdelayCount() {
- ++pdelay_count;
- }
-
- /**
- * @brief Gets current pdelay count value. It is set to zero
- * when asCapable is false.
- * @return pdelay count
- */
- unsigned getPdelayCount() {
- return pdelay_count;
- }
-
- /**
- * @brief Sets current sync count value.
- * @param cnt [in] sync count value
- * @return void
- */
- void setSyncCount(unsigned int cnt) {
- sync_count = cnt;
- }
-
- /**
- * @brief Increments sync count
- * @return void
- */
- void incSyncCount() {
- ++sync_count;
- }
-
- /**
- * @brief Gets current sync count value. It is set to zero
- * when master and incremented at each sync received for slave.
- * @return sync count
- */
- unsigned getSyncCount() {
- return sync_count;
- }
-
- /**
- * @brief Gets link up count
- * @return Link up count
- */
- uint32_t getLinkUpCount() {
- return linkUpCount;
- }
-
- /**
- * @brief Gets link down count
- * @return Link down count
- */
- uint32_t getLinkDownCount() {
- return linkDownCount;
- }
-
- /**
- * @brief Sets the Station State for the Test Status message
- * @param StationState_t [in] The station state
- * @return none
- */
- void setStationState(StationState_t _stationState) {
- stationState = _stationState;
- if (stationState == STATION_STATE_ETHERNET_READY) {
- GPTP_LOG_STATUS("AVnu AP Status : STATION_STATE_ETHERNET_READY");
- }
- else if (stationState == STATION_STATE_AVB_SYNC) {
- GPTP_LOG_STATUS("AVnu AP Status : STATION_STATE_AVB_SYNC");
- }
- else if (stationState == STATION_STATE_AVB_MEDIA_READY) {
- GPTP_LOG_STATUS("AVnu AP Status : STATION_STATE_AVB_MEDIA_READY");
- }
- }
-
- /**
- * @brief Gets the Station State for the Test Status
- * message
- * @return station state
- */
- StationState_t getStationState() {
- return stationState;
- }
-
-
- /**
- * @brief Gets the lastGmTimeBaseIndicator
- * @return uint16 of the lastGmTimeBaseIndicator
- */
- uint16_t getLastGmTimeBaseIndicator(void) {
- return lastGmTimeBaseIndicator;
- }
-
- /**
- * @brief Sets the lastGmTimeBaseIndicator
- * @param gmTimeBaseIndicator from last Follow up message
- * @return void
- */
- void setLastGmTimeBaseIndicator(uint16_t gmTimeBaseIndicator) {
- lastGmTimeBaseIndicator = gmTimeBaseIndicator;
- }
-
- /**
- * @brief Gets the testMode
- * @return bool of the test mode value
- */
- bool getTestMode(void) {
- return testMode;
- }
-
- /**
- * @brief Increment IEEE Port counter:
- * ieee8021AsPortStatRxSyncCount
- * @return void
- */
- void incCounter_ieee8021AsPortStatRxSyncCount(void) {
- counters.ieee8021AsPortStatRxSyncCount++;
- }
-
- /**
- * @brief Increment IEEE Port counter:
- * ieee8021AsPortStatRxFollowUpCount
- * @return void
- */
- void incCounter_ieee8021AsPortStatRxFollowUpCount(void) {
- counters.ieee8021AsPortStatRxFollowUpCount++;
- }
-
- /**
- * @brief Increment IEEE Port counter:
- * ieee8021AsPortStatRxPdelayRequest
- * @return void
- */
- void incCounter_ieee8021AsPortStatRxPdelayRequest(void) {
- counters.ieee8021AsPortStatRxPdelayRequest++;
- }
-
- /**
- * @brief Increment IEEE Port counter:
- * ieee8021AsPortStatRxPdelayResponse
- * @return void
- */
- void incCounter_ieee8021AsPortStatRxPdelayResponse(void) {
- counters.ieee8021AsPortStatRxPdelayResponse++;
- }
-
- /**
- * @brief Increment IEEE Port counter:
- * ieee8021AsPortStatRxPdelayResponseFollowUp
- * @return void
- */
- void incCounter_ieee8021AsPortStatRxPdelayResponseFollowUp(void) {
- counters.ieee8021AsPortStatRxPdelayResponseFollowUp++;
- }
-
- /**
- * @brief Increment IEEE Port counter:
- * ieee8021AsPortStatRxAnnounce
- * @return void
- */
- void incCounter_ieee8021AsPortStatRxAnnounce(void) {
- counters.ieee8021AsPortStatRxAnnounce++;
- }
-
- /**
- * @brief Increment IEEE Port counter:
- * ieee8021AsPortStatRxPTPPacketDiscard
- * @return void
- */
- void incCounter_ieee8021AsPortStatRxPTPPacketDiscard(void) {
- counters.ieee8021AsPortStatRxPTPPacketDiscard++;
- }
-
- /**
- * @brief Increment IEEE Port counter:
- * ieee8021AsPortStatRxSyncReceiptTimeouts
- * @return void
- */
- void incCounter_ieee8021AsPortStatRxSyncReceiptTimeouts(void) {
- counters.ieee8021AsPortStatRxSyncReceiptTimeouts++;
- }
-
- /**
- * @brief Increment IEEE Port counter:
- * ieee8021AsPortStatAnnounceReceiptTimeouts
- * @return void
- */
- void incCounter_ieee8021AsPortStatAnnounceReceiptTimeouts(void) {
- counters.ieee8021AsPortStatAnnounceReceiptTimeouts++;
- }
-
-
- /**
- * @brief Increment IEEE Port counter:
- * ieee8021AsPortStatPdelayAllowedLostResponsesExceeded
- * @return void
- */
- // TODO: Not called
- void incCounter_ieee8021AsPortStatPdelayAllowedLostResponsesExceeded(void) {
- counters.ieee8021AsPortStatPdelayAllowedLostResponsesExceeded++;
- }
-
- /**
- * @brief Increment IEEE Port counter:
- * ieee8021AsPortStatTxSyncCount
- * @return void
- */
- void incCounter_ieee8021AsPortStatTxSyncCount(void) {
- counters.ieee8021AsPortStatTxSyncCount++;
- }
-
- /**
- * @brief Increment IEEE Port counter:
- * ieee8021AsPortStatTxFollowUpCount
- * @return void
- */
- void incCounter_ieee8021AsPortStatTxFollowUpCount(void) {
- counters.ieee8021AsPortStatTxFollowUpCount++;
- }
-
- /**
- * @brief Increment IEEE Port counter:
- * ieee8021AsPortStatTxPdelayRequest
- * @return void
- */
- void incCounter_ieee8021AsPortStatTxPdelayRequest(void) {
- counters.ieee8021AsPortStatTxPdelayRequest++;
- }
-
- /**
- * @brief Increment IEEE Port counter:
- * ieee8021AsPortStatTxPdelayResponse
- * @return void
- */
- void incCounter_ieee8021AsPortStatTxPdelayResponse(void) {
- counters.ieee8021AsPortStatTxPdelayResponse++;
- }
-
- /**
- * @brief Increment IEEE Port counter:
- * ieee8021AsPortStatTxPdelayResponseFollowUp
- * @return void
- */
- void incCounter_ieee8021AsPortStatTxPdelayResponseFollowUp(void) {
- counters.ieee8021AsPortStatTxPdelayResponseFollowUp++;
- }
-
- /**
- * @brief Increment IEEE Port counter:
- * ieee8021AsPortStatTxAnnounce
- * @return void
- */
- void incCounter_ieee8021AsPortStatTxAnnounce(void) {
- counters.ieee8021AsPortStatTxAnnounce++;
- }
-
- /**
- * @brief Logs port counters
- * @return void
- */
- void logIEEEPortCounters(void) {
- GPTP_LOG_STATUS("IEEE Port Counter ieee8021AsPortStatRxSyncCount : %u", counters.ieee8021AsPortStatRxSyncCount);
- GPTP_LOG_STATUS("IEEE Port Counter ieee8021AsPortStatRxFollowUpCount : %u", counters.ieee8021AsPortStatRxFollowUpCount);
- GPTP_LOG_STATUS("IEEE Port Counter ieee8021AsPortStatRxPdelayRequest : %u", counters.ieee8021AsPortStatRxPdelayRequest);
- GPTP_LOG_STATUS("IEEE Port Counter ieee8021AsPortStatRxPdelayResponse : %u", counters.ieee8021AsPortStatRxPdelayResponse);
- GPTP_LOG_STATUS("IEEE Port Counter ieee8021AsPortStatRxPdelayResponseFollowUp : %u", counters.ieee8021AsPortStatRxPdelayResponseFollowUp);
- GPTP_LOG_STATUS("IEEE Port Counter ieee8021AsPortStatRxAnnounce : %u", counters.ieee8021AsPortStatRxAnnounce);
- GPTP_LOG_STATUS("IEEE Port Counter ieee8021AsPortStatRxPTPPacketDiscard : %u", counters.ieee8021AsPortStatRxPTPPacketDiscard);
- GPTP_LOG_STATUS("IEEE Port Counter ieee8021AsPortStatRxSyncReceiptTimeouts : %u", counters.ieee8021AsPortStatRxSyncReceiptTimeouts);
- GPTP_LOG_STATUS("IEEE Port Counter ieee8021AsPortStatAnnounceReceiptTimeouts : %u", counters.ieee8021AsPortStatAnnounceReceiptTimeouts);
- GPTP_LOG_STATUS("IEEE Port Counter ieee8021AsPortStatPdelayAllowedLostResponsesExceeded : %u", counters.ieee8021AsPortStatPdelayAllowedLostResponsesExceeded);
- GPTP_LOG_STATUS("IEEE Port Counter ieee8021AsPortStatTxSyncCount : %u", counters.ieee8021AsPortStatTxSyncCount);
- GPTP_LOG_STATUS("IEEE Port Counter ieee8021AsPortStatTxFollowUpCount : %u", counters.ieee8021AsPortStatTxFollowUpCount);
- GPTP_LOG_STATUS("IEEE Port Counter ieee8021AsPortStatTxPdelayRequest : %u", counters.ieee8021AsPortStatTxPdelayRequest);
- GPTP_LOG_STATUS("IEEE Port Counter ieee8021AsPortStatTxPdelayResponse : %u", counters.ieee8021AsPortStatTxPdelayResponse);
- GPTP_LOG_STATUS("IEEE Port Counter ieee8021AsPortStatTxPdelayResponseFollowUp : %u", counters.ieee8021AsPortStatTxPdelayResponseFollowUp);
- GPTP_LOG_STATUS("IEEE Port Counter ieee8021AsPortStatTxAnnounce : %u", counters.ieee8021AsPortStatTxAnnounce);
- }
-};
-
-#endif
diff --git a/daemons/gptp/common/common_port.cpp b/daemons/gptp/common/common_port.cpp
new file mode 100644
index 00000000..d8ba54f6
--- /dev/null
+++ b/daemons/gptp/common/common_port.cpp
@@ -0,0 +1,751 @@
+/******************************************************************************
+
+ Copyright (c) 2009-2012, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+******************************************************************************/
+
+
+#include <common_port.hpp>
+#include <avbts_clock.hpp>
+#include <common_tstamper.hpp>
+#include <gptp_cfg.hpp>
+
+CommonPort::CommonPort( PortInit_t *portInit ) :
+ thread_factory( portInit->thread_factory ),
+ timer_factory( portInit->timer_factory ),
+ lock_factory( portInit->lock_factory ),
+ condition_factory( portInit->condition_factory ),
+ _hw_timestamper( portInit->timestamper ),
+ clock( portInit->clock ),
+ isGM( portInit->isGM ),
+ phy_delay( portInit->phy_delay )
+{
+ one_way_delay = ONE_WAY_DELAY_DEFAULT;
+ neighbor_prop_delay_thresh = portInit->neighborPropDelayThreshold;
+ net_label = portInit->net_label;
+ link_thread = thread_factory->createThread();
+ listening_thread = thread_factory->createThread();
+ sync_receipt_thresh = portInit->syncReceiptThreshold;
+ wrongSeqIDCounter = 0;
+ _peer_rate_offset = 1.0;
+ _peer_offset_init = false;
+ ifindex = portInit->index;
+ testMode = false;
+ port_state = PTP_INITIALIZING;
+ clock->registerPort(this, ifindex);
+ qualified_announce = NULL;
+ announce_sequence_id = 0;
+ signal_sequence_id = 0;
+ sync_sequence_id = 0;
+ initialLogSyncInterval = portInit->initialLogSyncInterval;
+ log_mean_announce_interval = 0;
+ pdelay_count = 0;
+ asCapable = false;
+ link_speed = INVALID_LINKSPEED;
+}
+
+CommonPort::~CommonPort()
+{
+ delete qualified_announce;
+}
+
+bool CommonPort::init_port( void )
+{
+ log_mean_sync_interval = initialLogSyncInterval;
+
+ if (!OSNetworkInterfaceFactory::buildInterface
+ ( &net_iface, factory_name_t("default"), net_label,
+ _hw_timestamper))
+ return false;
+
+ this->net_iface->getLinkLayerAddress(&local_addr);
+ clock->setClockIdentity(&local_addr);
+
+ this->timestamper_init();
+
+ port_identity.setClockIdentity(clock->getClockIdentity());
+ port_identity.setPortNumber(&ifindex);
+
+ syncReceiptTimerLock = lock_factory->createLock(oslock_recursive);
+ syncIntervalTimerLock = lock_factory->createLock(oslock_recursive);
+ announceIntervalTimerLock = lock_factory->createLock(oslock_recursive);
+
+ return _init_port();
+}
+
+void CommonPort::timestamper_init( void )
+{
+ if( _hw_timestamper != NULL )
+ {
+ if( !_hw_timestamper->HWTimestamper_init
+ ( net_label, net_iface ))
+ {
+ GPTP_LOG_ERROR
+ ( "Failed to initialize hardware timestamper, "
+ "falling back to software timestamping" );
+ return;
+ }
+ }
+}
+
+void CommonPort::timestamper_reset( void )
+{
+ if( _hw_timestamper != NULL )
+ {
+ _hw_timestamper->HWTimestamper_reset();
+ }
+}
+
+PTPMessageAnnounce *CommonPort::calculateERBest( void )
+{
+ return qualified_announce;
+}
+
+void CommonPort::recommendState
+( PortState state, bool changed_external_master )
+{
+ bool reset_sync = false;
+ switch (state) {
+ case PTP_MASTER:
+ if ( getPortState() != PTP_MASTER )
+ {
+ setPortState( PTP_MASTER );
+ // Start announce receipt timeout timer
+ // Start sync receipt timeout timer
+ becomeMaster( true );
+ reset_sync = true;
+ }
+ break;
+ case PTP_SLAVE:
+ if ( getPortState() != PTP_SLAVE )
+ {
+ becomeSlave( true );
+ reset_sync = true;
+ } else {
+ if( changed_external_master ) {
+ GPTP_LOG_STATUS("Changed master!" );
+ clock->newSyntonizationSetPoint();
+ clock->updateFUPInfo();
+ reset_sync = true;
+ }
+ }
+ break;
+ default:
+ GPTP_LOG_ERROR
+ ("Invalid state change requested by call to "
+ "1588Port::recommendState()");
+ break;
+ }
+ if( reset_sync ) sync_count = 0;
+ return;
+}
+
+bool CommonPort::serializeState( void *buf, off_t *count )
+{
+ bool ret = true;
+
+ if( buf == NULL ) {
+ *count = sizeof(port_state)+sizeof(_peer_rate_offset)+
+ sizeof(asCapable)+sizeof(one_way_delay);
+ return true;
+ }
+
+ if( port_state != PTP_MASTER && port_state != PTP_SLAVE ) {
+ *count = 0;
+ ret = false;
+ goto bail;
+ }
+
+ /* asCapable */
+ if( ret && *count >= (off_t) sizeof( asCapable )) {
+ memcpy( buf, &asCapable, sizeof( asCapable ));
+ *count -= sizeof( asCapable );
+ buf = ((char *)buf) + sizeof( asCapable );
+ } else if( ret == false ) {
+ *count += sizeof( asCapable );
+ } else {
+ *count = sizeof( asCapable )-*count;
+ ret = false;
+ }
+
+ /* Port State */
+ if( ret && *count >= (off_t) sizeof( port_state )) {
+ memcpy( buf, &port_state, sizeof( port_state ));
+ *count -= sizeof( port_state );
+ buf = ((char *)buf) + sizeof( port_state );
+ } else if( ret == false ) {
+ *count += sizeof( port_state );
+ } else {
+ *count = sizeof( port_state )-*count;
+ ret = false;
+ }
+
+ /* Link Delay */
+ if( ret && *count >= (off_t) sizeof( one_way_delay )) {
+ memcpy( buf, &one_way_delay, sizeof( one_way_delay ));
+ *count -= sizeof( one_way_delay );
+ buf = ((char *)buf) + sizeof( one_way_delay );
+ } else if( ret == false ) {
+ *count += sizeof( one_way_delay );
+ } else {
+ *count = sizeof( one_way_delay )-*count;
+ ret = false;
+ }
+
+ /* Neighbor Rate Ratio */
+ if( ret && *count >= (off_t) sizeof( _peer_rate_offset )) {
+ memcpy( buf, &_peer_rate_offset, sizeof( _peer_rate_offset ));
+ *count -= sizeof( _peer_rate_offset );
+ buf = ((char *)buf) + sizeof( _peer_rate_offset );
+ } else if( ret == false ) {
+ *count += sizeof( _peer_rate_offset );
+ } else {
+ *count = sizeof( _peer_rate_offset )-*count;
+ ret = false;
+ }
+
+ bail:
+ return ret;
+}
+
+bool CommonPort::restoreSerializedState
+( void *buf, off_t *count )
+{
+ bool ret = true;
+
+ /* asCapable */
+ if( ret && *count >= (off_t) sizeof( asCapable )) {
+ memcpy( &asCapable, buf, sizeof( asCapable ));
+ *count -= sizeof( asCapable );
+ buf = ((char *)buf) + sizeof( asCapable );
+ } else if( ret == false ) {
+ *count += sizeof( asCapable );
+ } else {
+ *count = sizeof( asCapable )-*count;
+ ret = false;
+ }
+
+ /* Port State */
+ if( ret && *count >= (off_t) sizeof( port_state )) {
+ memcpy( &port_state, buf, sizeof( port_state ));
+ *count -= sizeof( port_state );
+ buf = ((char *)buf) + sizeof( port_state );
+ } else if( ret == false ) {
+ *count += sizeof( port_state );
+ } else {
+ *count = sizeof( port_state )-*count;
+ ret = false;
+ }
+
+ /* Link Delay */
+ if( ret && *count >= (off_t) sizeof( one_way_delay )) {
+ memcpy( &one_way_delay, buf, sizeof( one_way_delay ));
+ *count -= sizeof( one_way_delay );
+ buf = ((char *)buf) + sizeof( one_way_delay );
+ } else if( ret == false ) {
+ *count += sizeof( one_way_delay );
+ } else {
+ *count = sizeof( one_way_delay )-*count;
+ ret = false;
+ }
+
+ /* Neighbor Rate Ratio */
+ if( ret && *count >= (off_t) sizeof( _peer_rate_offset )) {
+ memcpy( &_peer_rate_offset, buf, sizeof( _peer_rate_offset ));
+ *count -= sizeof( _peer_rate_offset );
+ buf = ((char *)buf) + sizeof( _peer_rate_offset );
+ } else if( ret == false ) {
+ *count += sizeof( _peer_rate_offset );
+ } else {
+ *count = sizeof( _peer_rate_offset )-*count;
+ ret = false;
+ }
+
+ return ret;
+}
+
+void CommonPort::startSyncReceiptTimer
+( long long unsigned int waitTime )
+{
+ syncReceiptTimerLock->lock();
+ clock->deleteEventTimerLocked( this, SYNC_RECEIPT_TIMEOUT_EXPIRES );
+ clock->addEventTimerLocked
+ ( this, SYNC_RECEIPT_TIMEOUT_EXPIRES, waitTime );
+ syncReceiptTimerLock->unlock();
+}
+
+void CommonPort::stopSyncReceiptTimer( void )
+{
+ syncReceiptTimerLock->lock();
+ clock->deleteEventTimerLocked( this, SYNC_RECEIPT_TIMEOUT_EXPIRES );
+ syncReceiptTimerLock->unlock();
+}
+
+void CommonPort::startSyncIntervalTimer
+( long long unsigned int waitTime )
+{
+ if( syncIntervalTimerLock->trylock() == oslock_fail ) return;
+ clock->deleteEventTimerLocked(this, SYNC_INTERVAL_TIMEOUT_EXPIRES);
+ clock->addEventTimerLocked
+ (this, SYNC_INTERVAL_TIMEOUT_EXPIRES, waitTime);
+ syncIntervalTimerLock->unlock();
+}
+
+void CommonPort::startAnnounceIntervalTimer
+( long long unsigned int waitTime )
+{
+ announceIntervalTimerLock->lock();
+ clock->deleteEventTimerLocked
+ ( this, ANNOUNCE_INTERVAL_TIMEOUT_EXPIRES );
+ clock->addEventTimerLocked
+ ( this, ANNOUNCE_INTERVAL_TIMEOUT_EXPIRES, waitTime );
+ announceIntervalTimerLock->unlock();
+}
+
+bool CommonPort::processStateChange( Event e )
+{
+ bool changed_external_master;
+ uint8_t LastEBestClockIdentity[PTP_CLOCK_IDENTITY_LENGTH];
+ int number_ports, j;
+ PTPMessageAnnounce *EBest = NULL;
+ char EBestClockIdentity[PTP_CLOCK_IDENTITY_LENGTH];
+ CommonPort **ports;
+
+ // Nothing to do if we are slave only
+ if ( clock->getPriority1() == 255 )
+ return true;
+
+ clock->getPortList(number_ports, ports);
+
+ /* Find EBest for all ports */
+ j = 0;
+ for (int i = 0; i < number_ports; ++i) {
+ while (ports[j] == NULL)
+ ++j;
+ if ( ports[j]->getPortState() == PTP_DISABLED ||
+ ports[j]->getPortState() == PTP_FAULTY )
+ {
+ continue;
+ }
+ if( EBest == NULL )
+ {
+ EBest = ports[j]->calculateERBest();
+ }
+ else if( ports[j]->calculateERBest() )
+ {
+ if( ports[j]->
+ calculateERBest()->isBetterThan(EBest))
+ {
+ EBest = ports[j]->calculateERBest();
+ }
+ }
+ }
+
+ if (EBest == NULL)
+ {
+ return true;
+ }
+
+ /* Check if we've changed */
+ clock->getLastEBestIdentity().
+ getIdentityString( LastEBestClockIdentity );
+ EBest->getGrandmasterIdentity( EBestClockIdentity );
+ if( memcmp( EBestClockIdentity, LastEBestClockIdentity,
+ PTP_CLOCK_IDENTITY_LENGTH ) != 0 )
+ {
+ ClockIdentity newGM;
+ changed_external_master = true;
+ newGM.set((uint8_t *) EBestClockIdentity );
+ clock->setLastEBestIdentity( newGM );
+ }
+ else
+ {
+ changed_external_master = false;
+ }
+
+ if( clock->isBetterThan( EBest ))
+ {
+ // We're Grandmaster, set grandmaster info to me
+ ClockIdentity clock_identity;
+ unsigned char priority1;
+ unsigned char priority2;
+ ClockQuality clock_quality;
+
+ clock_identity = getClock()->getClockIdentity();
+ getClock()->setGrandmasterClockIdentity( clock_identity );
+ priority1 = getClock()->getPriority1();
+ getClock()->setGrandmasterPriority1( priority1 );
+ priority2 = getClock()->getPriority2();
+ getClock()->setGrandmasterPriority2( priority2 );
+ clock_quality = getClock()->getClockQuality();
+ getClock()->setGrandmasterClockQuality( clock_quality );
+ }
+
+ j = 0;
+ for( int i = 0; i < number_ports; ++i )
+ {
+ while (ports[j] == NULL)
+ ++j;
+ if ( ports[j]->getPortState() ==
+ PTP_DISABLED ||
+ ports[j]->getPortState() ==
+ PTP_FAULTY)
+ {
+ continue;
+ }
+ if (clock->isBetterThan(EBest))
+ {
+ // We are the GrandMaster, all ports are master
+ EBest = NULL; // EBest == NULL : we were grandmaster
+ ports[j]->recommendState( PTP_MASTER,
+ changed_external_master );
+ } else {
+ if( EBest == ports[j]->calculateERBest() ) {
+ // The "best" Announce was received on this
+ // port
+ ClockIdentity clock_identity;
+ unsigned char priority1;
+ unsigned char priority2;
+ ClockQuality *clock_quality;
+
+ ports[j]->recommendState
+ ( PTP_SLAVE, changed_external_master );
+ clock_identity =
+ EBest->getGrandmasterClockIdentity();
+ getClock()->setGrandmasterClockIdentity
+ ( clock_identity );
+ priority1 = EBest->getGrandmasterPriority1();
+ getClock()->setGrandmasterPriority1
+ ( priority1 );
+ priority2 =
+ EBest->getGrandmasterPriority2();
+ getClock()->setGrandmasterPriority2
+ ( priority2 );
+ clock_quality =
+ EBest->getGrandmasterClockQuality();
+ getClock()->setGrandmasterClockQuality
+ (*clock_quality);
+ } else {
+ /* Otherwise we are the master because we have
+ sync'd to a better clock */
+ ports[j]->recommendState
+ (PTP_MASTER, changed_external_master);
+ }
+ }
+ }
+
+ return true;
+}
+
+
+bool CommonPort::processSyncAnnounceTimeout( Event e )
+{
+ // We're Grandmaster, set grandmaster info to me
+ ClockIdentity clock_identity;
+ unsigned char priority1;
+ unsigned char priority2;
+ ClockQuality clock_quality;
+
+ Timestamp system_time;
+ Timestamp device_time;
+ uint32_t local_clock, nominal_clock_rate;
+
+ // Nothing to do
+ if( clock->getPriority1() == 255 )
+ return true;
+
+ // Restart timer
+ if( e == ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES ) {
+ clock->addEventTimerLocked
+ (this, ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES,
+ (ANNOUNCE_RECEIPT_TIMEOUT_MULTIPLIER*
+ (unsigned long long)
+ (pow((double)2,getAnnounceInterval())*
+ 1000000000.0)));
+ } else {
+ startSyncReceiptTimer
+ ((unsigned long long)
+ (SYNC_RECEIPT_TIMEOUT_MULTIPLIER *
+ ((double) pow((double)2, getSyncInterval()) *
+ 1000000000.0)));
+ }
+
+ if( getPortState() == PTP_MASTER )
+ return true;
+
+ GPTP_LOG_STATUS(
+ "*** %s Timeout Expired - Becoming Master",
+ e == ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES ? "Announce" :
+ "Sync" );
+
+ clock_identity = getClock()->getClockIdentity();
+ getClock()->setGrandmasterClockIdentity( clock_identity );
+ priority1 = getClock()->getPriority1();
+ getClock()->setGrandmasterPriority1( priority1 );
+ priority2 = getClock()->getPriority2();
+ getClock()->setGrandmasterPriority2( priority2 );
+ clock_quality = getClock()->getClockQuality();
+ getClock()->setGrandmasterClockQuality( clock_quality );
+
+ setPortState( PTP_MASTER );
+
+ getDeviceTime( system_time, device_time,
+ local_clock, nominal_clock_rate );
+
+ (void) clock->calcLocalSystemClockRateDifference
+ ( device_time, system_time );
+
+ setQualifiedAnnounce( NULL );
+
+ clock->addEventTimerLocked
+ ( this, SYNC_INTERVAL_TIMEOUT_EXPIRES,
+ 16000000 );
+
+ startAnnounce();
+
+ return true;
+}
+
+bool CommonPort::processEvent( Event e )
+{
+ bool ret;
+
+ switch( e )
+ {
+ default:
+ // Unhandled event
+ ret = _processEvent( e );
+ break;
+
+ case POWERUP:
+ case INITIALIZE:
+ GPTP_LOG_DEBUG("Received POWERUP/INITIALIZE event");
+
+ // If port has been configured as master or slave, run media
+ // specific configuration. If it hasn't been configured
+ // start listening for announce messages
+ if( clock->getPriority1() == 255 ||
+ port_state == PTP_SLAVE )
+ {
+ becomeSlave( true );
+ }
+ else if( port_state == PTP_MASTER )
+ {
+ becomeMaster( true );
+ }
+ else
+ {
+ clock->addEventTimerLocked(this, ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES,
+ ANNOUNCE_RECEIPT_TIMEOUT_MULTIPLIER * pow(2.0, getAnnounceInterval()) * 1000000000.0);
+ }
+
+ // Do any media specific initialization
+ ret = _processEvent( e );
+ break;
+
+ case STATE_CHANGE_EVENT:
+ ret = _processEvent( e );
+
+ // If this event wasn't handled in a media specific way, call
+ // the default action
+ if( !ret )
+ ret = processStateChange( e );
+ break;
+
+ case ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES:
+ case SYNC_RECEIPT_TIMEOUT_EXPIRES:
+ if (e == ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES) {
+ incCounter_ieee8021AsPortStatAnnounceReceiptTimeouts();
+ }
+ else if (e == SYNC_RECEIPT_TIMEOUT_EXPIRES) {
+ incCounter_ieee8021AsPortStatRxSyncReceiptTimeouts();
+ }
+
+ ret = _processEvent( e );
+
+ // If this event wasn't handled in a media specific way, call
+ // the default action
+ if( !ret )
+ ret = processSyncAnnounceTimeout( e );
+ break;
+
+ case ANNOUNCE_INTERVAL_TIMEOUT_EXPIRES:
+ GPTP_LOG_DEBUG("ANNOUNCE_INTERVAL_TIMEOUT_EXPIRES occured");
+
+ // Send an announce message
+ if ( asCapable)
+ {
+ PTPMessageAnnounce *annc =
+ new PTPMessageAnnounce(this);
+ PortIdentity dest_id;
+ PortIdentity gmId;
+ ClockIdentity clock_id = clock->getClockIdentity();
+ gmId.setClockIdentity(clock_id);
+ getPortIdentity( dest_id );
+ annc->setPortIdentity( &dest_id );
+ annc->sendPort( this, NULL );
+ delete annc;
+ }
+
+ startAnnounceIntervalTimer
+ ((uint64_t)( pow((double)2, getAnnounceInterval()) *
+ 1000000000.0 ));
+ ret = true;
+ break;
+
+ case SYNC_INTERVAL_TIMEOUT_EXPIRES:
+ GPTP_LOG_DEBUG("SYNC_INTERVAL_TIMEOUT_EXPIRES occured");
+ // If asCapable is true attempt some media specific action
+ ret = true;
+ if( asCapable )
+ ret = _processEvent( e );
+
+ /* Do getDeviceTime() after transmitting sync frame
+ causing an update to local/system timestamp */
+ {
+ Timestamp system_time;
+ Timestamp device_time;
+ uint32_t local_clock, nominal_clock_rate;
+ FrequencyRatio local_system_freq_offset;
+ int64_t local_system_offset;
+
+ getDeviceTime
+ ( system_time, device_time,
+ local_clock, nominal_clock_rate );
+
+ GPTP_LOG_VERBOSE
+ ( "port::processEvent(): System time: %u,%u "
+ "Device Time: %u,%u",
+ system_time.seconds_ls,
+ system_time.nanoseconds,
+ device_time.seconds_ls,
+ device_time.nanoseconds );
+
+ local_system_offset =
+ TIMESTAMP_TO_NS(system_time) -
+ TIMESTAMP_TO_NS(device_time);
+ local_system_freq_offset =
+ clock->calcLocalSystemClockRateDifference
+ ( device_time, system_time );
+ clock->setMasterOffset
+ ( this, 0, device_time, 1.0,
+ local_system_offset, system_time,
+ local_system_freq_offset, getSyncCount(),
+ pdelay_count, port_state, asCapable );
+ }
+
+ // Call media specific action for completed sync
+ syncDone();
+
+ // Restart the timer
+ startSyncIntervalTimer
+ ((uint64_t)( pow((double)2, getSyncInterval()) *
+ 1000000000.0 ));
+
+ break;
+ }
+
+ return ret;
+}
+
+void CommonPort::getDeviceTime
+( Timestamp &system_time, Timestamp &device_time,
+ uint32_t &local_clock, uint32_t &nominal_clock_rate )
+{
+ if (_hw_timestamper) {
+ _hw_timestamper->HWTimestamper_gettime
+ ( &system_time, &device_time,
+ &local_clock, &nominal_clock_rate );
+ } else {
+ device_time = system_time = clock->getSystemTime();
+ local_clock = nominal_clock_rate = 0;
+ }
+
+ return;
+}
+
+void CommonPort::startAnnounce()
+{
+ startAnnounceIntervalTimer(16000000);
+}
+
+int CommonPort::getTimestampVersion()
+{
+ return _hw_timestamper->getVersion();
+}
+
+bool CommonPort::_adjustClockRate( FrequencyRatio freq_offset )
+{
+ if( _hw_timestamper )
+ {
+ return _hw_timestamper->HWTimestamper_adjclockrate
+ ((float) freq_offset );
+ }
+
+ return false;
+}
+
+void CommonPort::getExtendedError( char *msg )
+{
+ if (_hw_timestamper)
+ {
+ _hw_timestamper->HWTimestamper_get_extderror(msg);
+ return;
+ }
+
+ *msg = '\0';
+}
+
+bool CommonPort::adjustClockPhase( int64_t phase_adjust )
+{
+ if( _hw_timestamper )
+ return _hw_timestamper->
+ HWTimestamper_adjclockphase( phase_adjust );
+
+ return false;
+}
+
+Timestamp CommonPort::getTxPhyDelay( uint32_t link_speed ) const
+{
+ if( phy_delay->count( link_speed ) != 0 )
+ return Timestamp
+ ( phy_delay->at(link_speed).get_tx_delay(), 0, 0 );
+
+ return Timestamp(0, 0, 0);
+}
+
+Timestamp CommonPort::getRxPhyDelay( uint32_t link_speed ) const
+{
+ if( phy_delay->count( link_speed ) != 0 )
+ return Timestamp
+ ( phy_delay->at(link_speed).get_rx_delay(), 0, 0 );
+
+ return Timestamp(0, 0, 0);
+}
diff --git a/daemons/gptp/common/common_port.hpp b/daemons/gptp/common/common_port.hpp
new file mode 100644
index 00000000..d5d0adda
--- /dev/null
+++ b/daemons/gptp/common/common_port.hpp
@@ -0,0 +1,1455 @@
+/******************************************************************************
+
+ Copyright (c) 2009-2012, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+******************************************************************************/
+
+
+#ifndef COMMON_PORT_HPP
+#define COMMON_PORT_HPP
+
+#include <avbts_message.hpp>
+#include <avbts_osthread.hpp>
+#include <avbts_oscondition.hpp>
+#include <avbts_ostimer.hpp>
+#include <avbts_oslock.hpp>
+#include <avbts_osnet.hpp>
+#include <unordered_map>
+
+#include <math.h>
+
+class IEEE1588Clock;
+
+/**
+ * @brief PortIdentity interface
+ * Defined at IEEE 802.1AS Clause 8.5.2
+ */
+class PortIdentity {
+private:
+ ClockIdentity clock_id;
+ uint16_t portNumber;
+public:
+ /**
+ * @brief Default Constructor
+ */
+ PortIdentity() { };
+
+ /**
+ * @brief Constructs PortIdentity interface.
+ * @param clock_id Clock ID value as defined at IEEE 802.1AS Clause
+ * 8.5.2.2
+ * @param portNumber Port Number
+ */
+ PortIdentity(uint8_t * clock_id, uint16_t * portNumber)
+ {
+ this->portNumber = *portNumber;
+ this->portNumber = PLAT_ntohs(this->portNumber);
+ this->clock_id.set(clock_id);
+ }
+
+ /**
+ * @brief Implements the operator '!=' overloading method. Compares
+ * clock_id and portNumber.
+ * @param cmp Constant PortIdentity value to be compared against.
+ * @return TRUE if the comparison value differs from the object's
+ * PortIdentity value. FALSE otherwise.
+ */
+ bool operator!=(const PortIdentity & cmp) const
+ {
+ return
+ !(this->clock_id == cmp.clock_id) ||
+ this->portNumber != cmp.portNumber ? true : false;
+ }
+
+ /**
+ * @brief Implements the operator '==' overloading method. Compares
+ * clock_id and portNumber.
+ * @param cmp Constant PortIdentity value to be compared against.
+ * @return TRUE if the comparison value equals to the object's
+ * PortIdentity value. FALSE otherwise.
+ */
+ bool operator==(const PortIdentity & cmp)const
+ {
+ return
+ this->clock_id == cmp.clock_id &&
+ this->portNumber == cmp.portNumber ? true : false;
+ }
+
+ /**
+ * @brief Implements the operator '<' overloading method. Compares
+ * clock_id and portNumber.
+ * @param cmp Constant PortIdentity value to be compared against.
+ * @return TRUE if the comparison value is lower than the object's
+ * PortIdentity value. FALSE otherwise.
+ */
+ bool operator<(const PortIdentity & cmp)const
+ {
+ return
+ this->clock_id < cmp.clock_id ?
+ true : this->clock_id == cmp.clock_id &&
+ this->portNumber < cmp.portNumber ? true : false;
+ }
+
+ /**
+ * @brief Implements the operator '>' overloading method. Compares
+ * clock_id and portNumber.
+ * @param cmp Constant PortIdentity value to be compared against.
+ * @return TRUE if the comparison value is greater than the object's
+ * PortIdentity value. FALSE otherwise.
+ */
+ bool operator>(const PortIdentity & cmp)const
+ {
+ return
+ this->clock_id > cmp.clock_id ?
+ true : this->clock_id == cmp.clock_id &&
+ this->portNumber > cmp.portNumber ? true : false;
+ }
+
+ /**
+ * @brief Gets the ClockIdentity string
+ * @param id [out] Pointer to an array of octets.
+ * @return void
+ */
+ void getClockIdentityString(uint8_t *id)
+ {
+ clock_id.getIdentityString(id);
+ }
+
+ /**
+ * @brief Sets the ClockIdentity.
+ * @param clock_id Clock Identity to be set.
+ * @return void
+ */
+ void setClockIdentity(ClockIdentity clock_id)
+ {
+ this->clock_id = clock_id;
+ }
+
+ /**
+ * @brief Gets the clockIdentity value
+ * @return A copy of Clock identity value.
+ */
+ ClockIdentity getClockIdentity( void ) {
+ return this->clock_id;
+ }
+
+ /**
+ * @brief Gets the port number following the network byte order, i.e.
+ * Big-Endian.
+ * @param id [out] Port number
+ * @return void
+ */
+ void getPortNumberNO(uint16_t * id) // Network byte order
+ {
+ uint16_t portNumberNO = PLAT_htons(portNumber);
+ *id = portNumberNO;
+ }
+
+ /**
+ * @brief Gets the port number in the host byte order, which can be
+ * either Big-Endian
+ * or Little-Endian, depending on the processor where it is running.
+ * @param id Port number
+ * @return void
+ */
+ void getPortNumber(uint16_t * id) // Host byte order
+ {
+ *id = portNumber;
+ }
+
+ /**
+ * @brief Sets the Port number
+ * @param id [in] Port number
+ * @return void
+ */
+ void setPortNumber(uint16_t * id)
+ {
+ portNumber = *id;
+ }
+};
+
+class phy_delay_spec_t;
+typedef std::unordered_map<uint32_t, phy_delay_spec_t> phy_delay_map_t;
+
+/**
+ * @brief Structure for initializing the port class
+ */
+typedef struct {
+ /* clock IEEE1588Clock instance */
+ IEEE1588Clock * clock;
+
+ /* index Interface index */
+ uint16_t index;
+
+ /* timestamper Hardware timestamper instance */
+ CommonTimestamper * timestamper;
+
+ /* net_label Network label */
+ InterfaceLabel *net_label;
+
+ /* automotive_profile set the AVnu automotive profile */
+ bool automotive_profile;
+
+ /* Set to true if the port is the grandmaster. Used for fixed GM in
+ * the the AVnu automotive profile */
+ bool isGM;
+
+ /* Set to true if the port is the grandmaster. Used for fixed GM in
+ * the the AVnu automotive profile */
+ bool testMode;
+
+ /* Set to true if the port's network interface is up. Used to filter
+ * false LINKUP/LINKDOWN events */
+ bool linkUp;
+
+ /* gPTP 10.2.4.4 */
+ signed char initialLogSyncInterval;
+
+ /* gPTP 11.5.2.2 */
+ signed char initialLogPdelayReqInterval;
+
+ /* CDS 6.2.1.5 */
+ signed char operLogPdelayReqInterval;
+
+ /* CDS 6.2.1.6 */
+ signed char operLogSyncInterval;
+
+ /* condition_factory OSConditionFactory instance */
+ OSConditionFactory * condition_factory;
+
+ /* thread_factory OSThreadFactory instance */
+ OSThreadFactory * thread_factory;
+
+ /* timer_factory OSTimerFactory instance */
+ OSTimerFactory * timer_factory;
+
+ /* lock_factory OSLockFactory instance */
+ OSLockFactory * lock_factory;
+
+ /* phy delay */
+ phy_delay_map_t const *phy_delay;
+
+ /* sync receipt threshold */
+ unsigned int syncReceiptThreshold;
+
+ /* neighbor delay threshold */
+ int64_t neighborPropDelayThreshold;
+} PortInit_t;
+
+
+/**
+ * @brief Structure for Port Counters
+ */
+typedef struct {
+ int32_t ieee8021AsPortStatRxSyncCount;
+ int32_t ieee8021AsPortStatRxFollowUpCount;
+ int32_t ieee8021AsPortStatRxPdelayRequest;
+ int32_t ieee8021AsPortStatRxPdelayResponse;
+ int32_t ieee8021AsPortStatRxPdelayResponseFollowUp;
+ int32_t ieee8021AsPortStatRxAnnounce;
+ int32_t ieee8021AsPortStatRxPTPPacketDiscard;
+ int32_t ieee8021AsPortStatRxSyncReceiptTimeouts;
+ int32_t ieee8021AsPortStatAnnounceReceiptTimeouts;
+ int32_t ieee8021AsPortStatPdelayAllowedLostResponsesExceeded;
+ int32_t ieee8021AsPortStatTxSyncCount;
+ int32_t ieee8021AsPortStatTxFollowUpCount;
+ int32_t ieee8021AsPortStatTxPdelayRequest;
+ int32_t ieee8021AsPortStatTxPdelayResponse;
+ int32_t ieee8021AsPortStatTxPdelayResponseFollowUp;
+ int32_t ieee8021AsPortStatTxAnnounce;
+} PortCounters_t;
+
+/**
+ * @brief Port functionality common to all network media
+ */
+class CommonPort
+{
+private:
+ LinkLayerAddress local_addr;
+ PortIdentity port_identity;
+
+ /* Network socket description
+ physical interface number that object represents */
+ uint16_t ifindex;
+
+ /* Link speed in kb/sec */
+ uint32_t link_speed;
+
+ /* Signed value allows this to be negative result because of inaccurate
+ timestamp */
+ int64_t one_way_delay;
+ int64_t neighbor_prop_delay_thresh;
+
+ InterfaceLabel *net_label;
+
+ OSNetworkInterface *net_iface;
+
+ PortState port_state;
+ bool testMode;
+
+ signed char log_mean_sync_interval;
+ signed char log_mean_announce_interval;
+ signed char initialLogSyncInterval;
+
+ /*Sync threshold*/
+ unsigned int sync_receipt_thresh;
+ unsigned int wrongSeqIDCounter;
+
+ PortCounters_t counters;
+
+ OSThread *listening_thread;
+ OSThread *link_thread;
+
+ FrequencyRatio _peer_rate_offset;
+ Timestamp _peer_offset_ts_theirs;
+ Timestamp _peer_offset_ts_mine;
+ bool _peer_offset_init;
+ bool asCapable;
+ unsigned sync_count; /* 0 for master, increment for each sync
+ * received as slave */
+ unsigned pdelay_count;
+
+ PTPMessageAnnounce *qualified_announce;
+
+ uint16_t announce_sequence_id;
+ uint16_t signal_sequence_id;
+ uint16_t sync_sequence_id;
+
+ uint16_t lastGmTimeBaseIndicator;
+
+ OSLock *syncReceiptTimerLock;
+ OSLock *syncIntervalTimerLock;
+ OSLock *announceIntervalTimerLock;
+
+protected:
+ static const int64_t INVALID_LINKDELAY = 3600000000000;
+ static const int64_t ONE_WAY_DELAY_DEFAULT = INVALID_LINKDELAY;
+
+ OSThreadFactory const * const thread_factory;
+ OSTimerFactory const * const timer_factory;
+ OSLockFactory const * const lock_factory;
+ OSConditionFactory const * const condition_factory;
+ CommonTimestamper * const _hw_timestamper;
+ IEEE1588Clock * const clock;
+ const bool isGM;
+
+ phy_delay_map_t const * const phy_delay;
+
+public:
+ static const int64_t NEIGHBOR_PROP_DELAY_THRESH = 800;
+ static const unsigned int DEFAULT_SYNC_RECEIPT_THRESH = 5;
+
+ CommonPort( PortInit_t *portInit );
+ virtual ~CommonPort();
+
+ /**
+ * @brief Global media dependent port initialization
+ * @return true on success
+ */
+ bool init_port( void );
+
+ /**
+ * @brief Media specific port initialization
+ * @return true on success
+ */
+ virtual bool _init_port( void ) = 0;
+
+ /**
+ * @brief Initializes the hwtimestamper
+ */
+ void timestamper_init( void );
+
+ /**
+ * @brief Resets the hwtimestamper
+ */
+ void timestamper_reset( void );
+
+ /**
+ * @brief Gets the link delay information.
+ * @return one way delay if delay > 0, or zero otherwise.
+ */
+ uint64_t getLinkDelay( void )
+ {
+ return one_way_delay > 0LL ? one_way_delay : 0LL;
+ }
+
+ /**
+ * @brief Gets the link delay information.
+ * @param [in] delay Pointer to the delay information
+ * @return True if valid, false if invalid
+ */
+ bool getLinkDelay( uint64_t *delay )
+ {
+ if(delay == NULL) {
+ return false;
+ }
+ *delay = getLinkDelay();
+ return *delay < INVALID_LINKDELAY;
+ }
+
+ /**
+ * @brief Sets link delay information.
+ * Signed value allows this to be negative result because
+ * of inaccurate timestamps.
+ * @param delay Link delay
+ * @return True if one_way_delay is lower or equal than neighbor
+ * propagation delay threshold False otherwise
+ */
+ bool setLinkDelay( int64_t delay )
+ {
+ one_way_delay = delay;
+ int64_t abs_delay = (one_way_delay < 0 ?
+ -one_way_delay : one_way_delay);
+
+ if (testMode) {
+ GPTP_LOG_STATUS("Link delay: %d", delay);
+ }
+
+ return (abs_delay <= neighbor_prop_delay_thresh);
+ }
+
+ /**
+ * @brief Gets a pointer to IEEE1588Clock
+ * @return Pointer to clock
+ */
+ IEEE1588Clock *getClock( void )
+ {
+ return clock;
+ }
+
+ /**
+ * @brief Gets the local_addr
+ * @return LinkLayerAddress
+ */
+ LinkLayerAddress *getLocalAddr( void )
+ {
+ return &local_addr;
+ }
+
+ /**
+ * @brief Gets the testMode
+ * @return bool of the test mode value
+ */
+ bool getTestMode( void )
+ {
+ return testMode;
+ }
+
+ /**
+ * @brief Sets the testMode
+ * @param testMode changes testMode to this value
+ */
+ void setTestMode( bool testMode )
+ {
+ this->testMode = testMode;
+ }
+
+ /**
+ * @brief Serializes (i.e. copy over buf pointer) the information from
+ * the variables (in that order):
+ * - asCapable;
+ * - Port Sate;
+ * - Link Delay;
+ * - Neighbor Rate Ratio
+ * @param buf [out] Buffer where to put the results.
+ * @param count [inout] Length of buffer. It contains maximum length
+ * to be written
+ * when the function is called, and the value is decremented by the
+ * same amount the
+ * buf size increases.
+ * @return TRUE if it has successfully written to buf all the values
+ * or if buf is NULL.
+ * FALSE if count should be updated with the right size.
+ */
+ bool serializeState( void *buf, long *count );
+
+ /**
+ * @brief Restores the serialized state from the buffer. Copies the
+ * information from buffer
+ * to the variables (in that order):
+ * - asCapable;
+ * - Port State;
+ * - Link Delay;
+ * - Neighbor Rate Ratio
+ * @param buf Buffer containing the serialized state.
+ * @param count Buffer lenght. It is decremented by the same size of
+ * the variables that are
+ * being copied.
+ * @return TRUE if everything was copied successfully, FALSE otherwise.
+ */
+ bool restoreSerializedState( void *buf, long *count );
+
+ /**
+ * @brief Sets the internal variabl sync_receipt_thresh, which is the
+ * flag that monitors the amount of wrong syncs enabled before
+ * switching
+ * the ptp to master.
+ * @param th Threshold to be set
+ * @return void
+ */
+ void setSyncReceiptThresh(unsigned int th)
+ {
+ sync_receipt_thresh = th;
+ }
+
+ /**
+ * @brief Gets the internal variabl sync_receipt_thresh, which is the
+ * flag that monitors the amount of wrong syncs enabled before
+ * switching
+ * the ptp to master.
+ * @return sync_receipt_thresh value
+ */
+ unsigned int getSyncReceiptThresh( void )
+ {
+ return sync_receipt_thresh;
+ }
+
+ /**
+ * @brief Sets the wrongSeqIDCounter variable
+ * @param cnt Value to be set
+ * @return void
+ */
+ void setWrongSeqIDCounter(unsigned int cnt)
+ {
+ wrongSeqIDCounter = cnt;
+ }
+
+ /**
+ * @brief Gets the wrongSeqIDCounter value
+ * @param [out] cnt Pointer to the counter value. It must be valid
+ * @return TRUE if ok and lower than the syncReceiptThreshold value.
+ * FALSE otherwise
+ */
+ bool getWrongSeqIDCounter(unsigned int *cnt)
+ {
+ if( cnt == NULL )
+ {
+ return false;
+ }
+ *cnt = wrongSeqIDCounter;
+
+ return( *cnt < getSyncReceiptThresh() );
+ }
+
+ /**
+ * @brief Increments the wrongSeqIDCounter value
+ * @param [out] cnt Pointer to the counter value. Must be valid
+ * @return TRUE if incremented value is lower than the
+ * syncReceiptThreshold. FALSE otherwise.
+ */
+ bool incWrongSeqIDCounter(unsigned int *cnt)
+ {
+ if( getAsCapable() )
+ {
+ wrongSeqIDCounter++;
+ }
+ bool ret = wrongSeqIDCounter < getSyncReceiptThresh();
+
+ if( cnt != NULL)
+ {
+ *cnt = wrongSeqIDCounter;
+ }
+
+ return ret;
+ }
+
+ /**
+ * @brief Gets the hardware timestamper version
+ * @return HW timestamper version
+ */
+ int getTimestampVersion();
+
+ /**
+ * @brief Adjusts the clock frequency.
+ * @param freq_offset Frequency offset
+ * @return TRUE if adjusted. FALSE otherwise.
+ */
+ bool _adjustClockRate( FrequencyRatio freq_offset );
+
+ /**
+ * @brief Adjusts the clock frequency.
+ * @param freq_offset Frequency offset
+ * @return TRUE if adjusted. FALSE otherwise.
+ */
+ bool adjustClockRate( FrequencyRatio freq_offset ) {
+ return _adjustClockRate( freq_offset );
+ }
+
+ /**
+ * @brief Adjusts the clock phase.
+ * @param phase_adjust phase offset in ns
+ * @return TRUE if adjusted. FALSE otherwise.
+ */
+ bool adjustClockPhase( int64_t phase_adjust );
+
+ /**
+ * @brief Gets extended error message from hardware timestamper
+ * @param msg [out] Extended error message
+ * @return void
+ */
+ void getExtendedError(char *msg);
+
+ /**
+ * @brief Increment IEEE Port counter:
+ * ieee8021AsPortStatRxSyncCount
+ * @return void
+ */
+ void incCounter_ieee8021AsPortStatRxSyncCount( void )
+ {
+ counters.ieee8021AsPortStatRxSyncCount++;
+ }
+
+ /**
+ * @brief Increment IEEE Port counter:
+ * ieee8021AsPortStatRxFollowUpCount
+ * @return void
+ */
+ void incCounter_ieee8021AsPortStatRxFollowUpCount( void )
+ {
+ counters.ieee8021AsPortStatRxFollowUpCount++;
+ }
+
+ /**
+ * @brief Increment IEEE Port counter:
+ * ieee8021AsPortStatRxPdelayRequest
+ * @return void
+ */
+ void incCounter_ieee8021AsPortStatRxPdelayRequest( void )
+ {
+ counters.ieee8021AsPortStatRxPdelayRequest++;
+ }
+
+ /**
+ * @brief Increment IEEE Port counter:
+ * ieee8021AsPortStatRxPdelayResponse
+ * @return void
+ */
+ void incCounter_ieee8021AsPortStatRxPdelayResponse( void )
+ {
+ counters.ieee8021AsPortStatRxPdelayResponse++;
+ }
+
+ /**
+ * @brief Increment IEEE Port counter:
+ * ieee8021AsPortStatRxPdelayResponseFollowUp
+ * @return void
+ */
+ void incCounter_ieee8021AsPortStatRxPdelayResponseFollowUp( void )
+ {
+ counters.ieee8021AsPortStatRxPdelayResponseFollowUp++;
+ }
+
+ /**
+ * @brief Increment IEEE Port counter:
+ * ieee8021AsPortStatRxAnnounce
+ * @return void
+ */
+ void incCounter_ieee8021AsPortStatRxAnnounce( void )
+ {
+ counters.ieee8021AsPortStatRxAnnounce++;
+ }
+
+ /**
+ * @brief Increment IEEE Port counter:
+ * ieee8021AsPortStatRxPTPPacketDiscard
+ * @return void
+ */
+ void incCounter_ieee8021AsPortStatRxPTPPacketDiscard( void )
+ {
+ counters.ieee8021AsPortStatRxPTPPacketDiscard++;
+ }
+
+ /**
+ * @brief Increment IEEE Port counter:
+ * ieee8021AsPortStatRxSyncReceiptTimeouts
+ * @return void
+ */
+ void incCounter_ieee8021AsPortStatRxSyncReceiptTimeouts( void )
+ {
+ counters.ieee8021AsPortStatRxSyncReceiptTimeouts++;
+ }
+
+ /**
+ * @brief Increment IEEE Port counter:
+ * ieee8021AsPortStatAnnounceReceiptTimeouts
+ * @return void
+ */
+ void incCounter_ieee8021AsPortStatAnnounceReceiptTimeouts( void )
+ {
+ counters.ieee8021AsPortStatAnnounceReceiptTimeouts++;
+ }
+
+
+ /**
+ * @brief Increment IEEE Port counter:
+ * ieee8021AsPortStatPdelayAllowedLostResponsesExceeded
+ * @return void
+ */
+ // TODO: Not called
+ void incCounter_ieee8021AsPortStatPdelayAllowedLostResponsesExceeded
+ ( void )
+ {
+ counters.
+ ieee8021AsPortStatPdelayAllowedLostResponsesExceeded++;
+ }
+
+ /**
+ * @brief Increment IEEE Port counter:
+ * ieee8021AsPortStatTxSyncCount
+ * @return void
+ */
+ void incCounter_ieee8021AsPortStatTxSyncCount( void )
+ {
+ counters.ieee8021AsPortStatTxSyncCount++;
+ }
+
+ /**
+ * @brief Increment IEEE Port counter:
+ * ieee8021AsPortStatTxFollowUpCount
+ * @return void
+ */
+ void incCounter_ieee8021AsPortStatTxFollowUpCount( void )
+ {
+ counters.ieee8021AsPortStatTxFollowUpCount++;
+ }
+
+ /**
+ * @brief Increment IEEE Port counter:
+ * ieee8021AsPortStatTxPdelayRequest
+ * @return void
+ */
+ void incCounter_ieee8021AsPortStatTxPdelayRequest( void )
+ {
+ counters.ieee8021AsPortStatTxPdelayRequest++;
+ }
+
+ /**
+ * @brief Increment IEEE Port counter:
+ * ieee8021AsPortStatTxPdelayResponse
+ * @return void
+ */
+ void incCounter_ieee8021AsPortStatTxPdelayResponse( void )
+ {
+ counters.ieee8021AsPortStatTxPdelayResponse++;
+ }
+
+ /**
+ * @brief Increment IEEE Port counter:
+ * ieee8021AsPortStatTxPdelayResponseFollowUp
+ * @return void
+ */
+ void incCounter_ieee8021AsPortStatTxPdelayResponseFollowUp( void )
+ {
+ counters.ieee8021AsPortStatTxPdelayResponseFollowUp++;
+ }
+
+ /**
+ * @brief Increment IEEE Port counter:
+ * ieee8021AsPortStatTxAnnounce
+ * @return void
+ */
+ void incCounter_ieee8021AsPortStatTxAnnounce( void )
+ {
+ counters.ieee8021AsPortStatTxAnnounce++;
+ }
+
+ /**
+ * @brief Logs port counters
+ * @return void
+ */
+ void logIEEEPortCounters( void )
+ {
+ GPTP_LOG_STATUS
+ ( "IEEE Port Counter "
+ "ieee8021AsPortStatRxSyncCount : %u",
+ counters.ieee8021AsPortStatRxSyncCount );
+ GPTP_LOG_STATUS
+ ( "IEEE Port Counter "
+ "ieee8021AsPortStatRxFollowUpCount : %u",
+ counters.ieee8021AsPortStatRxFollowUpCount );
+ GPTP_LOG_STATUS
+ ( "IEEE Port Counter "
+ "ieee8021AsPortStatRxPdelayRequest : %u",
+ counters.ieee8021AsPortStatRxPdelayRequest );
+ GPTP_LOG_STATUS
+ ( "IEEE Port Counter "
+ "ieee8021AsPortStatRxPdelayResponse : %u",
+ counters.ieee8021AsPortStatRxPdelayResponse );
+ GPTP_LOG_STATUS
+ ( "IEEE Port Counter "
+ "ieee8021AsPortStatRxPdelayResponseFollowUp "
+ ": %u", counters.
+ ieee8021AsPortStatRxPdelayResponseFollowUp );
+ GPTP_LOG_STATUS
+ ( "IEEE Port Counter "
+ "ieee8021AsPortStatRxAnnounce : %u",
+ counters.ieee8021AsPortStatRxAnnounce );
+ GPTP_LOG_STATUS
+ ( "IEEE Port Counter "
+ "ieee8021AsPortStatRxPTPPacketDiscard : %u",
+ counters.
+ ieee8021AsPortStatRxPTPPacketDiscard );
+ GPTP_LOG_STATUS
+ ( "IEEE Port Counter "
+ "ieee8021AsPortStatRxSyncReceiptTimeouts "
+ ": %u", counters.
+ ieee8021AsPortStatRxSyncReceiptTimeouts );
+ GPTP_LOG_STATUS
+ ( "IEEE Port Counter "
+ "ieee8021AsPortStatAnnounceReceiptTimeouts "
+ ": %u", counters.
+ ieee8021AsPortStatAnnounceReceiptTimeouts );
+ GPTP_LOG_STATUS
+ ( "IEEE Port Counter "
+ "ieee8021AsPortStatPdelayAllowed"
+ "LostResponsesExceeded : %u", counters.
+ ieee8021AsPortStatPdelayAllowedLostResponsesExceeded
+ );
+ GPTP_LOG_STATUS
+ ( "IEEE Port Counter "
+ "ieee8021AsPortStatTxSyncCount : %u",
+ counters.ieee8021AsPortStatTxSyncCount );
+ GPTP_LOG_STATUS
+ ( "IEEE Port Counter "
+ "ieee8021AsPortStatTxFollowUpCount : %u", counters.
+ ieee8021AsPortStatTxFollowUpCount);
+ GPTP_LOG_STATUS
+ ( "IEEE Port Counter "
+ "ieee8021AsPortStatTxPdelayRequest : %u",
+ counters.ieee8021AsPortStatTxPdelayRequest);
+ GPTP_LOG_STATUS
+ ( "IEEE Port Counter "
+ "ieee8021AsPortStatTxPdelayResponse : %u", counters.
+ ieee8021AsPortStatTxPdelayResponse);
+ GPTP_LOG_STATUS
+ ( "IEEE Port Counter "
+ "ieee8021AsPortStatTxPdelayResponseFollowUp : %u",
+ counters.ieee8021AsPortStatTxPdelayResponseFollowUp
+ );
+ GPTP_LOG_STATUS
+ ( "IEEE Port Counter "
+ "ieee8021AsPortStatTxAnnounce : %u",
+ counters.ieee8021AsPortStatTxAnnounce);
+ }
+
+ /**
+ * @brief Get the cross timestamping information.
+ * The gPTP subsystem uses these samples to calculate
+ * ratios which can be used to translate or extrapolate
+ * one clock into another clock reference. The gPTP service
+ * uses these supplied cross timestamps to perform internal
+ * rate estimation and conversion functions.
+ * @param system_time [out] System time
+ * @param device_time [out] Device time
+ * @param local_clock [out] Local clock
+ * @param nominal_clock_rate [out] Nominal clock rate
+ * @return True in case of success. FALSE in case of error
+ */
+ void getDeviceTime
+ ( Timestamp &system_time, Timestamp &device_time,
+ uint32_t &local_clock, uint32_t & nominal_clock_rate );
+
+ /**
+ * @brief Sets asCapable flag
+ * @param ascap flag to be set. If FALSE, marks peer_offset_init as
+ * false.
+ * @return void
+ */
+ void setAsCapable(bool ascap)
+ {
+ if ( ascap != asCapable ) {
+ GPTP_LOG_STATUS
+ ("AsCapable: %s", ascap == true
+ ? "Enabled" : "Disabled");
+ }
+ if( !ascap )
+ {
+ _peer_offset_init = false;
+ }
+ asCapable = ascap;
+ }
+
+ /**
+ * @brief Gets the asCapable flag
+ * @return asCapable flag.
+ */
+ bool getAsCapable()
+ {
+ return( asCapable );
+ }
+
+ /**
+ * @brief Gets the Peer rate offset. Used to calculate neighbor
+ * rate ratio.
+ * @return FrequencyRatio peer rate offset
+ */
+ FrequencyRatio getPeerRateOffset( void )
+ {
+ return _peer_rate_offset;
+ }
+
+ /**
+ * @brief Sets the peer rate offset. Used to calculate neighbor rate
+ * ratio.
+ * @param offset Offset to be set
+ * @return void
+ */
+ void setPeerRateOffset( FrequencyRatio offset ) {
+ _peer_rate_offset = offset;
+ }
+
+ /**
+ * @brief Sets peer offset timestamps
+ * @param mine Local timestamps
+ * @param theirs Remote timestamps
+ * @return void
+ */
+ void setPeerOffset(Timestamp mine, Timestamp theirs) {
+ _peer_offset_ts_mine = mine;
+ _peer_offset_ts_theirs = theirs;
+ _peer_offset_init = true;
+ }
+
+ /**
+ * @brief Gets peer offset timestamps
+ * @param mine [out] Reference to local timestamps
+ * @param theirs [out] Reference to remote timestamps
+ * @return TRUE if peer offset has already been initialized. FALSE
+ * otherwise.
+ */
+ bool getPeerOffset(Timestamp & mine, Timestamp & theirs) {
+ mine = _peer_offset_ts_mine;
+ theirs = _peer_offset_ts_theirs;
+ return _peer_offset_init;
+ }
+
+ /**
+ * @brief Sets the neighbor propagation delay threshold
+ * @param delay Delay in nanoseconds
+ * @return void
+ */
+ void setNeighPropDelayThresh(int64_t delay) {
+ neighbor_prop_delay_thresh = delay;
+ }
+
+ /**
+ * @brief Restart PDelay
+ * @return void
+ */
+ void restartPDelay() {
+ _peer_offset_init = false;
+ }
+
+ /**
+ * @brief Gets a pointer to timer_factory object
+ * @return timer_factory pointer
+ */
+ const OSTimerFactory *getTimerFactory() {
+ return timer_factory;
+ }
+
+ /**
+ * @brief Watch for link up and down events.
+ * @return Its an infinite loop. Returns NULL in case of error.
+ */
+ void *watchNetLink( void )
+ {
+ // Should never return
+ net_iface->watchNetLink(this);
+
+ return NULL;
+ }
+
+ /**
+ * @brief Receive frame
+ */
+ net_result recv
+ ( LinkLayerAddress *addr, uint8_t *payload, size_t &length,
+ uint32_t &link_speed )
+ {
+ net_result result = net_iface->nrecv( addr, payload, length );
+ link_speed = this->link_speed;
+ return result;
+ }
+
+ /**
+ * @brief Send frame
+ */
+ net_result send
+ ( LinkLayerAddress *addr, uint16_t etherType, uint8_t *payload,
+ size_t length, bool timestamp )
+ {
+ return net_iface->send
+ ( addr, etherType, payload, length, timestamp );
+ }
+
+ /**
+ * @brief Get the payload offset inside a packet
+ * @return 0
+ */
+ unsigned getPayloadOffset()
+ {
+ return net_iface->getPayloadOffset();
+ }
+
+ bool linkWatch( OSThreadFunction func, OSThreadFunctionArg arg )
+ {
+ return link_thread->start( func, arg );
+ }
+
+ bool linkOpen( OSThreadFunction func, OSThreadFunctionArg arg )
+ {
+ return listening_thread->start( func, arg );
+ }
+
+ /**
+ * @brief Gets the portState information
+ * @return PortState
+ */
+ PortState getPortState( void ) {
+ return port_state;
+ }
+
+ /**
+ * @brief Sets the PortState
+ * @param state value to be set
+ * @return void
+ */
+ void setPortState( PortState state ) {
+ port_state = state;
+ }
+
+ /**
+ * @brief Gets port identity
+ * @param identity [out] Reference to PortIdentity
+ * @return void
+ */
+ void getPortIdentity(PortIdentity & identity) {
+ identity = this->port_identity;
+ }
+
+ /**
+ * @brief Gets the "best" announce
+ * @return Pointer to PTPMessageAnnounce
+ */
+ PTPMessageAnnounce *calculateERBest( void );
+
+ /**
+ * @brief Changes the port state
+ * @param state Current state
+ * @param changed_external_master TRUE if external master has
+ * changed, FALSE otherwise
+ * @return void
+ */
+ void recommendState(PortState state, bool changed_external_master);
+
+ /**
+ * @brief Locks the TX port
+ * @return TRUE if success. FALSE otherwise.
+ */
+ virtual bool getTxLock()
+ {
+ return true;
+ }
+
+ /**
+ * @brief Unlocks the port TX.
+ * @return TRUE if success. FALSE otherwise.
+ */
+ virtual bool putTxLock()
+ {
+ return false;
+ }
+
+ /**
+ * @brief Adds a new qualified announce the port. IEEE 802.1AS
+ * Clause 10.3.10.2
+ * @param annc PTP announce message
+ * @return void
+ */
+ void setQualifiedAnnounce( PTPMessageAnnounce *annc )
+ {
+ delete qualified_announce;
+ qualified_announce = annc;
+ }
+
+ /**
+ * @brief Switches port to a gPTP master
+ * @param annc If TRUE, starts announce event timer.
+ * @return void
+ */
+ virtual void becomeMaster( bool annc ) = 0;
+
+ /**
+ * @brief Switches port to a gPTP slave.
+ * @param restart_syntonization if TRUE, restarts the syntonization
+ * @return void
+ */
+ virtual void becomeSlave( bool restart_syntonization ) = 0;
+
+ /**
+ * @brief Sets current sync count value.
+ * @param cnt [in] sync count value
+ * @return void
+ */
+ void setSyncCount(unsigned int cnt)
+ {
+ sync_count = cnt;
+ }
+
+ /**
+ * @brief Increments sync count
+ * @return void
+ */
+ void incSyncCount() {
+ ++sync_count;
+ }
+
+ /**
+ * @brief Gets current sync count value. It is set to zero
+ * when master and incremented at each sync received for slave.
+ * @return sync count
+ */
+ unsigned getSyncCount()
+ {
+ return sync_count;
+ }
+
+ /**
+ * @brief Sets current pdelay count value.
+ * @param cnt [in] pdelay count value
+ * @return void
+ */
+ void setPdelayCount(unsigned int cnt) {
+ pdelay_count = cnt;
+ }
+
+ /**
+ * @brief Increments Pdelay count
+ * @return void
+ */
+ void incPdelayCount()
+ {
+ ++pdelay_count;
+ }
+
+ /**
+ * @brief Gets current pdelay count value. It is set to zero
+ * when asCapable is false.
+ * @return pdelay count
+ */
+ unsigned getPdelayCount()
+ {
+ return pdelay_count;
+ }
+
+ /**
+ * @brief Increments announce sequence id and returns
+ * @return Next announce sequence id.
+ */
+ uint16_t getNextAnnounceSequenceId( void )
+ {
+ return announce_sequence_id++;
+ }
+
+ /**
+ * @brief Increments signal sequence id and returns
+ * @return Next signal sequence id.
+ */
+ uint16_t getNextSignalSequenceId( void )
+ {
+ return signal_sequence_id++;
+ }
+
+ /**
+ * @brief Increments sync sequence ID and returns
+ * @return Next synce sequence id.
+ */
+ uint16_t getNextSyncSequenceId( void )
+ {
+ return sync_sequence_id++;
+ }
+
+ /**
+ * @brief Gets the lastGmTimeBaseIndicator
+ * @return uint16 of the lastGmTimeBaseIndicator
+ */
+ uint16_t getLastGmTimeBaseIndicator( void ) {
+ return lastGmTimeBaseIndicator;
+ }
+
+ /**
+ * @brief Sets the lastGmTimeBaseIndicator
+ * @param gmTimeBaseIndicator from last Follow up message
+ * @return void
+ */
+ void setLastGmTimeBaseIndicator(uint16_t gmTimeBaseIndicator)
+ {
+ lastGmTimeBaseIndicator = gmTimeBaseIndicator;
+ }
+
+ /**
+ * @brief Gets the sync interval value
+ * @return Sync Interval
+ */
+ signed char getSyncInterval( void )
+ {
+ return log_mean_sync_interval;
+ }
+
+ /**
+ * @brief Sets the sync interval value
+ * @param val time interval
+ * @return none
+ */
+ void setSyncInterval( signed char val )
+ {
+ log_mean_sync_interval = val;
+ }
+
+ /**
+ * @brief Sets the sync interval back to initial value
+ * @return none
+ */
+ void resetInitSyncInterval( void )
+ {
+ log_mean_sync_interval = initialLogSyncInterval;;
+ }
+
+ /**
+ * @brief Sets the sync interval
+ * @return none
+ */
+ void setInitSyncInterval( signed char interval )
+ {
+ initialLogSyncInterval = interval;
+ }
+
+ /**
+ * @brief Gets the sync interval
+ * @return sync interval
+ */
+ signed char getInitSyncInterval( void )
+ {
+ return initialLogSyncInterval;
+ }
+
+ /**
+ * @brief Gets the announce interval
+ * @return Announce interval
+ */
+ signed char getAnnounceInterval( void ) {
+ return log_mean_announce_interval;
+ }
+
+ /**
+ * @brief Sets the announce interval
+ * @param val time interval
+ * @return none
+ */
+ void setAnnounceInterval(signed char val) {
+ log_mean_announce_interval = val;
+ }
+ /**
+ * @brief Start sync receipt timer
+ * @param waitTime time interval
+ * @return none
+ */
+ void startSyncReceiptTimer(long long unsigned int waitTime);
+
+ /**
+ * @brief Stop sync receipt timer
+ * @return none
+ */
+ void stopSyncReceiptTimer( void );
+
+ /**
+ * @brief Start sync interval timer
+ * @param waitTime time interval in nanoseconds
+ * @return none
+ */
+ void startSyncIntervalTimer(long long unsigned int waitTime);
+
+ /**
+ * @brief Start announce interval timer
+ * @param waitTime time interval
+ * @return none
+ */
+ void startAnnounceIntervalTimer(long long unsigned int waitTime);
+
+ /**
+ * @brief Starts announce event timer
+ * @return void
+ */
+ void startAnnounce();
+
+ /**
+ * @brief Process default state change event
+ * @return true if event is handled without errors
+ */
+ bool processStateChange( Event e );
+
+ /**
+ * @brief Default sync/announce timeout handler
+ * @return true if event is handled without errors
+ */
+ bool processSyncAnnounceTimeout( Event e );
+
+
+ /**
+ * @brief Perform default event action, can be overridden by media
+ * specific actions in _processEvent
+ * @return true if event is handled without errors
+ */
+ bool processEvent( Event e );
+
+ /**
+ * @brief Perform media specific event handling action
+ * @return true if event is handled without errors
+ */
+ virtual bool _processEvent( Event e ) = 0;
+
+ virtual void syncDone() = 0;
+
+ /**
+ * @brief Sends a general message to a port. No timestamps
+ * @param buf [in] Pointer to the data buffer
+ * @param len Size of the message
+ * @param mcast_type Enumeration
+ * MulticastType (pdelay, none or other). Depracated.
+ * @param destIdentity Destination port identity
+ * @return void
+ */
+ virtual void sendGeneralPort
+ (uint16_t etherType, uint8_t * buf, int len, MulticastType mcast_type,
+ PortIdentity * destIdentity) = 0;
+
+ /**
+ * @brief Sets link speed
+ */
+ void setLinkSpeed( uint32_t link_speed )
+ {
+ this->link_speed = link_speed;
+ }
+
+ /**
+ * @brief Returns link speed
+ */
+ uint32_t getLinkSpeed( void )
+ {
+ return link_speed;
+ }
+
+ /**
+ * @brief Returns TX PHY delay
+ */
+ Timestamp getTxPhyDelay( uint32_t link_speed ) const;
+
+ /**
+ * @brief Returns RX PHY delay
+ */
+ Timestamp getRxPhyDelay( uint32_t link_speed ) const;
+};
+
+/**
+ * @brief Specifies a RX/TX PHY compensation pair
+ */
+class phy_delay_spec_t
+{
+private:
+ uint16_t tx_delay;
+ uint16_t rx_delay;
+public:
+ /**
+ * Constructor setting PHY compensation
+ */
+ phy_delay_spec_t(
+ uint16_t tx_delay,
+ uint16_t rx_delay )
+ {
+ this->tx_delay = tx_delay;
+ this->rx_delay = rx_delay;
+ }
+
+ /**
+ * Default constructor sets 0 PHY compensation
+ */
+ phy_delay_spec_t()
+ {
+ phy_delay_spec_t( 0, 0 );
+ }
+
+ /**
+ * @brief sets PHY compensation
+ */
+ void set_delay(
+ uint16_t tx_delay,
+ uint16_t rx_delay )
+ {
+ this->tx_delay = tx_delay;
+ this->rx_delay = rx_delay;
+ }
+
+ /**
+ * @brief sets RX PHY compensation
+ */
+ void set_tx_delay(
+ uint16_t tx_delay )
+ {
+ this->tx_delay = tx_delay;
+ }
+
+ /**
+ * @brief sets TX PHY compensation
+ */
+ void set_rx_delay(
+ uint16_t rx_delay )
+ {
+ this->rx_delay = rx_delay;
+ }
+
+ /**
+ * @brief gets TX PHY compensation
+ */
+ uint16_t get_tx_delay() const
+ {
+ return tx_delay;
+ }
+
+ /**
+ * @brief gets RX PHY compensation
+ */
+ uint16_t get_rx_delay() const
+ {
+ return rx_delay;
+ }
+};
+
+#endif/*COMMON_PORT_HPP*/
diff --git a/daemons/gptp/common/common_tstamper.hpp b/daemons/gptp/common/common_tstamper.hpp
new file mode 100644
index 00000000..cfaf3abd
--- /dev/null
+++ b/daemons/gptp/common/common_tstamper.hpp
@@ -0,0 +1,153 @@
+/******************************************************************************
+
+ Copyright (c) 2009-2012, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+******************************************************************************/
+
+#ifndef COMMON_TSTAMPER_HPP
+#define COMMON_TSTAMPER_HPP
+
+#include <unordered_map>
+#include <stdint.h>
+#include <avbts_message.hpp>
+
+#define HWTIMESTAMPER_EXTENDED_MESSAGE_SIZE 4096 /*!< Maximum size of HWTimestamper extended message */
+
+/**
+ * @brief Provides a generic interface for hardware timestamping
+ */
+class CommonTimestamper {
+protected:
+ uint8_t version; //!< HWTimestamper version
+
+public:
+ /**
+ * @brief Initializes the hardware timestamp unit
+ * @param iface_label [in] Interface label
+ * @param iface [in] Network interface
+ * @return true
+ */
+ virtual bool HWTimestamper_init
+ ( InterfaceLabel *iface_label, OSNetworkInterface *iface )
+ { return true; }
+
+ /**
+ * @brief Reset the hardware timestamp unit
+ * @return void
+ */
+ virtual void HWTimestamper_reset(void) {
+ }
+
+ /**
+ * @brief This method is called before the object is de-allocated.
+ * @return void
+ */
+ virtual void HWTimestamper_final(void) {
+ }
+
+ /**
+ * @brief Adjusts the hardware clock frequency
+ * @param frequency_offset Frequency offset
+ * @return false
+ */
+ virtual bool HWTimestamper_adjclockrate
+ ( float frequency_offset ) const
+ { return false; }
+
+ /**
+ * @brief Adjusts the hardware clock phase
+ * @param phase_adjust Phase offset
+ * @return false
+ */
+ virtual bool HWTimestamper_adjclockphase( int64_t phase_adjust )
+ { return false; }
+
+ /**
+ * @brief Get the cross timestamping information.
+ * The gPTP subsystem uses these samples to calculate
+ * ratios which can be used to translate or extrapolate
+ * one clock into another clock reference. The gPTP service
+ * uses these supplied cross timestamps to perform internal
+ * rate estimation and conversion functions.
+ * @param system_time [out] System time
+ * @param device_time [out] Device time
+ * @param local_clock [out] Local clock
+ * @param nominal_clock_rate [out] Nominal clock rate
+ * @return True in case of success. FALSE in case of error
+ */
+ virtual bool HWTimestamper_gettime(Timestamp * system_time,
+ Timestamp * device_time,
+ uint32_t * local_clock,
+ uint32_t * nominal_clock_rate) const = 0;
+
+ /**
+ * @brief Gets a string with the error from the hardware timestamp block
+ * @param msg [out] String error
+ * @return void
+ * @todo There is no current implementation for this method.
+ */
+ virtual void HWTimestamper_get_extderror(char *msg) const
+ {
+ *msg = '\0';
+ }
+
+ /**
+ * @brief Starts the PPS (pulse per second) interface
+ * @return false
+ */
+ virtual bool HWTimestamper_PPS_start() { return false; };
+
+ /**
+ * @brief Stops the PPS (pulse per second) interface
+ * @return true
+ */
+ virtual bool HWTimestamper_PPS_stop() { return true; };
+
+ /**
+ * @brief Gets the HWTimestamper version
+ * @return version (signed integer)
+ */
+ int getVersion() const
+ {
+ return version;
+ }
+
+ /**
+ * @brief Default constructor. Sets version to zero.
+ */
+ CommonTimestamper() { version = 0; }
+
+ /**
+ * @brief Deletes HWtimestamper object
+ */
+ virtual ~CommonTimestamper() { }
+};
+
+#endif/*COMMON_TSTAMPER_HPP*/
diff --git a/daemons/gptp/common/ether_port.cpp b/daemons/gptp/common/ether_port.cpp
new file mode 100644
index 00000000..2325fb99
--- /dev/null
+++ b/daemons/gptp/common/ether_port.cpp
@@ -0,0 +1,864 @@
+/******************************************************************************
+
+ Copyright (c) 2009-2012, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+******************************************************************************/
+
+#include <ieee1588.hpp>
+
+#include <ether_port.hpp>
+#include <avbts_message.hpp>
+#include <avbts_clock.hpp>
+
+#include <avbts_oslock.hpp>
+#include <avbts_osnet.hpp>
+#include <avbts_oscondition.hpp>
+#include <ether_tstamper.hpp>
+
+#include <gptp_log.hpp>
+
+#include <stdio.h>
+
+#include <math.h>
+
+#include <stdlib.h>
+
+LinkLayerAddress EtherPort::other_multicast(OTHER_MULTICAST);
+LinkLayerAddress EtherPort::pdelay_multicast(PDELAY_MULTICAST);
+LinkLayerAddress EtherPort::test_status_multicast
+( TEST_STATUS_MULTICAST );
+
+OSThreadExitCode watchNetLinkWrapper(void *arg)
+{
+ EtherPort *port;
+
+ port = (EtherPort *) arg;
+ if (port->watchNetLink() == NULL)
+ return osthread_ok;
+ else
+ return osthread_error;
+}
+
+OSThreadExitCode openPortWrapper(void *arg)
+{
+ EtherPort *port;
+
+ port = (EtherPort *) arg;
+ if (port->openPort(port) == NULL)
+ return osthread_ok;
+ else
+ return osthread_error;
+}
+
+EtherPort::~EtherPort()
+{
+ delete port_ready_condition;
+}
+
+EtherPort::EtherPort( PortInit_t *portInit ) :
+ CommonPort( portInit )
+{
+ automotive_profile = portInit->automotive_profile;
+ linkUp = portInit->linkUp;
+ setTestMode( portInit->testMode );
+
+ pdelay_sequence_id = 0;
+
+ pdelay_started = false;
+ pdelay_halted = false;
+ sync_rate_interval_timer_started = false;
+
+ duplicate_resp_counter = 0;
+ last_invalid_seqid = 0;
+
+ initialLogPdelayReqInterval = portInit->initialLogPdelayReqInterval;
+ operLogPdelayReqInterval = portInit->operLogPdelayReqInterval;
+ operLogSyncInterval = portInit->operLogSyncInterval;
+
+ if (automotive_profile) {
+ setAsCapable( true );
+
+ if (getInitSyncInterval() == LOG2_INTERVAL_INVALID)
+ setInitSyncInterval( -5 ); // 31.25 ms
+ if (initialLogPdelayReqInterval == LOG2_INTERVAL_INVALID)
+ initialLogPdelayReqInterval = 0; // 1 second
+ if (operLogPdelayReqInterval == LOG2_INTERVAL_INVALID)
+ operLogPdelayReqInterval = 0; // 1 second
+ if (operLogSyncInterval == LOG2_INTERVAL_INVALID)
+ operLogSyncInterval = 0; // 1 second
+ }
+ else {
+ setAsCapable( false );
+
+ if ( getInitSyncInterval() == LOG2_INTERVAL_INVALID )
+ setInitSyncInterval( -3 ); // 125 ms
+ if (initialLogPdelayReqInterval == LOG2_INTERVAL_INVALID)
+ initialLogPdelayReqInterval = 0; // 1 second
+ if (operLogPdelayReqInterval == LOG2_INTERVAL_INVALID)
+ operLogPdelayReqInterval = 0; // 1 second
+ if (operLogSyncInterval == LOG2_INTERVAL_INVALID)
+ operLogSyncInterval = 0; // 1 second
+ }
+
+ /*TODO: Add intervals below to a config interface*/
+ log_min_mean_pdelay_req_interval = initialLogPdelayReqInterval;
+
+ last_sync = NULL;
+ last_pdelay_req = NULL;
+ last_pdelay_resp = NULL;
+ last_pdelay_resp_fwup = NULL;
+
+ setPdelayCount(0);
+ setSyncCount(0);
+
+ if (automotive_profile) {
+ if (isGM) {
+ avbSyncState = 1;
+ }
+ else {
+ avbSyncState = 2;
+ }
+ if (getTestMode())
+ {
+ linkUpCount = 1; // TODO : really should check the current linkup status http://stackoverflow.com/questions/15723061/how-to-check-if-interface-is-up
+ linkDownCount = 0;
+ }
+ setStationState(STATION_STATE_RESERVED);
+ }
+}
+
+bool EtherPort::_init_port( void )
+{
+ pdelay_rx_lock = lock_factory->createLock(oslock_recursive);
+ port_tx_lock = lock_factory->createLock(oslock_recursive);
+
+ pDelayIntervalTimerLock = lock_factory->createLock(oslock_recursive);
+
+ port_ready_condition = condition_factory->createCondition();
+
+ return true;
+}
+
+void EtherPort::startPDelay()
+{
+ if(!pdelayHalted()) {
+ if (automotive_profile) {
+ if (log_min_mean_pdelay_req_interval != PTPMessageSignalling::sigMsgInterval_NoSend) {
+ long long unsigned int waitTime;
+ waitTime = ((long long) (pow((double)2, log_min_mean_pdelay_req_interval) * 1000000000.0));
+ waitTime = waitTime > EVENT_TIMER_GRANULARITY ? waitTime : EVENT_TIMER_GRANULARITY;
+ pdelay_started = true;
+ startPDelayIntervalTimer(waitTime);
+ }
+ }
+ else {
+ pdelay_started = true;
+ startPDelayIntervalTimer(32000000);
+ }
+ }
+}
+
+void EtherPort::stopPDelay()
+{
+ haltPdelay(true);
+ pdelay_started = false;
+ clock->deleteEventTimerLocked( this, PDELAY_INTERVAL_TIMEOUT_EXPIRES);
+}
+
+void EtherPort::startSyncRateIntervalTimer()
+{
+ if (automotive_profile) {
+ sync_rate_interval_timer_started = true;
+ if (isGM) {
+ // GM will wait up to 8 seconds for signaling rate
+ // TODO: This isn't according to spec but set because it is believed that some slave devices aren't signalling
+ // to reduce the rate
+ clock->addEventTimerLocked( this, SYNC_RATE_INTERVAL_TIMEOUT_EXPIRED, 8000000000 );
+ }
+ else {
+ // Slave will time out after 4 seconds
+ clock->addEventTimerLocked( this, SYNC_RATE_INTERVAL_TIMEOUT_EXPIRED, 4000000000 );
+ }
+ }
+}
+
+void EtherPort::processMessage
+( char *buf, int length, LinkLayerAddress *remote, uint32_t link_speed )
+{
+ GPTP_LOG_VERBOSE("Processing network buffer");
+
+ PTPMessageCommon *msg =
+ buildPTPMessage( buf, (int)length, remote, this );
+
+ if (msg == NULL)
+ {
+ GPTP_LOG_ERROR("Discarding invalid message");
+ return;
+ }
+ GPTP_LOG_VERBOSE("Processing message");
+
+ if( msg->isEvent() )
+ {
+ Timestamp rx_timestamp = msg->getTimestamp();
+ Timestamp phy_compensation = getRxPhyDelay( link_speed );
+ GPTP_LOG_DEBUG( "RX PHY compensation: %s sec",
+ phy_compensation.toString().c_str() );
+ phy_compensation._version = rx_timestamp._version;
+ rx_timestamp = rx_timestamp - phy_compensation;
+ msg->setTimestamp( rx_timestamp );
+ }
+
+ msg->processMessage(this);
+ if (msg->garbage())
+ delete msg;
+}
+
+void *EtherPort::openPort( EtherPort *port )
+{
+ port_ready_condition->signal();
+
+ while (1) {
+ uint8_t buf[128];
+ LinkLayerAddress remote;
+ net_result rrecv;
+ size_t length = sizeof(buf);
+ uint32_t link_speed;
+
+ if ( ( rrecv = recv( &remote, buf, length, link_speed ))
+ == net_succeed )
+ {
+ processMessage
+ ((char *)buf, (int)length, &remote, link_speed );
+ } else if (rrecv == net_fatal) {
+ GPTP_LOG_ERROR("read from network interface failed");
+ this->processEvent(FAULT_DETECTED);
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+net_result EtherPort::port_send
+( uint16_t etherType, uint8_t *buf, int size, MulticastType mcast_type,
+ PortIdentity *destIdentity, bool timestamp )
+{
+ LinkLayerAddress dest;
+
+ if (mcast_type != MCAST_NONE) {
+ if (mcast_type == MCAST_PDELAY) {
+ dest = pdelay_multicast;
+ }
+ else if (mcast_type == MCAST_TEST_STATUS) {
+ dest = test_status_multicast;
+ }
+ else {
+ dest = other_multicast;
+ }
+ } else {
+ mapSocketAddr(destIdentity, &dest);
+ }
+
+ return send(&dest, etherType, (uint8_t *) buf, size, timestamp);
+}
+
+void EtherPort::sendEventPort
+( uint16_t etherType, uint8_t *buf, int size, MulticastType mcast_type,
+ PortIdentity *destIdentity, uint32_t *link_speed )
+{
+ net_result rtx = port_send
+ ( etherType, buf, size, mcast_type, destIdentity, true );
+ if( rtx != net_succeed )
+ {
+ GPTP_LOG_ERROR("sendEventPort(): failure");
+ return;
+ }
+
+ *link_speed = this->getLinkSpeed();
+
+ return;
+}
+
+void EtherPort::sendGeneralPort
+( uint16_t etherType, uint8_t *buf, int size, MulticastType mcast_type,
+ PortIdentity * destIdentity )
+{
+ net_result rtx = port_send(etherType, buf, size, mcast_type, destIdentity, false);
+ if (rtx != net_succeed) {
+ GPTP_LOG_ERROR("sendGeneralPort(): failure");
+ }
+
+ return;
+}
+
+bool EtherPort::_processEvent( Event e )
+{
+ bool ret;
+
+ switch (e) {
+ case POWERUP:
+ case INITIALIZE:
+ if (!automotive_profile) {
+ if ( getPortState() != PTP_SLAVE &&
+ getPortState() != PTP_MASTER )
+ {
+ GPTP_LOG_STATUS("Starting PDelay");
+ startPDelay();
+ }
+ }
+ else {
+ startPDelay();
+ }
+
+ port_ready_condition->wait_prelock();
+
+ if( !linkWatch(watchNetLinkWrapper, (void *)this) )
+ {
+ GPTP_LOG_ERROR("Error creating port link thread");
+ ret = false;
+ break;
+ }
+
+ if( !linkOpen(openPortWrapper, (void *)this) )
+ {
+ GPTP_LOG_ERROR("Error creating port thread");
+ ret = false;
+ break;
+ }
+
+ port_ready_condition->wait();
+
+ if (automotive_profile) {
+ setStationState(STATION_STATE_ETHERNET_READY);
+ if (getTestMode())
+ {
+ APMessageTestStatus *testStatusMsg = new APMessageTestStatus(this);
+ if (testStatusMsg) {
+ testStatusMsg->sendPort(this);
+ delete testStatusMsg;
+ }
+ }
+ if (!isGM) {
+ // Send an initial signalling message
+ PTPMessageSignalling *sigMsg = new PTPMessageSignalling(this);
+ if (sigMsg) {
+ sigMsg->setintervals(PTPMessageSignalling::sigMsgInterval_NoSend, getSyncInterval(), PTPMessageSignalling::sigMsgInterval_NoSend);
+ sigMsg->sendPort(this, NULL);
+ delete sigMsg;
+ }
+
+ startSyncReceiptTimer((unsigned long long)
+ (SYNC_RECEIPT_TIMEOUT_MULTIPLIER *
+ ((double) pow((double)2, getSyncInterval()) *
+ 1000000000.0)));
+ }
+ }
+
+ ret = true;
+ break;
+ case STATE_CHANGE_EVENT:
+ // If the automotive profile is enabled, handle the event by
+ // doing nothing and returning true, preventing the default
+ // action from executing
+ if( automotive_profile )
+ ret = true;
+ else
+ ret = false;
+
+ break;
+ case LINKUP:
+ haltPdelay(false);
+ startPDelay();
+ if (automotive_profile) {
+ GPTP_LOG_EXCEPTION("LINKUP");
+ }
+ else {
+ GPTP_LOG_STATUS("LINKUP");
+ }
+
+ if( clock->getPriority1() == 255 || getPortState() == PTP_SLAVE ) {
+ becomeSlave( true );
+ } else if( getPortState() == PTP_MASTER ) {
+ becomeMaster( true );
+ } else {
+ clock->addEventTimerLocked(this, ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES,
+ ANNOUNCE_RECEIPT_TIMEOUT_MULTIPLIER * pow(2.0, getAnnounceInterval()) * 1000000000.0);
+ }
+
+ if (automotive_profile) {
+ setAsCapable( true );
+
+ setStationState(STATION_STATE_ETHERNET_READY);
+ if (getTestMode())
+ {
+ APMessageTestStatus *testStatusMsg = new APMessageTestStatus(this);
+ if (testStatusMsg) {
+ testStatusMsg->sendPort(this);
+ delete testStatusMsg;
+ }
+ }
+
+ resetInitSyncInterval();
+ setAnnounceInterval( 0 );
+ log_min_mean_pdelay_req_interval = initialLogPdelayReqInterval;
+
+ if (!isGM) {
+ // Send an initial signaling message
+ PTPMessageSignalling *sigMsg = new PTPMessageSignalling(this);
+ if (sigMsg) {
+ sigMsg->setintervals(PTPMessageSignalling::sigMsgInterval_NoSend, getSyncInterval(), PTPMessageSignalling::sigMsgInterval_NoSend);
+ sigMsg->sendPort(this, NULL);
+ delete sigMsg;
+ }
+
+ startSyncReceiptTimer((unsigned long long)
+ (SYNC_RECEIPT_TIMEOUT_MULTIPLIER *
+ ((double) pow((double)2, getSyncInterval()) *
+ 1000000000.0)));
+ }
+
+ // Reset Sync count and pdelay count
+ setPdelayCount(0);
+ setSyncCount(0);
+
+ // Start AVB SYNC at 2. It will decrement after each sync. When it reaches 0 the Test Status message
+ // can be sent
+ if (isGM) {
+ avbSyncState = 1;
+ }
+ else {
+ avbSyncState = 2;
+ }
+
+ if (getTestMode())
+ {
+ linkUpCount++;
+ }
+ }
+ this->timestamper_reset();
+
+ ret = true;
+ break;
+ case LINKDOWN:
+ stopPDelay();
+ if (automotive_profile) {
+ GPTP_LOG_EXCEPTION("LINK DOWN");
+ }
+ else {
+ setAsCapable(false);
+ GPTP_LOG_STATUS("LINK DOWN");
+ }
+ if (getTestMode())
+ {
+ linkDownCount++;
+ }
+
+ ret = true;
+ break;
+ case ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES:
+ case SYNC_RECEIPT_TIMEOUT_EXPIRES:
+ if( !automotive_profile )
+ {
+ ret = false;
+ break;
+ }
+
+ // Automotive Profile specific action
+ if (e == SYNC_RECEIPT_TIMEOUT_EXPIRES) {
+ GPTP_LOG_EXCEPTION("SYNC receipt timeout");
+
+ startSyncReceiptTimer((unsigned long long)
+ (SYNC_RECEIPT_TIMEOUT_MULTIPLIER *
+ ((double) pow((double)2, getSyncInterval()) *
+ 1000000000.0)));
+ }
+ ret = true;
+ break;
+ case PDELAY_INTERVAL_TIMEOUT_EXPIRES:
+ GPTP_LOG_DEBUG("PDELAY_INTERVAL_TIMEOUT_EXPIRES occured");
+ {
+ Timestamp req_timestamp;
+
+ PTPMessagePathDelayReq *pdelay_req =
+ new PTPMessagePathDelayReq(this);
+ PortIdentity dest_id;
+ getPortIdentity(dest_id);
+ pdelay_req->setPortIdentity(&dest_id);
+
+ {
+ Timestamp pending =
+ PDELAY_PENDING_TIMESTAMP;
+ pdelay_req->setTimestamp(pending);
+ }
+
+ if (last_pdelay_req != NULL) {
+ delete last_pdelay_req;
+ }
+ setLastPDelayReq(pdelay_req);
+
+ getTxLock();
+ pdelay_req->sendPort(this, NULL);
+ GPTP_LOG_DEBUG("*** Sent PDelay Request message");
+ putTxLock();
+
+ {
+ long long timeout;
+ long long interval;
+
+ timeout = PDELAY_RESP_RECEIPT_TIMEOUT_MULTIPLIER *
+ ((long long)
+ (pow((double)2,getPDelayInterval())*1000000000.0));
+
+ timeout = timeout > EVENT_TIMER_GRANULARITY ?
+ timeout : EVENT_TIMER_GRANULARITY;
+ clock->addEventTimerLocked
+ (this, PDELAY_RESP_RECEIPT_TIMEOUT_EXPIRES, timeout );
+ GPTP_LOG_DEBUG("Schedule PDELAY_RESP_RECEIPT_TIMEOUT_EXPIRES, "
+ "PDelay interval %d, timeout %lld",
+ getPDelayInterval(), timeout);
+
+ interval =
+ ((long long)
+ (pow((double)2,getPDelayInterval())*1000000000.0));
+ interval = interval > EVENT_TIMER_GRANULARITY ?
+ interval : EVENT_TIMER_GRANULARITY;
+ startPDelayIntervalTimer(interval);
+ }
+ }
+ break;
+ case SYNC_INTERVAL_TIMEOUT_EXPIRES:
+ {
+ /* Set offset from master to zero, update device vs
+ system time offset */
+
+ // Send a sync message and then a followup to broadcast
+ PTPMessageSync *sync = new PTPMessageSync(this);
+ PortIdentity dest_id;
+ bool tx_succeed;
+ getPortIdentity(dest_id);
+ sync->setPortIdentity(&dest_id);
+ getTxLock();
+ tx_succeed = sync->sendPort(this, NULL);
+ GPTP_LOG_DEBUG("Sent SYNC message");
+
+ if ( automotive_profile &&
+ getPortState() == PTP_MASTER )
+ {
+ if (avbSyncState > 0) {
+ avbSyncState--;
+ if (avbSyncState == 0) {
+ // Send Avnu Automotive Profile status message
+ setStationState(STATION_STATE_AVB_SYNC);
+ if (getTestMode()) {
+ APMessageTestStatus *testStatusMsg = new APMessageTestStatus(this);
+ if (testStatusMsg) {
+ testStatusMsg->sendPort(this);
+ delete testStatusMsg;
+ }
+ }
+ }
+ }
+ }
+ putTxLock();
+
+ if ( tx_succeed )
+ {
+ Timestamp sync_timestamp = sync->getTimestamp();
+
+ GPTP_LOG_VERBOSE("Successful Sync timestamp");
+ GPTP_LOG_VERBOSE("Seconds: %u",
+ sync_timestamp.seconds_ls);
+ GPTP_LOG_VERBOSE("Nanoseconds: %u",
+ sync_timestamp.nanoseconds);
+
+ PTPMessageFollowUp *follow_up = new PTPMessageFollowUp(this);
+ PortIdentity dest_id;
+ getPortIdentity(dest_id);
+
+ follow_up->setClockSourceTime(getClock()->getFUPInfo());
+ follow_up->setPortIdentity(&dest_id);
+ follow_up->setSequenceId(sync->getSequenceId());
+ follow_up->setPreciseOriginTimestamp
+ (sync_timestamp);
+ follow_up->sendPort(this, NULL);
+ delete follow_up;
+ } else {
+ GPTP_LOG_ERROR
+ ("*** Unsuccessful Sync timestamp");
+ }
+ delete sync;
+ }
+ break;
+ case FAULT_DETECTED:
+ GPTP_LOG_ERROR("Received FAULT_DETECTED event");
+ if (!automotive_profile) {
+ setAsCapable(false);
+ }
+ break;
+ case PDELAY_DEFERRED_PROCESSING:
+ GPTP_LOG_DEBUG("PDELAY_DEFERRED_PROCESSING occured");
+ pdelay_rx_lock->lock();
+ if (last_pdelay_resp_fwup == NULL) {
+ GPTP_LOG_ERROR("PDelay Response Followup is NULL!");
+ abort();
+ }
+ last_pdelay_resp_fwup->processMessage(this);
+ if (last_pdelay_resp_fwup->garbage()) {
+ delete last_pdelay_resp_fwup;
+ this->setLastPDelayRespFollowUp(NULL);
+ }
+ pdelay_rx_lock->unlock();
+ break;
+ case PDELAY_RESP_RECEIPT_TIMEOUT_EXPIRES:
+ if (!automotive_profile) {
+ GPTP_LOG_EXCEPTION("PDelay Response Receipt Timeout");
+ setAsCapable(false);
+ }
+ setPdelayCount( 0 );
+ break;
+
+ case PDELAY_RESP_PEER_MISBEHAVING_TIMEOUT_EXPIRES:
+ GPTP_LOG_EXCEPTION("PDelay Resp Peer Misbehaving timeout expired! Restarting PDelay");
+
+ haltPdelay(false);
+ if( getPortState() != PTP_SLAVE &&
+ getPortState() != PTP_MASTER )
+ {
+ GPTP_LOG_STATUS("Starting PDelay" );
+ startPDelay();
+ }
+ break;
+ case SYNC_RATE_INTERVAL_TIMEOUT_EXPIRED:
+ {
+ GPTP_LOG_INFO("SYNC_RATE_INTERVAL_TIMEOUT_EXPIRED occured");
+
+ sync_rate_interval_timer_started = false;
+
+ bool sendSignalMessage = false;
+ if ( getSyncInterval() != operLogSyncInterval )
+ {
+ setSyncInterval( operLogSyncInterval );
+ sendSignalMessage = true;
+ }
+
+ if (log_min_mean_pdelay_req_interval != operLogPdelayReqInterval) {
+ log_min_mean_pdelay_req_interval = operLogPdelayReqInterval;
+ sendSignalMessage = true;
+ }
+
+ if (sendSignalMessage) {
+ if (!isGM) {
+ // Send operational signalling message
+ PTPMessageSignalling *sigMsg = new PTPMessageSignalling(this);
+ if (sigMsg) {
+ if (automotive_profile)
+ sigMsg->setintervals(PTPMessageSignalling::sigMsgInterval_NoChange, getSyncInterval(), PTPMessageSignalling::sigMsgInterval_NoChange);
+ else
+ sigMsg->setintervals(log_min_mean_pdelay_req_interval, getSyncInterval(), PTPMessageSignalling::sigMsgInterval_NoChange);
+ sigMsg->sendPort(this, NULL);
+ delete sigMsg;
+ }
+
+ startSyncReceiptTimer((unsigned long long)
+ (SYNC_RECEIPT_TIMEOUT_MULTIPLIER *
+ ((double) pow((double)2, getSyncInterval()) *
+ 1000000000.0)));
+ }
+ }
+ }
+
+ break;
+ default:
+ GPTP_LOG_ERROR
+ ( "Unhandled event type in "
+ "EtherPort::processEvent(), %d", e );
+ ret = false;
+ break;
+ }
+
+ return ret;
+}
+
+void EtherPort::recoverPort( void )
+{
+ return;
+}
+
+void EtherPort::becomeMaster( bool annc ) {
+ setPortState( PTP_MASTER );
+ // Stop announce receipt timeout timer
+ clock->deleteEventTimerLocked( this, ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES );
+
+ // Stop sync receipt timeout timer
+ stopSyncReceiptTimer();
+
+ if( annc ) {
+ if (!automotive_profile) {
+ startAnnounce();
+ }
+ }
+ startSyncIntervalTimer(16000000);
+ GPTP_LOG_STATUS("Switching to Master" );
+
+ clock->updateFUPInfo();
+
+ return;
+}
+
+void EtherPort::becomeSlave( bool restart_syntonization ) {
+ clock->deleteEventTimerLocked( this, ANNOUNCE_INTERVAL_TIMEOUT_EXPIRES );
+ clock->deleteEventTimerLocked( this, SYNC_INTERVAL_TIMEOUT_EXPIRES );
+
+ setPortState( PTP_SLAVE );
+
+ if (!automotive_profile) {
+ clock->addEventTimerLocked
+ (this, ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES,
+ (ANNOUNCE_RECEIPT_TIMEOUT_MULTIPLIER*
+ (unsigned long long)
+ (pow((double)2,getAnnounceInterval())*1000000000.0)));
+ }
+
+ GPTP_LOG_STATUS("Switching to Slave" );
+ if( restart_syntonization ) clock->newSyntonizationSetPoint();
+
+ getClock()->updateFUPInfo();
+
+ return;
+}
+
+void EtherPort::mapSocketAddr
+( PortIdentity *destIdentity, LinkLayerAddress *remote )
+{
+ *remote = identity_map[*destIdentity];
+ return;
+}
+
+void EtherPort::addSockAddrMap
+( PortIdentity *destIdentity, LinkLayerAddress *remote )
+{
+ identity_map[*destIdentity] = *remote;
+ return;
+}
+
+int EtherPort::getTxTimestamp
+( PTPMessageCommon *msg, Timestamp &timestamp, unsigned &counter_value,
+ bool last )
+{
+ PortIdentity identity;
+ msg->getPortIdentity(&identity);
+ return getTxTimestamp
+ (&identity, msg->getMessageId(), timestamp, counter_value, last);
+}
+
+int EtherPort::getRxTimestamp
+( PTPMessageCommon * msg, Timestamp & timestamp, unsigned &counter_value,
+ bool last )
+{
+ PortIdentity identity;
+ msg->getPortIdentity(&identity);
+ return getRxTimestamp
+ (&identity, msg->getMessageId(), timestamp, counter_value, last);
+}
+
+int EtherPort::getTxTimestamp
+(PortIdentity *sourcePortIdentity, PTPMessageId messageId,
+ Timestamp &timestamp, unsigned &counter_value, bool last )
+{
+ EtherTimestamper *timestamper =
+ dynamic_cast<EtherTimestamper *>(_hw_timestamper);
+ if (timestamper)
+ {
+ return timestamper->HWTimestamper_txtimestamp
+ ( sourcePortIdentity, messageId, timestamp,
+ counter_value, last );
+ }
+ timestamp = clock->getSystemTime();
+ return 0;
+}
+
+int EtherPort::getRxTimestamp
+( PortIdentity * sourcePortIdentity, PTPMessageId messageId,
+ Timestamp &timestamp, unsigned &counter_value, bool last )
+{
+ EtherTimestamper *timestamper =
+ dynamic_cast<EtherTimestamper *>(_hw_timestamper);
+ if (timestamper)
+ {
+ return timestamper->HWTimestamper_rxtimestamp
+ (sourcePortIdentity, messageId, timestamp, counter_value,
+ last);
+ }
+ timestamp = clock->getSystemTime();
+ return 0;
+}
+
+void EtherPort::startPDelayIntervalTimer
+( long long unsigned int waitTime )
+{
+ pDelayIntervalTimerLock->lock();
+ clock->deleteEventTimerLocked(this, PDELAY_INTERVAL_TIMEOUT_EXPIRES);
+ clock->addEventTimerLocked(this, PDELAY_INTERVAL_TIMEOUT_EXPIRES, waitTime);
+ pDelayIntervalTimerLock->unlock();
+}
+
+void EtherPort::syncDone() {
+ GPTP_LOG_VERBOSE("Sync complete");
+
+ if (automotive_profile && getPortState() == PTP_SLAVE) {
+ if (avbSyncState > 0) {
+ avbSyncState--;
+ if (avbSyncState == 0) {
+ setStationState(STATION_STATE_AVB_SYNC);
+ if (getTestMode()) {
+ APMessageTestStatus *testStatusMsg =
+ new APMessageTestStatus(this);
+ if (testStatusMsg) {
+ testStatusMsg->sendPort(this);
+ delete testStatusMsg;
+ }
+ }
+ }
+ }
+ }
+
+ if (automotive_profile) {
+ if (!sync_rate_interval_timer_started) {
+ if ( getSyncInterval() != operLogSyncInterval )
+ {
+ startSyncRateIntervalTimer();
+ }
+ }
+ }
+
+ if( !pdelay_started ) {
+ startPDelay();
+ }
+}
diff --git a/daemons/gptp/common/ether_port.hpp b/daemons/gptp/common/ether_port.hpp
new file mode 100644
index 00000000..32968dc4
--- /dev/null
+++ b/daemons/gptp/common/ether_port.hpp
@@ -0,0 +1,636 @@
+/******************************************************************************
+
+ Copyright (c) 2009-2012, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+******************************************************************************/
+
+#ifndef ETHER_PORT_HPP
+#define ETHER_PORT_HPP
+
+#include <ieee1588.hpp>
+#include <avbap_message.hpp>
+
+#include <avbts_ostimer.hpp>
+#include <avbts_oslock.hpp>
+#include <avbts_osnet.hpp>
+#include <avbts_osthread.hpp>
+#include <avbts_oscondition.hpp>
+#include <ipcdef.hpp>
+#include <gptp_log.hpp>
+
+#include <stdint.h>
+
+#include <map>
+#include <list>
+
+#include <common_port.hpp>
+
+/**@file*/
+
+#define GPTP_MULTICAST 0x0180C200000EULL /*!< GPTP multicast adddress */
+#define PDELAY_MULTICAST GPTP_MULTICAST /*!< PDELAY Multicast value */
+#define OTHER_MULTICAST GPTP_MULTICAST /*!< OTHER multicast value */
+#define TEST_STATUS_MULTICAST 0x011BC50AC000ULL /*!< AVnu Automotive profile test status msg Multicast value */
+
+#define PDELAY_RESP_RECEIPT_TIMEOUT_MULTIPLIER 3 /*!< PDelay timeout multiplier*/
+#define SYNC_RECEIPT_TIMEOUT_MULTIPLIER 3 /*!< Sync receipt timeout multiplier*/
+#define ANNOUNCE_RECEIPT_TIMEOUT_MULTIPLIER 3 /*!< Announce receipt timeout multiplier*/
+
+#define LOG2_INTERVAL_INVALID -127 /* Simple out of range Log base 2 value used for Sync and PDelay msg internvals */
+
+/**
+ * @brief PortType enumeration. Selects between delay request-response (E2E) mechanism
+ * or PTPV1 or PTPV2 P2P (peer delay) mechanism.
+ */
+typedef enum {
+ V1,
+ V2_E2E,
+ V2_P2P
+} PortType;
+
+/**
+ * @brief Provides a map for the identityMap member of EtherPort
+ * class
+ */
+typedef std::map < PortIdentity, LinkLayerAddress > IdentityMap_t;
+
+
+/**
+ * @brief Ethernet specific port functions
+ */
+class EtherPort : public CommonPort
+{
+ static LinkLayerAddress other_multicast;
+ static LinkLayerAddress pdelay_multicast;
+ static LinkLayerAddress test_status_multicast;
+
+ /* Port Status */
+ // set to 0 when asCapable is false, increment for each pdelay recvd
+ bool linkUp;
+
+ /* Port Configuration */
+ signed char log_mean_unicast_sync_interval;
+ signed char log_min_mean_delay_req_interval;
+ signed char log_min_mean_pdelay_req_interval;
+
+ unsigned int duplicate_resp_counter;
+ uint16_t last_invalid_seqid;
+
+ /* Automotive Profile : Static variables */
+ // port_state : already defined as port_state
+ bool isGM;
+ // asCapable : already defined as asCapable
+ signed char operLogPdelayReqInterval;
+ signed char operLogSyncInterval;
+ signed char initialLogPdelayReqInterval;
+ bool automotive_profile;
+
+ // Test Status variables
+ uint32_t linkUpCount;
+ uint32_t linkDownCount;
+ StationState_t stationState;
+
+
+ /* Automotive Profile : Persistant variables */
+ // neighborPropDelay : defined as one_way_delay ??
+ // rateRatio : Optional and didn't fine this variable. Will proceed without writing it.
+ // neighborRateRatio : defined as _peer_rate_offset ??
+
+ // Automotive Profile AVB SYNC state indicator. > 0 will inditate valid AVB SYNC state
+ uint32_t avbSyncState;
+
+ uint16_t pdelay_sequence_id;
+ PTPMessagePathDelayReq *last_pdelay_req;
+ PTPMessagePathDelayResp *last_pdelay_resp;
+ PTPMessagePathDelayRespFollowUp *last_pdelay_resp_fwup;
+
+ IdentityMap_t identity_map;
+
+ PTPMessageSync *last_sync;
+
+ OSCondition *port_ready_condition;
+
+ OSLock *pdelay_rx_lock;
+ OSLock *port_tx_lock;
+
+ OSLock *pDelayIntervalTimerLock;
+
+ net_result port_send
+ (uint16_t etherType, uint8_t * buf, int size, MulticastType mcast_type,
+ PortIdentity * destIdentity, bool timestamp);
+
+ bool pdelay_started;
+ bool pdelay_halted;
+ bool sync_rate_interval_timer_started;
+
+protected:
+ static const unsigned int DUPLICATE_RESP_THRESH = 3;
+
+ public:
+ void becomeMaster( bool annc );
+ void becomeSlave( bool restart_syntonization );
+
+ /**
+ * @brief Starts pDelay event timer.
+ * @return void
+ */
+ void startPDelay();
+
+ /**
+ * @brief Stops PDelay event timer
+ * @return void
+ */
+ void stopPDelay();
+
+ /**
+ * @brief Enable/Disable PDelay Request messages
+ * @param hlt True to HALT (stop sending), False to resume (start sending).
+ */
+ void haltPdelay(bool hlt)
+ {
+ pdelay_halted = hlt;
+ }
+
+ /**
+ * @brief Get the status of pdelayHalted condition.
+ * @return True PdelayRequest halted. False when PDelay Request is running
+ */
+ bool pdelayHalted(void)
+ {
+ return pdelay_halted;
+ }
+
+ /**
+ * @brief Starts Sync Rate Interval event timer. Used for the
+ * Automotive Profile.
+ * @return void
+ */
+ void startSyncRateIntervalTimer();
+
+ /**
+ * @brief Starts pDelay event timer if not yet started.
+ * @return void
+ */
+ void syncDone();
+
+ /**
+ * @brief Gets the AVnu automotive profile flag
+ * @return automotive_profile flag
+ */
+ bool getAutomotiveProfile() { return( automotive_profile ); }
+
+ /**
+ * @brief Destroys a EtherPort
+ */
+ ~EtherPort();
+
+ /**
+ * @brief Creates the EtherPort interface.
+ * @param init PortInit initialization parameters
+ */
+ EtherPort( PortInit_t *portInit );
+
+ /**
+ * @brief Initializes the port. Creates network interface, initializes
+ * hardware timestamper and create OS locks conditions
+ * @return FALSE if error during building the interface. TRUE if success
+ */
+ bool _init_port( void );
+
+ /**
+ * @brief Currently doesnt do anything. Just returns.
+ * @return void
+ */
+ void recoverPort(void);
+
+ /**
+ * @brief Message processing logic on receipt
+ * @param [in] buf buffer containing message
+ * @param [in] length buffer length
+ * @param [in] remote address of sender
+ * @param [in] link_speed of the receiving device
+ */
+ void processMessage
+ ( char *buf, int length, LinkLayerAddress *remote,
+ uint32_t link_speed );
+
+ /**
+ * @brief Receives messages from the network interface
+ * @return Its an infinite loop. Returns NULL in case of error.
+ */
+ void *openPort( EtherPort *port );
+
+ /**
+ * @brief Sends and event to a IEEE1588 port. It includes timestamp
+ * @param buf [in] Pointer to the data buffer
+ * @param len Size of the message
+ * @param mcast_type Enumeration MulticastType (pdlay, none or other). Depracated.
+ * @param destIdentity Destination port identity
+ * @param [out] link_speed indicates link speed
+ * @return void
+ */
+ void sendEventPort
+ (uint16_t etherType, uint8_t * buf, int len, MulticastType mcast_type,
+ PortIdentity * destIdentity, uint32_t *link_speed );
+
+ /**
+ * @brief Sends a general message to a port. No timestamps
+ * @param buf [in] Pointer to the data buffer
+ * @param len Size of the message
+ * @param mcast_type Enumeration MulticastType (pdelay, none or other). Depracated.
+ * @param destIdentity Destination port identity
+ * @return void
+ */
+ void sendGeneralPort
+ (uint16_t etherType, uint8_t * buf, int len, MulticastType mcast_type,
+ PortIdentity * destIdentity);
+
+ /**
+ * @brief Process all events for a EtherPort
+ * @param e Event to be processed
+ * @return true if event is handled, false otherwise
+ */
+ bool _processEvent(Event e);
+
+ /**
+ * @brief Adds a foreign master.
+ * @param msg [in] PTP announce message
+ * @return void
+ * @todo Currently not implemented
+ */
+ void addForeignMaster(PTPMessageAnnounce * msg);
+
+ /**
+ * @brief Remove a foreign master.
+ * @param msg [in] PTP announce message
+ * @return void
+ * @todo Currently not implemented
+ */
+ void removeForeignMaster(PTPMessageAnnounce * msg);
+
+ /**
+ * @brief Remove all foreign masters.
+ * @return void
+ * @todo Currently not implemented
+ */
+ void removeForeignMasterAll(void);
+
+ /**
+ * @brief Gets the pDelay minimum interval
+ * @return PDelay interval
+ */
+ signed char getPDelayInterval(void) {
+ return log_min_mean_pdelay_req_interval;
+ }
+
+ /**
+ * @brief Sets the pDelay minimum interval
+ * @param val time interval
+ * @return none
+ */
+ void setPDelayInterval(signed char val) {
+ log_min_mean_pdelay_req_interval = val;
+ }
+
+ /**
+ * @brief Sets the pDelay minimum interval back to initial
+ * value
+ * @return none */
+ void setInitPDelayInterval(void) {
+ log_min_mean_pdelay_req_interval = initialLogPdelayReqInterval;
+ }
+
+ /**
+ * @brief Start pDelay interval timer
+ * @param waitTime time interval
+ * @return none
+ */
+ void startPDelayIntervalTimer(long long unsigned int waitTime);
+
+ /**
+ * @brief Increments PDelay sequence ID and returns.
+ * @return Next PDelay sequence id.
+ */
+ uint16_t getNextPDelaySequenceId(void) {
+ return pdelay_sequence_id++;
+ }
+
+ /**
+ * @brief Gets last sync sequence number from parent
+ * @return Parent last sync sequence number
+ * @todo Not currently implemented.
+ */
+ uint16_t getParentLastSyncSequenceNumber(void);
+
+ /**
+ * @brief Sets last sync sequence number from parent
+ * @param num Sequence number
+ * @return void
+ * @todo Currently not implemented.
+ */
+ void setParentLastSyncSequenceNumber(uint16_t num);
+
+ /**
+ * @brief Sets last sync ptp message
+ * @param msg [in] PTP sync message
+ * @return void
+ */
+ void setLastSync(PTPMessageSync * msg) {
+ last_sync = msg;
+ }
+
+ /**
+ * @brief Gets last sync message
+ * @return PTPMessageSync last sync
+ */
+ PTPMessageSync *getLastSync(void) {
+ return last_sync;
+ }
+
+ /**
+ * @brief Locks PDelay RX
+ * @return TRUE if acquired the lock. FALSE otherwise
+ */
+ bool getPDelayRxLock() {
+ return pdelay_rx_lock->lock() == oslock_ok ? true : false;
+ }
+
+ /**
+ * @brief Do a trylock on the PDelay RX
+ * @return TRUE if acquired the lock. FALSE otherwise.
+ */
+ bool tryPDelayRxLock() {
+ return pdelay_rx_lock->trylock() == oslock_ok ? true : false;
+ }
+
+ /**
+ * @brief Unlocks PDelay RX.
+ * @return TRUE if success. FALSE otherwise
+ */
+ bool putPDelayRxLock() {
+ return pdelay_rx_lock->unlock() == oslock_ok ? true : false;
+ }
+
+ bool getTxLock() {
+ return port_tx_lock->lock() == oslock_ok ? true : false;
+ }
+
+ bool putTxLock() {
+ return port_tx_lock->unlock() == oslock_ok ? true : false;
+ }
+
+ /**
+ * @brief Sets the last_pdelay_req message
+ * @param msg [in] PTPMessagePathDelayReq message to set
+ * @return void
+ */
+ void setLastPDelayReq(PTPMessagePathDelayReq * msg) {
+ last_pdelay_req = msg;
+ }
+
+ /**
+ * @brief Gets the last PTPMessagePathDelayReq message
+ * @return Last pdelay request
+ */
+ PTPMessagePathDelayReq *getLastPDelayReq(void) {
+ return last_pdelay_req;
+ }
+
+ /**
+ * @brief Sets the last PTPMessagePathDelayResp message
+ * @param msg [in] Last pdelay response
+ * @return void
+ */
+ void setLastPDelayResp(PTPMessagePathDelayResp * msg) {
+ last_pdelay_resp = msg;
+ }
+
+ /**
+ * @brief Gets the last PTPMessagePathDelayResp message
+ * @return Last pdelay response
+ */
+ PTPMessagePathDelayResp *getLastPDelayResp(void) {
+ return last_pdelay_resp;
+ }
+
+ /**
+ * @brief Sets the last PTPMessagePathDelayRespFollowUp message
+ * @param msg [in] last pdelay response follow up
+ * @return void
+ */
+ void setLastPDelayRespFollowUp(PTPMessagePathDelayRespFollowUp * msg) {
+ last_pdelay_resp_fwup = msg;
+ }
+
+ /**
+ * @brief Gets the last PTPMessagePathDelayRespFollowUp message
+ * @return last pdelay response follow up
+ */
+ PTPMessagePathDelayRespFollowUp *getLastPDelayRespFollowUp(void) {
+ return last_pdelay_resp_fwup;
+ }
+
+ /**
+ * @brief Gets RX timestamp based on port identity
+ * @param sourcePortIdentity [in] Source port identity
+ * @param sequenceId Sequence ID
+ * @param timestamp [out] RX timestamp
+ * @param counter_value [out] timestamp count value
+ * @param last If true, removes the rx lock.
+ * @return GPTP_EC_SUCCESS if no error, GPTP_EC_FAILURE if error and GPTP_EC_EAGAIN to try again.
+ */
+ int getRxTimestamp
+ (PortIdentity * sourcePortIdentity, PTPMessageId messageId,
+ Timestamp & timestamp, unsigned &counter_value, bool last);
+
+ /**
+ * @brief Gets TX timestamp based on port identity
+ * @param sourcePortIdentity [in] Source port identity
+ * @param sequenceId Sequence ID
+ * @param timestamp [out] TX timestamp
+ * @param counter_value [out] timestamp count value
+ * @param last If true, removes the TX lock
+ * @return GPTP_EC_SUCCESS if no error, GPTP_EC_FAILURE if error and GPTP_EC_EAGAIN to try again.
+ */
+ int getTxTimestamp
+ (PortIdentity * sourcePortIdentity, PTPMessageId messageId,
+ Timestamp & timestamp, unsigned &counter_value, bool last);
+
+ /**
+ * @brief Gets TX timestamp based on PTP message
+ * @param msg PTPMessageCommon message
+ * @param timestamp [out] TX timestamp
+ * @param counter_value [out] timestamp count value
+ * @param last If true, removes the TX lock
+ * @return GPTP_EC_SUCCESS if no error, GPTP_EC_FAILURE if error and GPTP_EC_EAGAIN to try again.
+ */
+ int getTxTimestamp
+ (PTPMessageCommon * msg, Timestamp & timestamp, unsigned &counter_value,
+ bool last);
+
+ /**
+ * @brief Gets RX timestamp based on PTP message
+ * @param msg PTPMessageCommon message
+ * @param timestamp [out] RX timestamp
+ * @param counter_value [out] timestamp count value
+ * @param last If true, removes the RX lock
+ * @return GPTP_EC_SUCCESS if no error, GPTP_EC_FAILURE if error and GPTP_EC_EAGAIN to try again.
+ */
+ int getRxTimestamp
+ (PTPMessageCommon * msg, Timestamp & timestamp, unsigned &counter_value,
+ bool last);
+
+ /**
+ * @brief Sets the value of last duplicated SeqID
+ * @param seqid Value to set
+ * @return void
+ */
+ void setLastInvalidSeqID(uint16_t seqid)
+ {
+ last_invalid_seqid = seqid;
+ }
+
+ /**
+ * @brief Get the value of last invalid seqID
+ * @return Last invalid seq id
+ */
+ uint16_t getLastInvalidSeqID(void)
+ {
+ return last_invalid_seqid;
+ }
+
+ /**
+ * @brief Sets the duplicate pdelay_resp counter.
+ * @param cnt Value to be set
+ */
+ void setDuplicateRespCounter(unsigned int cnt)
+ {
+ duplicate_resp_counter = cnt;
+ }
+
+ /**
+ * @brief Gets the current value of pdelay_resp duplicate messages counter
+ * @return Counter value
+ */
+ unsigned int getDuplicateRespCounter(void)
+ {
+ return duplicate_resp_counter;
+ }
+
+ /**
+ * @brief Increment the duplicate PDelayResp message counter
+ * @return True if it equals the threshold, False otherwise
+ */
+ bool incrementDuplicateRespCounter(void)
+ {
+ return ++duplicate_resp_counter == DUPLICATE_RESP_THRESH;
+ }
+
+ /**
+ * @brief Maps socket addr to the remote link layer address
+ * @param destIdentity [in] PortIdentity remote
+ * @param remote [in] remote link layer address
+ * @return void
+ */
+ void mapSocketAddr
+ (PortIdentity * destIdentity, LinkLayerAddress * remote);
+
+ /**
+ * @brief Adds New sock addr map
+ * @param destIdentity [in] PortIdentity remote
+ * @param remote [in] remote link layer address
+ * @return void
+ */
+ void addSockAddrMap
+ (PortIdentity * destIdentity, LinkLayerAddress * remote);
+
+ /**
+ * @brief Gets link up count
+ * @return Link up count
+ */
+ uint32_t getLinkUpCount() {
+ return linkUpCount;
+ }
+
+ /**
+ * @brief Gets link down count
+ * @return Link down count
+ */
+ uint32_t getLinkDownCount() {
+ return linkDownCount;
+ }
+
+ /**
+ * @brief Sets the Station State for the Test Status message
+ * @param StationState_t [in] The station state
+ * @return none
+ */
+ void setStationState(StationState_t _stationState) {
+ stationState = _stationState;
+ if (stationState == STATION_STATE_ETHERNET_READY) {
+ GPTP_LOG_STATUS("AVnu AP Status : STATION_STATE_ETHERNET_READY");
+ }
+ else if (stationState == STATION_STATE_AVB_SYNC) {
+ GPTP_LOG_STATUS("AVnu AP Status : STATION_STATE_AVB_SYNC");
+ }
+ else if (stationState == STATION_STATE_AVB_MEDIA_READY) {
+ GPTP_LOG_STATUS("AVnu AP Status : STATION_STATE_AVB_MEDIA_READY");
+ }
+ }
+
+ /**
+ * @brief Gets the Station State for the Test Status
+ * message
+ * @return station state
+ */
+ StationState_t getStationState() {
+ return stationState;
+ }
+
+
+ /**
+ * @brief Sets the linkUp status
+ * @param bool of the linkUp status
+ * @return void
+ */
+ void setLinkUpState(bool state) {
+ linkUp = state;
+ }
+
+ /**
+ * @brief Gets the linkUp status
+ * @return bool of the linkUp status
+ */
+ bool getLinkUpState(void) {
+ return linkUp;
+ }
+};
+
+#endif/*ETHER_PORT_HPP*/
diff --git a/daemons/gptp/common/ether_tstamper.hpp b/daemons/gptp/common/ether_tstamper.hpp
new file mode 100644
index 00000000..bc590cbc
--- /dev/null
+++ b/daemons/gptp/common/ether_tstamper.hpp
@@ -0,0 +1,73 @@
+/******************************************************************************
+
+ Copyright (c) 2009-2012, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+******************************************************************************/
+
+#ifndef ETHER_TSTAMPER_HPP
+#define ETHER_TSTAMPER_HPP
+
+#include <common_tstamper.hpp>
+
+class EtherTimestamper : public CommonTimestamper
+{
+public:
+ /**
+ * @brief Gets the tx timestamp from hardware
+ * @param identity PTP port identity
+ * @param PTPMessageId Message ID
+ * @param timestamp [out] Timestamp value
+ * @param clock_value [out] Clock value
+ * @param last Signalizes that it is the last timestamp to get. When TRUE, releases the lock when its done.
+ * @return GPTP_EC_SUCCESS if no error, GPTP_EC_FAILURE if error and GPTP_EC_EAGAIN to try again.
+ */
+ virtual int HWTimestamper_txtimestamp
+ ( PortIdentity * identity, PTPMessageId messageId,
+ Timestamp &timestamp, unsigned &clock_value, bool last ) = 0;
+
+ /**
+ * @brief Get rx timestamp
+ * @param identity PTP port identity
+ * @param messageId Message ID
+ * @param timestamp [out] Timestamp value
+ * @param clock_value [out] Clock value
+ * @param last Signalizes that it is the last timestamp to get. When TRUE, releases the lock when its done.
+ * @return GPTP_EC_SUCCESS if no error, GPTP_EC_FAILURE if error and GPTP_EC_EAGAIN to try again.
+ */
+ virtual int HWTimestamper_rxtimestamp(PortIdentity * identity,
+ PTPMessageId messageId,
+ Timestamp & timestamp,
+ unsigned &clock_value,
+ bool last) = 0;
+
+ virtual ~EtherTimestamper() {}
+};
+
+#endif/*ETHER_TSTAMPER_HPP*/
diff --git a/daemons/gptp/common/gptp_cfg.cpp b/daemons/gptp/common/gptp_cfg.cpp
index 3c6e37ef..fae8e6c0 100644
--- a/daemons/gptp/common/gptp_cfg.cpp
+++ b/daemons/gptp/common/gptp_cfg.cpp
@@ -48,6 +48,8 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "gptp_cfg.hpp"
+uint32_t findSpeedByName( const char *name, const char **end );
+
GptpIniParser::GptpIniParser(std::string filename)
{
_error = ini_parse(filename.c_str(), iniCallBack, this);
@@ -156,7 +158,7 @@ int GptpIniParser::iniCallBack(void *user, const char *section, const char *name
int phdly = strtoul(value, &pEnd, 10);
if( *pEnd == '\0' && errno == 0) {
valOK = true;
- parser->_config.phyDelay.gb_tx_phy_delay = phdly;
+ parser->_config.phy_delay[LINKSPEED_1G].set_tx_delay( phdly );
}
}
@@ -167,7 +169,7 @@ int GptpIniParser::iniCallBack(void *user, const char *section, const char *name
int phdly = strtoul(value, &pEnd, 10);
if( *pEnd == '\0' && errno == 0) {
valOK = true;
- parser->_config.phyDelay.gb_rx_phy_delay = phdly;
+ parser->_config.phy_delay[LINKSPEED_1G].set_rx_delay( phdly );
}
}
@@ -178,7 +180,8 @@ int GptpIniParser::iniCallBack(void *user, const char *section, const char *name
int phdly = strtoul(value, &pEnd, 10);
if( *pEnd == '\0' && errno == 0) {
valOK = true;
- parser->_config.phyDelay.mb_tx_phy_delay = phdly;
+ parser->_config.phy_delay[LINKSPEED_100MB].
+ set_tx_delay( phdly );
}
}
@@ -189,7 +192,28 @@ int GptpIniParser::iniCallBack(void *user, const char *section, const char *name
int phdly = strtoul(value, &pEnd, 10);
if( *pEnd == '\0' && errno == 0) {
valOK = true;
- parser->_config.phyDelay.mb_rx_phy_delay = phdly;
+ parser->_config.phy_delay[LINKSPEED_100MB].
+ set_rx_delay( phdly );
+ }
+ }
+
+ else if( parseMatch(name, "phy_delay") )
+ {
+ errno = 0;
+ char *pEnd;
+ const char *c_pEnd;
+ uint32_t speed = findSpeedByName( value, &c_pEnd );
+ if( speed == INVALID_LINKSPEED )
+ {
+ speed = strtoul( value, &pEnd, 10 );
+ c_pEnd = pEnd;
+ }
+ int ph_tx_dly = strtoul(c_pEnd, &pEnd, 10);
+ int ph_rx_dly = strtoul(pEnd, &pEnd, 10);
+ if( *pEnd == '\0' && errno == 0) {
+ valOK = true;
+ parser->_config.phy_delay[speed].
+ set_delay( ph_tx_dly, ph_rx_dly );
}
}
}
@@ -211,3 +235,90 @@ bool GptpIniParser::parseMatch(const char *s1, const char *s2)
return strcasecmp(s1, s2) == 0;
}
+#define PHY_DELAY_DESC_LEN 21
+
+void GptpIniParser::print_phy_delay( void )
+{
+
+ phy_delay_map_t map = this->getPhyDelay();
+ for( phy_delay_map_t::const_iterator i = map.cbegin();
+ i != map.cend(); ++i )
+ {
+ uint32_t speed;
+ uint16_t tx, rx;
+ const char *speed_name;
+ char phy_delay_desc[PHY_DELAY_DESC_LEN+1];
+
+ speed = (*i).first;
+ tx = i->second.get_tx_delay();
+ rx = i->second.get_rx_delay();
+
+ snprintf( phy_delay_desc, PHY_DELAY_DESC_LEN+1,
+ "TX: %hu | RX: %hu", tx, rx );
+
+ speed_name = findNameBySpeed( speed );
+ if( speed_name != NULL )
+ GPTP_LOG_INFO( "%s - PHY delay\n\t\t\t%s",
+ speed_name, phy_delay_desc );
+ else
+ GPTP_LOG_INFO( "link speed %u - PHY delay\n\t\t\t%s",
+ speed, phy_delay_desc );
+ }
+}
+
+
+#define DECLARE_SPEED_NAME_MAP( name ) \
+ { name, #name }
+
+typedef struct
+{
+ const uint32_t speed;
+ const char *name;
+} speed_name_map_t;
+
+speed_name_map_t speed_name_map[] =
+{
+ DECLARE_SPEED_NAME_MAP( LINKSPEED_10G ),
+ DECLARE_SPEED_NAME_MAP( LINKSPEED_2_5G ),
+ DECLARE_SPEED_NAME_MAP( LINKSPEED_1G ),
+ DECLARE_SPEED_NAME_MAP( LINKSPEED_100MB ),
+ DECLARE_SPEED_NAME_MAP( INVALID_LINKSPEED )
+};
+
+const char *findNameBySpeed( uint32_t speed )
+{
+ speed_name_map_t *iter = speed_name_map;
+
+ while( iter->speed != INVALID_LINKSPEED )
+ {
+ if( iter->speed == speed )
+ {
+ break;
+ }
+ ++iter;
+ }
+
+ if( iter->speed != INVALID_LINKSPEED )
+ return iter->name;
+
+ return NULL;
+}
+
+uint32_t findSpeedByName( const char *name, const char **end )
+{
+ speed_name_map_t *iter = speed_name_map;
+ *end = name;
+
+ while( iter->speed != INVALID_LINKSPEED )
+ {
+ if( strncmp( name, iter->name, strlen( iter->name )) == 0 )
+ {
+ *end = name + strlen( iter->name );
+ break;
+ }
+ ++iter;
+ }
+
+ return iter->speed;
+}
+
diff --git a/daemons/gptp/common/gptp_cfg.hpp b/daemons/gptp/common/gptp_cfg.hpp
index 62bf149a..f283a4db 100644
--- a/daemons/gptp/common/gptp_cfg.hpp
+++ b/daemons/gptp/common/gptp_cfg.hpp
@@ -37,7 +37,20 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include <string>
#include "ini.h"
-#include "ieee1588.hpp"
+#include <limits.h>
+#include <common_port.hpp>
+
+const uint32_t LINKSPEED_10G = 10000000;
+const uint32_t LINKSPEED_2_5G = 2500000;
+const uint32_t LINKSPEED_1G = 1000000;
+const uint32_t LINKSPEED_100MB = 100000;
+const uint32_t INVALID_LINKSPEED = UINT_MAX;
+
+/**
+ * @brief Returns name given numeric link speed
+ * @return NULL if speed/name isn't found
+ */
+const char *findNameBySpeed( uint32_t speed );
/**
* @brief Provides the gptp interface for
@@ -65,8 +78,8 @@ class GptpIniParser
PortState port_state;
/*ethernet adapter data set*/
- std::string ifname;
- struct phy_delay phyDelay;
+ std::string ifname;
+ phy_delay_map_t phy_delay;
} gptp_cfg_t;
/*public methods*/
@@ -111,43 +124,13 @@ class GptpIniParser
}
/**
- * @brief Reads the TX PHY DELAY GB value from the configuration file
- * @param void
- * @return gb_tx_phy_delay value from the .ini file
- */
- int getPhyDelayGbTx(void)
- {
- return _config.phyDelay.gb_tx_phy_delay;
- }
-
- /**
- * @brief Reads the RX PHY DELAY GB value from the configuration file
+ * @brief Reads the PHY DELAY values from the configuration file
* @param void
- * @return gb_rx_phy_delay value from the .ini file
+ * @return PHY delay map structure
*/
- int getPhyDelayGbRx(void)
+ const phy_delay_map_t getPhyDelay(void)
{
- return _config.phyDelay.gb_rx_phy_delay;
- }
-
- /**
- * @brief Reads the TX PHY DELAY MB value from the configuration file
- * @param void
- * @return mb_tx_phy_delay value from the .ini file
- */
- int getPhyDelayMbTx(void)
- {
- return _config.phyDelay.mb_tx_phy_delay;
- }
-
- /**
- * @brief Reads the RX PHY DELAY MB valye from the configuration file
- * @param void
- * @return mb_rx_phy_delay value from the .ini file
- */
- int getPhyDelayMbRx(void)
- {
- return _config.phyDelay.mb_rx_phy_delay;
+ return _config.phy_delay;
}
/**
@@ -169,6 +152,11 @@ class GptpIniParser
return _config.syncReceiptThresh;
}
+ /**
+ * @brief Dump PHY delays to screen
+ */
+ void print_phy_delay( void );
+
private:
int _error;
gptp_cfg_t _config;
diff --git a/daemons/gptp/common/gptp_log.cpp b/daemons/gptp/common/gptp_log.cpp
index cf425eb6..a1a5809f 100644
--- a/daemons/gptp/common/gptp_log.cpp
+++ b/daemons/gptp/common/gptp_log.cpp
@@ -33,7 +33,27 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// MS VC++ 2013 has C++11 but not C11 support, use this to get millisecond resolution
#include <chrono>
-void gptpLog(const char *tag, const char *path, int line, const char *fmt, ...)
+#ifdef GENIVI_DLT
+DLT_DECLARE_CONTEXT(dlt_con_gptp);
+#endif
+
+void gptplogRegister(void)
+{
+#ifdef GENIVI_DLT
+ DLT_REGISTER_APP("GPTP","OpenAVB gPTP");
+ DLT_REGISTER_CONTEXT(dlt_con_gptp, "GNRL", "General Context");
+#endif
+}
+
+void gptplogUnregister(void)
+{
+#ifdef GENIVI_DLT
+ DLT_UNREGISTER_CONTEXT(dlt_con_gptp);
+ DLT_UNREGISTER_APP();
+#endif
+}
+
+void gptpLog(GPTP_LOG_LEVEL level, const char *tag, const char *path, int line, const char *fmt, ...)
{
char msg[1024];
@@ -41,6 +61,7 @@ void gptpLog(const char *tag, const char *path, int line, const char *fmt, ...)
va_start(args, fmt);
vsprintf(msg, fmt, args);
+#ifndef GENIVI_DLT
std::chrono::system_clock::time_point cNow = std::chrono::system_clock::now();
time_t tNow = std::chrono::system_clock::to_time_t(cNow);
struct tm tmNow;
@@ -56,5 +77,37 @@ void gptpLog(const char *tag, const char *path, int line, const char *fmt, ...)
fprintf(stderr, "%s: GPTP [%2.2d:%2.2d:%2.2d:%3.3ld] %s\n",
tag, tmNow.tm_hour, tmNow.tm_min, tmNow.tm_sec, millis, msg);
}
+#else
+ DltLogLevelType dlt_level;
+
+ switch (level) {
+ case GPTP_LOG_LVL_CRITICAL:
+ dlt_level = DLT_LOG_FATAL;
+ break;
+ case GPTP_LOG_LVL_ERROR:
+ dlt_level = DLT_LOG_ERROR;
+ break;
+ case GPTP_LOG_LVL_EXCEPTION:
+ case GPTP_LOG_LVL_WARNING:
+ dlt_level = DLT_LOG_WARN;
+ break;
+ case GPTP_LOG_LVL_INFO:
+ case GPTP_LOG_LVL_STATUS:
+ dlt_level = DLT_LOG_INFO;
+ break;
+ case GPTP_LOG_LVL_DEBUG:
+ dlt_level = DLT_LOG_DEBUG;
+ break;
+ case GPTP_LOG_LVL_VERBOSE:
+ dlt_level = DLT_LOG_VERBOSE;
+ break;
+ default:
+ dlt_level = DLT_LOG_INFO;
+ break;
+ }
+
+ DLT_LOG(dlt_con_gptp, dlt_level, DLT_STRING(msg));
+#endif
+
}
diff --git a/daemons/gptp/common/gptp_log.hpp b/daemons/gptp/common/gptp_log.hpp
index 91d3f519..272d8cd8 100644
--- a/daemons/gptp/common/gptp_log.hpp
+++ b/daemons/gptp/common/gptp_log.hpp
@@ -32,62 +32,84 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdarg.h>
#include <time.h>
+#ifdef GENIVI_DLT
+#include "dlt.h"
+#endif
+
#define GPTP_LOG_CRITICAL_ON 1
#define GPTP_LOG_ERROR_ON 1
-#define GPTP_LOG_EXCEPTION_ON 1
-#define GPTP_LOG_WARNING_ON 1
-#define GPTP_LOG_INFO_ON 1
+#define GPTP_LOG_EXCEPTION_ON 1
+#define GPTP_LOG_WARNING_ON 1
+#define GPTP_LOG_INFO_ON 1
#define GPTP_LOG_STATUS_ON 1
//#define GPTP_LOG_DEBUG_ON 1
//#define GPTP_LOG_VERBOSE_ON 1
+typedef enum {
+ GPTP_LOG_LVL_CRITICAL,
+ GPTP_LOG_LVL_ERROR,
+ GPTP_LOG_LVL_EXCEPTION,
+ GPTP_LOG_LVL_WARNING,
+ GPTP_LOG_LVL_INFO,
+ GPTP_LOG_LVL_STATUS,
+ GPTP_LOG_LVL_DEBUG,
+ GPTP_LOG_LVL_VERBOSE,
+} GPTP_LOG_LEVEL;
+
+
+void gptplogRegister(void);
+void gptplogUnregister(void);
+void gptpLog(GPTP_LOG_LEVEL level, const char *tag, const char *path, int line, const char *fmt, ...);
+
+
+#define GPTP_LOG_REGISTER() gptplogRegister()
-void gptpLog(const char *tag, const char *path, int line, const char *fmt, ...);
+#define GPTP_LOG_UNREGISTER() gptplogUnregister()
#ifdef GPTP_LOG_CRITICAL_ON
-#define GPTP_LOG_CRITICAL(fmt,...) gptpLog("CRITICAL ", NULL, 0, fmt, ## __VA_ARGS__)
+#define GPTP_LOG_CRITICAL(fmt,...) gptpLog(GPTP_LOG_LVL_CRITICAL, "CRITICAL ", NULL, 0, fmt, ## __VA_ARGS__)
#else
#define GPTP_LOG_CRITICAL(fmt,...)
#endif
#ifdef GPTP_LOG_ERROR_ON
-#define GPTP_LOG_ERROR(fmt,...) gptpLog("ERROR ", NULL, 0, fmt, ## __VA_ARGS__)
+#define GPTP_LOG_ERROR(fmt,...) gptpLog(GPTP_LOG_LVL_ERROR, "ERROR ", NULL, 0, fmt, ## __VA_ARGS__)
#else
#define GPTP_LOG_ERROR(fmt,...)
#endif
#ifdef GPTP_LOG_EXCEPTION_ON
-#define GPTP_LOG_EXCEPTION(fmt,...) gptpLog("EXCEPTION", NULL, 0, fmt, ## __VA_ARGS__)
+#define GPTP_LOG_EXCEPTION(fmt,...) gptpLog(GPTP_LOG_LVL_EXCEPTION, "EXCEPTION", NULL, 0, fmt, ## __VA_ARGS__)
#else
#define GPTP_LOG_EXCEPTION(fmt,...)
#endif
#ifdef GPTP_LOG_WARNING_ON
-#define GPTP_LOG_WARNING(fmt,...) gptpLog("WARNING ", NULL, 0, fmt, ## __VA_ARGS__)
+#define GPTP_LOG_WARNING(fmt,...) gptpLog(GPTP_LOG_LVL_WARNING, "WARNING ", NULL, 0, fmt, ## __VA_ARGS__)
#else
#define GPTP_LOG_WARNING(fmt,...)
#endif
#ifdef GPTP_LOG_INFO_ON
-#define GPTP_LOG_INFO(fmt,...) gptpLog("INFO ", NULL, 0, fmt, ## __VA_ARGS__)
+#define GPTP_LOG_INFO(fmt,...) gptpLog(GPTP_LOG_LVL_INFO, "INFO ", NULL, 0, fmt, ## __VA_ARGS__)
#else
#define GPTP_LOG_INFO(fmt,...)
#endif
#ifdef GPTP_LOG_STATUS_ON
-#define GPTP_LOG_STATUS(fmt,...) gptpLog("STATUS ", NULL, 0, fmt, ## __VA_ARGS__)
+#define GPTP_LOG_STATUS(fmt,...) gptpLog(GPTP_LOG_LVL_STATUS, "STATUS ", NULL, 0, fmt, ## __VA_ARGS__)
#else
#define GPTP_LOG_STATUS(fmt,...)
#endif
#ifdef GPTP_LOG_DEBUG_ON
-#define GPTP_LOG_DEBUG(fmt,...) gptpLog("DEBUG ", __FILE__, __LINE__, fmt, ## __VA_ARGS__)
+#define GPTP_LOG_DEBUG(fmt,...) gptpLog(GPTP_LOG_LVL_DEBUG, "DEBUG ", __FILE__, __LINE__, fmt, ## __VA_ARGS__)
#else
#define GPTP_LOG_DEBUG(fmt,...)
#endif
#ifdef GPTP_LOG_VERBOSE_ON
-#define GPTP_LOG_VERBOSE(fmt,...) gptpLog("VERBOSE ", __FILE__, __LINE__, fmt, ## __VA_ARGS__)
+#define GPTP_LOG_VERBOSE(fmt,...) gptpLog(GPTP_LOG_LVL_VERBOSE, "VERBOSE ", __FILE__, __LINE__, fmt, ## __VA_ARGS__)
#else
#define GPTP_LOG_VERBOSE(fmt,...)
#endif
diff --git a/daemons/gptp/common/ieee1588.hpp b/daemons/gptp/common/ieee1588.hpp
index 79746862..bd95a5fa 100644
--- a/daemons/gptp/common/ieee1588.hpp
+++ b/daemons/gptp/common/ieee1588.hpp
@@ -48,10 +48,9 @@
#include <ptptypes.hpp>
#include <gptp_log.hpp>
+#include <limits.h>
-#define MAX_PORTS 32 /*!< Maximum number of IEEE1588Port instances */
-
-#define PTP_CLOCK_IDENTITY_LENGTH 8 /*!< Size of a clock identifier stored in the ClockIndentity class, described at IEEE 802.1AS Clause 8.5.2.4*/
+#define MAX_PORTS 32 /*!< Maximum number of EtherPort instances */
/**
@@ -65,13 +64,15 @@
class LinkLayerAddress;
struct ClockQuality;
class PortIdentity;
+class PTPMessageId;
class PTPMessageCommon;
class PTPMessageSync;
class PTPMessageAnnounce;
class PTPMessagePathDelayReq;
class PTPMessagePathDelayResp;
class PTPMessagePathDelayRespFollowUp;
-class IEEE1588Port;
+class EtherPort;
+class CommonPort;
class IEEE1588Clock;
class OSNetworkInterface;
@@ -104,18 +105,10 @@ typedef enum {
* @brief Defines an event descriptor type
*/
typedef struct {
- IEEE1588Port *port; //!< IEEE 1588 Port
+ CommonPort *port; //!< Media Dependent Ether Port
Event event; //!< Event enumeration
} event_descriptor_t;
-struct phy_delay
-{
- int mb_tx_phy_delay;
- int mb_rx_phy_delay;
- int gb_tx_phy_delay;
- int gb_rx_phy_delay;
-};
-
/**
* @brief Provides a generic InterfaceLabel class
*/
@@ -235,14 +228,12 @@ class ClockIdentity {
#define INVALID_TIMESTAMP_VERSION 0xFF /*!< Value defining invalid timestamp version*/
#define MAX_NANOSECONDS 1000000000 /*!< Maximum value of nanoseconds (1 second)*/
-#define MAX_TIMESTAMP_STRLEN 28 /*!< Maximum size of timestamp strlen*/
+#define MAX_TSTAMP_STRLEN 25 /*!< Maximum size of timestamp strlen*/
/**
* @brief Provides a Timestamp interface
*/
class Timestamp {
-private:
- char output_string[MAX_TIMESTAMP_STRLEN];
public:
/**
* @brief Creates a Timestamp instance
@@ -264,7 +255,7 @@ public:
* the private parameters
*/
Timestamp() {
- output_string[0] = '\0';
+ Timestamp( 0, 0, 0 );
}
uint32_t nanoseconds; //!< 32 bit nanoseconds value
uint32_t seconds_ls; //!< 32 bit seconds LSB value
@@ -274,14 +265,17 @@ public:
/**
* @brief Copies the timestamp to the internal string in the following format:
* seconds_ms seconds_ls nanoseconds
- * @return Formated string (as a char *)
+ * @return STL string containing timestamp
*/
- char *toString() {
+ std::string toString() const
+ {
+ char output_string[MAX_TSTAMP_STRLEN+1];
+
PLAT_snprintf
- ( output_string, 28, "%hu %u %u", seconds_ms, seconds_ls
- ,
- nanoseconds );
- return output_string;
+ ( output_string, MAX_TSTAMP_STRLEN+1, "%hu %u.%09u",
+ seconds_ms, seconds_ls, nanoseconds );
+
+ return std::string( output_string );
}
/**
@@ -379,9 +373,11 @@ public:
#define INVALID_TIMESTAMP (Timestamp( 0xC0000000, 0, 0 )) /*!< Defines an invalid timestamp using a Timestamp instance and a fixed value*/
#define PDELAY_PENDING_TIMESTAMP (Timestamp( 0xC0000001, 0, 0 )) /*!< PDelay is pending timestamp */
-#define TIMESTAMP_TO_NS(ts) (((static_cast<long long int>((ts).seconds_ms) \
- << sizeof((ts).seconds_ls)*8) + \
- (ts).seconds_ls)*1000000000LL + (ts).nanoseconds) /*!< Converts timestamp value into nanoseconds value*/
+static inline uint64_t TIMESTAMP_TO_NS(Timestamp &ts)
+{
+ return (((static_cast<long long int>(ts.seconds_ms) << sizeof(ts.seconds_ls)*8) +
+ ts.seconds_ls)*1000000000LL + ts.nanoseconds) ; /*!< Converts timestamp value into nanoseconds value*/
+}
/**
* @brief Swaps out byte-a-byte a 64 bit value
@@ -456,203 +452,6 @@ static inline void TIMESTAMP_ADD_NS( Timestamp &ts, uint64_t ns ) {
ts.nanoseconds = (uint32_t)nanos;
}
-#define HWTIMESTAMPER_EXTENDED_MESSAGE_SIZE 4096 /*!< Maximum size of HWTimestamper extended message */
-
-/**
- * @brief Provides a generic interface for hardware timestamping
- */
-class HWTimestamper {
-
-protected:
- uint8_t version; //!< HWTimestamper version
- struct phy_delay delay;
-public:
- /**
- * @brief Initializes the hardware timestamp unit
- * @param iface_label [in] Interface label
- * @param iface [in] Network interface
- * @return true
- */
- virtual bool HWTimestamper_init
- ( InterfaceLabel *iface_label, OSNetworkInterface *iface )
- { return true; }
-
- /**
- * @brief This method is called before the object is de-allocated.
- * @return void
- */
- virtual void HWTimestamper_final(void) {
- }
-
- /**
- * @brief Adjusts the hardware clock frequency
- * @param frequency_offset Frequency offset
- * @return false
- */
- virtual bool HWTimestamper_adjclockrate( float frequency_offset )
- { return false; }
-
- /**
- * @brief Adjusts the hardware clock phase
- * @param phase_adjust Phase offset
- * @return false
- */
- virtual bool HWTimestamper_adjclockphase( int64_t phase_adjust )
- { return false; }
-
- /**
- * @brief Get the cross timestamping information.
- * The gPTP subsystem uses these samples to calculate
- * ratios which can be used to translate or extrapolate
- * one clock into another clock reference. The gPTP service
- * uses these supplied cross timestamps to perform internal
- * rate estimation and conversion functions.
- * @param system_time [out] System time
- * @param device_time [out] Device time
- * @param local_clock [out] Local clock
- * @param nominal_clock_rate [out] Nominal clock rate
- * @return True in case of success. FALSE in case of error
- */
- virtual bool HWTimestamper_gettime(Timestamp * system_time,
- Timestamp * device_time,
- uint32_t * local_clock,
- uint32_t * nominal_clock_rate) = 0;
-
- /**
- * @brief Gets the tx timestamp from hardware
- * @param identity PTP port identity
- * @param sequenceId Sequence ID
- * @param timestamp [out] Timestamp value
- * @param clock_value [out] Clock value
- * @param last Signalizes that it is the last timestamp to get. When TRUE, releases the lock when its done.
- * @return GPTP_EC_SUCCESS if no error, GPTP_EC_FAILURE if error and GPTP_EC_EAGAIN to try again.
- */
- virtual int HWTimestamper_txtimestamp(PortIdentity * identity,
- uint16_t sequenceId,
- Timestamp & timestamp,
- unsigned &clock_value,
- bool last) = 0;
-
- /**
- * @brief Get rx timestamp
- * @param identity PTP port identity
- * @param sequenceId Sequence ID
- * @param timestamp [out] Timestamp value
- * @param clock_value [out] Clock value
- * @param last Signalizes that it is the last timestamp to get. When TRUE, releases the lock when its done.
- * @return GPTP_EC_SUCCESS if no error, GPTP_EC_FAILURE if error and GPTP_EC_EAGAIN to try again.
- */
- virtual int HWTimestamper_rxtimestamp(PortIdentity * identity,
- uint16_t sequenceId,
- Timestamp & timestamp,
- unsigned &clock_value,
- bool last) = 0;
-
- /**
- * @brief Get external clock offset
- * @param local_time [inout] Local time
- * @param clk_offset [inout] clock offset
- * @param ppt_freq_offset [inout] Frequency offset in ppts
- * @return false
- * @todo This code should be removed. It was a hack to get a specific board
- * working.
- */
- virtual bool HWTimestamper_get_extclk_offset(Timestamp * local_time,
- int64_t * clk_offset,
- int32_t *
- ppt_freq_offset) {
- return false;
- }
-
- /**
- * @brief Gets a string with the error from the hardware timestamp block
- * @param msg [out] String error
- * @return void
- * @todo There is no current implementation for this method.
- */
- virtual void HWTimestamper_get_extderror(char *msg) {
- *msg = '\0';
- }
-
- /**
- * @brief Starts the PPS (pulse per second) interface
- * @return false
- */
- virtual bool HWTimestamper_PPS_start() { return false; };
-
- /**
- * @brief Stops the PPS (pulse per second) interface
- * @return true
- */
- virtual bool HWTimestamper_PPS_stop() { return true; };
-
- /**
- * @brief Gets the HWTimestamper version
- * @return version (signed integer)
- */
- int getVersion() {
- return version;
- }
- /**
- * @brief Initializes the PHY delay for TX and RX
- * @param [input] mb_tx_phy_delay, mb_rx_phy_delay, gb_tx_phy_delay, gb_rx_phy_delay
- * @return 0
- **/
-
- int init_phy_delay(int phy_delay[4])
- {
- delay.gb_tx_phy_delay = phy_delay[0];
- delay.gb_rx_phy_delay = phy_delay[1];
- delay.mb_tx_phy_delay = phy_delay[2];
- delay.mb_rx_phy_delay = phy_delay[3];
-
-
- return 0;
- }
-
- /**
- * @brief Returns the the PHY delay for TX and RX
- * @param [input] struct phy_delay pointer
- * @return 0
- **/
-
- int get_phy_delay (struct phy_delay *get_delay)
- {
- get_delay->mb_tx_phy_delay = delay.mb_tx_phy_delay;
- get_delay->mb_rx_phy_delay = delay.mb_rx_phy_delay;
- get_delay->gb_tx_phy_delay = delay.gb_tx_phy_delay;
- get_delay->gb_rx_phy_delay = delay.gb_rx_phy_delay;
-
- return 0;
- }
-
- /**
- * @brief Sets the the PHY delay for TX and RX
- * @param [input] struct phy_delay pointer
- * @return 0
- **/
-
- int set_phy_delay(struct phy_delay *set_delay)
- {
- delay.mb_tx_phy_delay = set_delay->mb_tx_phy_delay;
- delay.mb_rx_phy_delay = set_delay->mb_rx_phy_delay;
- delay.gb_tx_phy_delay = set_delay->gb_tx_phy_delay;
- delay.gb_rx_phy_delay = set_delay->gb_rx_phy_delay;
-
- return 0;
- }
-
- /**
- * @brief Default constructor. Sets version to zero.
- */
- HWTimestamper() { version = 0; }
-
- /**
- * @brief Deletes HWtimestamper object
- */
- virtual ~HWTimestamper() { }
-};
-
/**
* @brief Builds a PTP message
* @param buf [in] message buffer to send
@@ -661,8 +460,8 @@ public:
* @param port [in] IEEE1588 port
* @return PTP message instance of PTPMessageCommon
*/
-PTPMessageCommon *buildPTPMessage(char *buf, int size,
- LinkLayerAddress * remote,
- IEEE1588Port * port);
+PTPMessageCommon *buildPTPMessage
+( char *buf, int size, LinkLayerAddress *remote,
+ EtherPort *port );
#endif
diff --git a/daemons/gptp/common/ieee1588clock.cpp b/daemons/gptp/common/ieee1588clock.cpp
index ab6f47ac..3cb7ad8e 100644
--- a/daemons/gptp/common/ieee1588clock.cpp
+++ b/daemons/gptp/common/ieee1588clock.cpp
@@ -79,8 +79,8 @@ void ClockIdentity::set(LinkLayerAddress * addr)
IEEE1588Clock::IEEE1588Clock
( bool forceOrdinarySlave, bool syntonize, uint8_t priority1,
- HWTimestamper *timestamper, OSTimerQueueFactory *timerq_factory,
- OS_IPC *ipc, OSLockFactory *lock_factory )
+ OSTimerQueueFactory *timerq_factory, OS_IPC *ipc,
+ OSLockFactory *lock_factory )
{
this->priority1 = priority1;
priority2 = 248;
@@ -106,7 +106,6 @@ IEEE1588Clock::IEEE1588Clock
_master_local_freq_offset_init = false;
_local_system_freq_offset_init = false;
- _timestamper = timestamper;
this->ipc = ipc;
@@ -233,7 +232,7 @@ void timerq_handler(void *arg)
}
void IEEE1588Clock::addEventTimer
-( IEEE1588Port * target, Event e, unsigned long long time_ns )
+( CommonPort *target, Event e, unsigned long long time_ns )
{
event_descriptor_t *event_descriptor = new event_descriptor_t();
event_descriptor->event = e;
@@ -244,7 +243,7 @@ void IEEE1588Clock::addEventTimer
}
void IEEE1588Clock::addEventTimerLocked
-( IEEE1588Port * target, Event e, unsigned long long time_ns )
+( CommonPort *target, Event e, unsigned long long time_ns )
{
if( getTimerQLock() == oslock_fail ) return;
addEventTimer( target, e, time_ns );
@@ -253,12 +252,14 @@ void IEEE1588Clock::addEventTimerLocked
-void IEEE1588Clock::deleteEventTimer(IEEE1588Port * target, Event event)
+void IEEE1588Clock::deleteEventTimer
+( CommonPort *target, Event event )
{
timerq->cancelEvent((int)event, NULL);
}
-void IEEE1588Clock::deleteEventTimerLocked(IEEE1588Port * target, Event event)
+void IEEE1588Clock::deleteEventTimerLocked
+( CommonPort *target, Event event )
{
if( getTimerQLock() == oslock_fail ) return;
@@ -320,8 +321,11 @@ FrequencyRatio IEEE1588Clock::calcMasterLocalClockRateDifference( Timestamp mast
inter_sync_time =
TIMESTAMP_TO_NS(sync_time) - TIMESTAMP_TO_NS(_prev_sync_time);
- inter_master_time =
- TIMESTAMP_TO_NS(master_time) - TIMESTAMP_TO_NS(_prev_master_time);
+
+ uint64_t master_time_ns = TIMESTAMP_TO_NS(master_time);
+ uint64_t prev_master_time_ns = TIMESTAMP_TO_NS(_prev_master_time);
+
+ inter_master_time = master_time_ns - prev_master_time_ns;
if( inter_sync_time != 0 ) {
ppt_offset = ((FrequencyRatio)inter_master_time)/inter_sync_time;
@@ -329,6 +333,14 @@ FrequencyRatio IEEE1588Clock::calcMasterLocalClockRateDifference( Timestamp mast
ppt_offset = 1.0;
}
+ if( master_time_ns < prev_master_time_ns ) {
+ GPTP_LOG_ERROR("Negative time jump detected - inter_master_time: %lld, inter_sync_time: %lld, incorrect ppt_offset: %Lf",
+ inter_master_time, inter_sync_time, ppt_offset);
+ _master_local_freq_offset_init = false;
+
+ return NEGATIVE_TIME_JUMP;
+ }
+
_prev_sync_time = sync_time;
_prev_master_time = master_time;
@@ -336,10 +348,11 @@ FrequencyRatio IEEE1588Clock::calcMasterLocalClockRateDifference( Timestamp mast
}
void IEEE1588Clock::setMasterOffset
-( IEEE1588Port * port, int64_t master_local_offset, Timestamp local_time,
- FrequencyRatio master_local_freq_offset, int64_t local_system_offset,
- Timestamp system_time, FrequencyRatio local_system_freq_offset,
- unsigned sync_count, unsigned pdelay_count, PortState port_state, bool asCapable )
+( CommonPort *port, int64_t master_local_offset,
+ Timestamp local_time, FrequencyRatio master_local_freq_offset,
+ int64_t local_system_offset, Timestamp system_time,
+ FrequencyRatio local_system_freq_offset, unsigned sync_count,
+ unsigned pdelay_count, PortState port_state, bool asCapable )
{
_master_local_freq_offset = master_local_freq_offset;
_local_system_freq_offset = local_system_freq_offset;
@@ -349,10 +362,35 @@ void IEEE1588Clock::setMasterOffset
master_local_offset, master_local_freq_offset, sync_count, pdelay_count);
}
- if( ipc != NULL ) ipc->update
- ( master_local_offset, local_system_offset, master_local_freq_offset,
- local_system_freq_offset, TIMESTAMP_TO_NS(local_time), sync_count,
- pdelay_count, port_state, asCapable );
+ if( ipc != NULL ) {
+ uint8_t grandmaster_id[PTP_CLOCK_IDENTITY_LENGTH];
+ uint8_t clock_id[PTP_CLOCK_IDENTITY_LENGTH];
+ PortIdentity port_identity;
+ uint16_t port_number;
+
+ grandmaster_clock_identity.getIdentityString(grandmaster_id);
+ clock_identity.getIdentityString(clock_id);
+ port->getPortIdentity(port_identity);
+ port_identity.getPortNumber(&port_number);
+
+ ipc->update(
+ master_local_offset, local_system_offset, master_local_freq_offset,
+ local_system_freq_offset, TIMESTAMP_TO_NS(local_time),
+ sync_count, pdelay_count, port_state, asCapable);
+
+ ipc->update_grandmaster(
+ grandmaster_id, domain_number);
+
+ ipc->update_network_interface(
+ clock_id, priority1,
+ clock_quality.cq_class, clock_quality.offsetScaledLogVariance,
+ clock_quality.clockAccuracy,
+ priority2, domain_number,
+ port->getSyncInterval(),
+ port->getAnnounceInterval(),
+ 0, // TODO: Was port->getPDelayInterval() before refactoring. What do we do now?
+ port_number);
+ }
if( master_local_offset == 0 && master_local_freq_offset == 1.0 ) {
return;
@@ -362,20 +400,17 @@ void IEEE1588Clock::setMasterOffset
if( _new_syntonization_set_point || _phase_error_violation > PHASE_ERROR_MAX_COUNT ) {
_new_syntonization_set_point = false;
_phase_error_violation = 0;
- if( _timestamper ) {
- /* Make sure that there are no transmit operations
- in progress */
- getTxLockAll();
- if (port->getTestMode()) {
- GPTP_LOG_STATUS("Adjust clock phase offset:%lld", -master_local_offset);
- }
- _timestamper->HWTimestamper_adjclockphase
- ( -master_local_offset );
- _master_local_freq_offset_init = false;
- restartPDelayAll();
- putTxLockAll();
- master_local_offset = 0;
+ /* Make sure that there are no transmit operations
+ in progress */
+ getTxLockAll();
+ if (port->getTestMode()) {
+ GPTP_LOG_STATUS("Adjust clock phase offset:%lld", -master_local_offset);
}
+ port->adjustClockPhase( -master_local_offset );
+ _master_local_freq_offset_init = false;
+ restartPDelayAll();
+ putTxLockAll();
+ master_local_offset = 0;
}
// Adjust for frequency offset
@@ -393,13 +428,11 @@ void IEEE1588Clock::setMasterOffset
if( _ppm < LOWER_FREQ_LIMIT ) _ppm = LOWER_FREQ_LIMIT;
if( _ppm > UPPER_FREQ_LIMIT ) _ppm = UPPER_FREQ_LIMIT;
- if( _timestamper ) {
- if (port->getTestMode()) {
- GPTP_LOG_STATUS("Adjust clock rate ppm:%f", _ppm);
- }
- if( !_timestamper->HWTimestamper_adjclockrate( _ppm )) {
- GPTP_LOG_ERROR( "Failed to adjust clock rate" );
- }
+ if ( port->getTestMode() ) {
+ GPTP_LOG_STATUS("Adjust clock rate ppm:%f", _ppm);
+ }
+ if( !port->adjustClockRate( _ppm ) ) {
+ GPTP_LOG_ERROR( "Failed to adjust clock rate" );
}
}
@@ -424,6 +457,9 @@ bool IEEE1588Clock::isBetterThan(PTPMessageAnnounce * msg)
unsigned char that1[14];
uint16_t tmp;
+ if (msg == NULL)
+ return true;
+
this1[0] = priority1;
that1[0] = msg->getGrandmasterPriority1();
diff --git a/daemons/gptp/common/ieee1588port.cpp b/daemons/gptp/common/ieee1588port.cpp
deleted file mode 100644
index 34edf4d1..00000000
--- a/daemons/gptp/common/ieee1588port.cpp
+++ /dev/null
@@ -1,1437 +0,0 @@
-/******************************************************************************
-
- Copyright (c) 2009-2012, Intel Corporation
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- 1. Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- 3. Neither the name of the Intel Corporation nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
-
-******************************************************************************/
-
-#include <ieee1588.hpp>
-
-#include <avbts_port.hpp>
-#include <avbts_message.hpp>
-#include <avbts_clock.hpp>
-
-#include <avbts_oslock.hpp>
-#include <avbts_osnet.hpp>
-#include <avbts_oscondition.hpp>
-
-#include <gptp_log.hpp>
-
-#include <stdio.h>
-
-#include <math.h>
-
-#include <stdlib.h>
-
-LinkLayerAddress IEEE1588Port::other_multicast(OTHER_MULTICAST);
-LinkLayerAddress IEEE1588Port::pdelay_multicast(PDELAY_MULTICAST);
-LinkLayerAddress IEEE1588Port::test_status_multicast(TEST_STATUS_MULTICAST);
-
-OSThreadExitCode watchNetLinkWrapper(void *arg)
-{
- IEEE1588Port *port;
-
- port = (IEEE1588Port *) arg;
- if (port->watchNetLink() == NULL)
- return osthread_ok;
- else
- return osthread_error;
-}
-
-OSThreadExitCode openPortWrapper(void *arg)
-{
- IEEE1588Port *port;
-
- port = (IEEE1588Port *) arg;
- if (port->openPort(port) == NULL)
- return osthread_ok;
- else
- return osthread_error;
-}
-
-IEEE1588Port::~IEEE1588Port()
-{
- delete port_ready_condition;
- delete [] rate_offset_array;
- if( qualified_announce != NULL ) delete qualified_announce;
-}
-
-IEEE1588Port::IEEE1588Port(IEEE1588PortInit_t *portInit)
-{
- sync_sequence_id = 0;
-
- clock = portInit->clock;
- ifindex = portInit->index;
- clock->registerPort(this, ifindex);
-
- forceSlave = portInit->forceSlave;
- port_state = PTP_INITIALIZING;
-
- automotive_profile = portInit->automotive_profile;
- isGM = portInit->isGM;
- testMode = portInit->testMode;
- initialLogSyncInterval = portInit->initialLogSyncInterval;
- initialLogPdelayReqInterval = portInit->initialLogPdelayReqInterval;
- operLogPdelayReqInterval = portInit->operLogPdelayReqInterval;
- operLogSyncInterval = portInit->operLogSyncInterval;
-
- if (automotive_profile) {
- asCapable = true;
-
- if (initialLogSyncInterval == LOG2_INTERVAL_INVALID)
- initialLogSyncInterval = -5; // 31.25 ms
- if (initialLogPdelayReqInterval == LOG2_INTERVAL_INVALID)
- initialLogPdelayReqInterval = 0; // 1 second
- if (operLogPdelayReqInterval == LOG2_INTERVAL_INVALID)
- operLogPdelayReqInterval = 0; // 1 second
- if (operLogSyncInterval == LOG2_INTERVAL_INVALID)
- operLogSyncInterval = 0; // 1 second
- }
- else {
- asCapable = false;
-
- if (initialLogSyncInterval == LOG2_INTERVAL_INVALID)
- initialLogSyncInterval = -3; // 125 ms
- if (initialLogPdelayReqInterval == LOG2_INTERVAL_INVALID)
- initialLogPdelayReqInterval = 0; // 1 second
- if (operLogPdelayReqInterval == LOG2_INTERVAL_INVALID)
- operLogPdelayReqInterval = 0; // 1 second
- if (operLogSyncInterval == LOG2_INTERVAL_INVALID)
- operLogSyncInterval = 0; // 1 second
- }
-
- announce_sequence_id = 0;
- signal_sequence_id = 0;
- sync_sequence_id = 0;
- pdelay_sequence_id = 0;
-
- pdelay_started = false;
- pdelay_halted = false;
- sync_rate_interval_timer_started = false;
-
- duplicate_resp_counter = 0;
- last_invalid_seqid = 0;
-
- /*TODO: Add intervals below to a config interface*/
- log_mean_sync_interval = initialLogSyncInterval;
- _accelerated_sync_count = portInit->accelerated_sync_count;
- log_mean_announce_interval = 0;
- log_min_mean_pdelay_req_interval = initialLogPdelayReqInterval;
-
- _current_clock_offset = _initial_clock_offset = portInit->offset;
-
- rate_offset_array = NULL;
-
- _hw_timestamper = portInit->timestamper;
-
- one_way_delay = ONE_WAY_DELAY_DEFAULT;
- neighbor_prop_delay_thresh = NEIGHBOR_PROP_DELAY_THRESH;
- sync_receipt_thresh = DEFAULT_SYNC_RECEIPT_THRESH;
- wrongSeqIDCounter = 0;
-
- _peer_rate_offset = 1.0;
-
- last_sync = NULL;
- last_pdelay_req = NULL;
- last_pdelay_resp = NULL;
- last_pdelay_resp_fwup = NULL;
-
- qualified_announce = NULL;
-
- this->net_label = portInit->net_label;
-
- this->timer_factory = portInit->timer_factory;
- this->thread_factory = portInit->thread_factory;
-
- this->condition_factory = portInit->condition_factory;
- this->lock_factory = portInit->lock_factory;
-
- setPdelayCount(0);
- setSyncCount(0);
- memset(link_delay, 0, sizeof(link_delay));
-
- _peer_offset_init = false;
-
- if (automotive_profile) {
- if (isGM) {
- avbSyncState = 1;
- }
- else {
- avbSyncState = 2;
- }
- if (testMode) {
- linkUpCount = 1; // TODO : really should check the current linkup status http://stackoverflow.com/questions/15723061/how-to-check-if-interface-is-up
- linkDownCount = 0;
- }
- setStationState(STATION_STATE_RESERVED);
- }
-}
-
-void IEEE1588Port::timestamper_init(void)
-{
- if( _hw_timestamper != NULL ) {
- _hw_timestamper->init_phy_delay(this->link_delay);
- if( !_hw_timestamper->HWTimestamper_init( net_label, net_iface )) {
- GPTP_LOG_ERROR
- ( "Failed to initialize hardware timestamper, "
- "falling back to software timestamping" );
- _hw_timestamper = NULL;
- return;
- }
- }
-}
-
-bool IEEE1588Port::init_port(int delay[4])
-{
- if (!OSNetworkInterfaceFactory::buildInterface
- (&net_iface, factory_name_t("default"), net_label, _hw_timestamper))
- return false;
-
- this->net_iface = net_iface;
- this->net_iface->getLinkLayerAddress(&local_addr);
- clock->setClockIdentity(&local_addr);
- memcpy(this->link_delay, delay, sizeof(this->link_delay));
-
- this->timestamper_init();
-
- pdelay_rx_lock = lock_factory->createLock(oslock_recursive);
- port_tx_lock = lock_factory->createLock(oslock_recursive);
-
- syncReceiptTimerLock = lock_factory->createLock(oslock_recursive);
- syncIntervalTimerLock = lock_factory->createLock(oslock_recursive);
- announceIntervalTimerLock = lock_factory->createLock(oslock_recursive);
- pDelayIntervalTimerLock = lock_factory->createLock(oslock_recursive);
-
- port_identity.setClockIdentity(clock->getClockIdentity());
- port_identity.setPortNumber(&ifindex);
-
- port_ready_condition = condition_factory->createCondition();
-
- return true;
-}
-
-void IEEE1588Port::startPDelay() {
- if(!pdelayHalted()) {
- if (automotive_profile) {
- if (log_min_mean_pdelay_req_interval != PTPMessageSignalling::sigMsgInterval_NoSend) {
- long long unsigned int waitTime;
- waitTime = ((long long) (pow((double)2, log_min_mean_pdelay_req_interval) * 1000000000.0));
- waitTime = waitTime > EVENT_TIMER_GRANULARITY ? waitTime : EVENT_TIMER_GRANULARITY;
- pdelay_started = true;
- startPDelayIntervalTimer(waitTime);
- }
- }
- else {
- pdelay_started = true;
- startPDelayIntervalTimer(32000000);
- }
- }
-}
-
-void IEEE1588Port::stopPDelay() {
- haltPdelay(true);
- pdelay_started = false;
- clock->deleteEventTimerLocked( this, PDELAY_INTERVAL_TIMEOUT_EXPIRES);
-}
-
-void IEEE1588Port::startSyncRateIntervalTimer() {
- if (automotive_profile) {
- sync_rate_interval_timer_started = true;
- if (isGM) {
- // GM will wait up to 8 seconds for signaling rate
- // TODO: This isn't according to spec but set because it is believed that some slave devices aren't signalling
- // to reduce the rate
- clock->addEventTimerLocked( this, SYNC_RATE_INTERVAL_TIMEOUT_EXPIRED, 8000000000 );
- }
- else {
- // Slave will time out after 4 seconds
- clock->addEventTimerLocked( this, SYNC_RATE_INTERVAL_TIMEOUT_EXPIRED, 4000000000 );
- }
- }
-}
-
-void IEEE1588Port::startAnnounce() {
- if (!automotive_profile) {
- startAnnounceIntervalTimer(16000000);
- }
-}
-
-bool IEEE1588Port::serializeState( void *buf, off_t *count ) {
- bool ret = true;
-
- if( buf == NULL ) {
- *count = sizeof(port_state)+sizeof(_peer_rate_offset)+
- sizeof(asCapable)+sizeof(one_way_delay);
- return true;
- }
-
- if( port_state != PTP_MASTER && port_state != PTP_SLAVE ) {
- *count = 0;
- ret = false;
- goto bail;
- }
-
- /* asCapable */
- if( ret && *count >= (off_t) sizeof( asCapable )) {
- memcpy( buf, &asCapable, sizeof( asCapable ));
- *count -= sizeof( asCapable );
- buf = ((char *)buf) + sizeof( asCapable );
- } else if( ret == false ) {
- *count += sizeof( asCapable );
- } else {
- *count = sizeof( asCapable )-*count;
- ret = false;
- }
-
- /* Port State */
- if( ret && *count >= (off_t) sizeof( port_state )) {
- memcpy( buf, &port_state, sizeof( port_state ));
- *count -= sizeof( port_state );
- buf = ((char *)buf) + sizeof( port_state );
- } else if( ret == false ) {
- *count += sizeof( port_state );
- } else {
- *count = sizeof( port_state )-*count;
- ret = false;
- }
-
- /* Link Delay */
- if( ret && *count >= (off_t) sizeof( one_way_delay )) {
- memcpy( buf, &one_way_delay, sizeof( one_way_delay ));
- *count -= sizeof( one_way_delay );
- buf = ((char *)buf) + sizeof( one_way_delay );
- } else if( ret == false ) {
- *count += sizeof( one_way_delay );
- } else {
- *count = sizeof( one_way_delay )-*count;
- ret = false;
- }
-
- /* Neighbor Rate Ratio */
- if( ret && *count >= (off_t) sizeof( _peer_rate_offset )) {
- memcpy( buf, &_peer_rate_offset, sizeof( _peer_rate_offset ));
- *count -= sizeof( _peer_rate_offset );
- buf = ((char *)buf) + sizeof( _peer_rate_offset );
- } else if( ret == false ) {
- *count += sizeof( _peer_rate_offset );
- } else {
- *count = sizeof( _peer_rate_offset )-*count;
- ret = false;
- }
-
- bail:
- return ret;
-}
-
-bool IEEE1588Port::restoreSerializedState( void *buf, off_t *count ) {
- bool ret = true;
-
- /* asCapable */
- if( ret && *count >= (off_t) sizeof( asCapable )) {
- memcpy( &asCapable, buf, sizeof( asCapable ));
- *count -= sizeof( asCapable );
- buf = ((char *)buf) + sizeof( asCapable );
- } else if( ret == false ) {
- *count += sizeof( asCapable );
- } else {
- *count = sizeof( asCapable )-*count;
- ret = false;
- }
-
- /* Port State */
- if( ret && *count >= (off_t) sizeof( port_state )) {
- memcpy( &port_state, buf, sizeof( port_state ));
- *count -= sizeof( port_state );
- buf = ((char *)buf) + sizeof( port_state );
- } else if( ret == false ) {
- *count += sizeof( port_state );
- } else {
- *count = sizeof( port_state )-*count;
- ret = false;
- }
-
- /* Link Delay */
- if( ret && *count >= (off_t) sizeof( one_way_delay )) {
- memcpy( &one_way_delay, buf, sizeof( one_way_delay ));
- *count -= sizeof( one_way_delay );
- buf = ((char *)buf) + sizeof( one_way_delay );
- } else if( ret == false ) {
- *count += sizeof( one_way_delay );
- } else {
- *count = sizeof( one_way_delay )-*count;
- ret = false;
- }
-
- /* Neighbor Rate Ratio */
- if( ret && *count >= (off_t) sizeof( _peer_rate_offset )) {
- memcpy( &_peer_rate_offset, buf, sizeof( _peer_rate_offset ));
- *count -= sizeof( _peer_rate_offset );
- buf = ((char *)buf) + sizeof( _peer_rate_offset );
- } else if( ret == false ) {
- *count += sizeof( _peer_rate_offset );
- } else {
- *count = sizeof( _peer_rate_offset )-*count;
- ret = false;
- }
-
- return ret;
-}
-
-void *IEEE1588Port::watchNetLink(void)
-{
- // Should never return
- net_iface->watchNetLink(this);
-
- return NULL;
-}
-
-void *IEEE1588Port::openPort(IEEE1588Port *port)
-{
- port_ready_condition->signal();
- struct phy_delay get_delay = { 0, 0, 0, 0 };
- if(port->_hw_timestamper)
- port->_hw_timestamper->get_phy_delay(&get_delay);
-
- while (1) {
- PTPMessageCommon *msg;
- uint8_t buf[128];
- LinkLayerAddress remote;
- net_result rrecv;
- size_t length = sizeof(buf);
-
- if ((rrecv = net_iface->nrecv(&remote, buf, length,&get_delay)) == net_succeed) {
- GPTP_LOG_VERBOSE("Processing network buffer");
- msg = buildPTPMessage((char *)buf, (int)length, &remote,
- this);
- if (msg != NULL) {
- GPTP_LOG_VERBOSE("Processing message");
- msg->processMessage(this);
- if (msg->garbage()) {
- delete msg;
- }
- } else {
- GPTP_LOG_ERROR("Discarding invalid message");
- }
- } else if (rrecv == net_fatal) {
- GPTP_LOG_ERROR("read from network interface failed");
- this->processEvent(FAULT_DETECTED);
- break;
- }
- }
-
- return NULL;
-}
-
-net_result IEEE1588Port::port_send(uint16_t etherType, uint8_t * buf, int size,
- MulticastType mcast_type,
- PortIdentity * destIdentity, bool timestamp)
-{
- LinkLayerAddress dest;
-
- if (mcast_type != MCAST_NONE) {
- if (mcast_type == MCAST_PDELAY) {
- dest = pdelay_multicast;
- }
- else if (mcast_type == MCAST_TEST_STATUS) {
- dest = test_status_multicast;
- }
- else {
- dest = other_multicast;
- }
- } else {
- mapSocketAddr(destIdentity, &dest);
- }
-
- return net_iface->send(&dest, etherType, (uint8_t *) buf, size, timestamp);
-}
-
-unsigned IEEE1588Port::getPayloadOffset()
-{
- return net_iface->getPayloadOffset();
-}
-
-void IEEE1588Port::sendEventPort(uint16_t etherType, uint8_t * buf, int size,
- MulticastType mcast_type,
- PortIdentity * destIdentity)
-{
- net_result rtx = port_send(etherType, buf, size, mcast_type, destIdentity, true);
- if (rtx != net_succeed) {
- GPTP_LOG_ERROR("sendEventPort(): failure");
- }
-
- return;
-}
-
-void IEEE1588Port::sendGeneralPort(uint16_t etherType, uint8_t * buf, int size,
- MulticastType mcast_type,
- PortIdentity * destIdentity)
-{
- net_result rtx = port_send(etherType, buf, size, mcast_type, destIdentity, false);
- if (rtx != net_succeed) {
- GPTP_LOG_ERROR("sendGeneralPort(): failure");
- }
-
- return;
-}
-
-void IEEE1588Port::processEvent(Event e)
-{
- bool changed_external_master;
-
- switch (e) {
- case POWERUP:
- case INITIALIZE:
- GPTP_LOG_DEBUG("Received POWERUP/INITIALIZE event");
-
- {
- unsigned long long interval3;
- unsigned long long interval4;
- Event e3 = NULL_EVENT;
- Event e4 = NULL_EVENT;
-
- if( port_state != PTP_MASTER ) {
- _accelerated_sync_count = -1;
- }
-
- if (!automotive_profile) {
- if (port_state != PTP_SLAVE && port_state != PTP_MASTER) {
- GPTP_LOG_STATUS("Starting PDelay");
- startPDelay();
- }
- }
- else {
- startPDelay();
- }
-
- if( clock->getPriority1() == 255 || port_state == PTP_SLAVE ) {
- becomeSlave( true );
- } else if( port_state == PTP_MASTER ) {
- becomeMaster( true );
- } else {
- /*TODO: Should I remove the commented code below ?*/
- //e3 = SYNC_RECEIPT_TIMEOUT_EXPIRES;
- e4 = ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES;
- interval3 = (unsigned long long)
- (SYNC_RECEIPT_TIMEOUT_MULTIPLIER*
- pow((double)2,getSyncInterval())*1000000000.0);
- interval4 = (unsigned long long)
- (ANNOUNCE_RECEIPT_TIMEOUT_MULTIPLIER*
- pow((double)2,getAnnounceInterval())*1000000000.0);
- }
-
- port_ready_condition->wait_prelock();
-
- link_thread = thread_factory->createThread();
- if(!link_thread->start(watchNetLinkWrapper, (void *)this))
- {
- GPTP_LOG_ERROR("Error creating port link thread");
- return;
- }
-
- listening_thread = thread_factory->createThread();
- if (!listening_thread->
- start (openPortWrapper, (void *)this))
- {
- GPTP_LOG_ERROR("Error creating port thread");
- return;
- }
- port_ready_condition->wait();
-
- if (e3 != NULL_EVENT)
- clock->addEventTimerLocked(this, e3, interval3);
- if (e4 != NULL_EVENT)
- clock->addEventTimerLocked(this, e4, interval4);
- }
-
- if (automotive_profile) {
- setStationState(STATION_STATE_ETHERNET_READY);
- if (testMode) {
- APMessageTestStatus *testStatusMsg = new APMessageTestStatus(this);
- if (testStatusMsg) {
- testStatusMsg->sendPort(this);
- delete testStatusMsg;
- }
- }
- if (!isGM) {
- // Send an initial signalling message
- PTPMessageSignalling *sigMsg = new PTPMessageSignalling(this);
- if (sigMsg) {
- sigMsg->setintervals(PTPMessageSignalling::sigMsgInterval_NoSend, log_mean_sync_interval, PTPMessageSignalling::sigMsgInterval_NoSend);
- sigMsg->sendPort(this, NULL);
- delete sigMsg;
- }
-
- startSyncReceiptTimer((unsigned long long)
- (SYNC_RECEIPT_TIMEOUT_MULTIPLIER *
- ((double) pow((double)2, getSyncInterval()) *
- 1000000000.0)));
- }
- }
-
- break;
-
- case STATE_CHANGE_EVENT:
- if (!automotive_profile) { // BMCA is not active with Automotive Profile
- if ( clock->getPriority1() != 255 ) {
- int number_ports, j;
- PTPMessageAnnounce *EBest = NULL;
- char EBestClockIdentity[PTP_CLOCK_IDENTITY_LENGTH];
-
- IEEE1588Port **ports;
- clock->getPortList(number_ports, ports);
-
- /* Find EBest for all ports */
- j = 0;
- for (int i = 0; i < number_ports; ++i) {
- while (ports[j] == NULL)
- ++j;
- if (ports[j]->port_state == PTP_DISABLED
- || ports[j]->port_state == PTP_FAULTY) {
- continue;
- }
- if (EBest == NULL) {
- EBest = ports[j]->calculateERBest();
- } else {
- if (ports[j]->calculateERBest()->isBetterThan(EBest)) {
- EBest = ports[j]->calculateERBest();
- }
- }
- }
-
- /* Check if we've changed */
- {
-
- uint8_t LastEBestClockIdentity[PTP_CLOCK_IDENTITY_LENGTH];
- clock->getLastEBestIdentity().
- getIdentityString( LastEBestClockIdentity );
- EBest->getGrandmasterIdentity( EBestClockIdentity );
- if( memcmp( EBestClockIdentity, LastEBestClockIdentity,
- PTP_CLOCK_IDENTITY_LENGTH ) != 0 )
- {
- ClockIdentity newGM;
- changed_external_master = true;
- newGM.set((uint8_t *) EBestClockIdentity );
- clock->setLastEBestIdentity( newGM );
- } else {
- changed_external_master = false;
- }
- }
-
- if( clock->isBetterThan( EBest )) {
- // We're Grandmaster, set grandmaster info to me
- ClockIdentity clock_identity;
- unsigned char priority1;
- unsigned char priority2;
- ClockQuality clock_quality;
-
- clock_identity = getClock()->getClockIdentity();
- getClock()->setGrandmasterClockIdentity( clock_identity );
- priority1 = getClock()->getPriority1();
- getClock()->setGrandmasterPriority1( priority1 );
- priority2 = getClock()->getPriority2();
- getClock()->setGrandmasterPriority2( priority2 );
- clock_quality = getClock()->getClockQuality();
- getClock()->setGrandmasterClockQuality( clock_quality );
- }
-
- j = 0;
- for (int i = 0; i < number_ports; ++i) {
- while (ports[j] == NULL)
- ++j;
- if (ports[j]->port_state == PTP_DISABLED
- || ports[j]->port_state == PTP_FAULTY) {
- continue;
- }
- if (clock->isBetterThan(EBest)) {
- // We are the GrandMaster, all ports are master
- EBest = NULL; // EBest == NULL : we were grandmaster
- ports[j]->recommendState(PTP_MASTER,
- changed_external_master);
- } else {
- if( EBest == ports[j]->calculateERBest() ) {
- // The "best" Announce was recieved on this port
- ClockIdentity clock_identity;
- unsigned char priority1;
- unsigned char priority2;
- ClockQuality *clock_quality;
-
- ports[j]->recommendState
- ( PTP_SLAVE, changed_external_master );
-
- clock_identity = EBest->getGrandmasterClockIdentity();
- getClock()->setGrandmasterClockIdentity(clock_identity);
- priority1 = EBest->getGrandmasterPriority1();
- getClock()->setGrandmasterPriority1( priority1 );
- priority2 = EBest->getGrandmasterPriority2();
- getClock()->setGrandmasterPriority2( priority2 );
- clock_quality = EBest->getGrandmasterClockQuality();
- getClock()->setGrandmasterClockQuality(*clock_quality);
- } else {
- /* Otherwise we are the master because we have
- sync'd to a better clock */
- ports[j]->recommendState
- (PTP_MASTER, changed_external_master);
- }
- }
- }
- }
- }
- break;
-
- case LINKUP:
- if (automotive_profile) {
- GPTP_LOG_EXCEPTION("LINKUP");
- }
- else {
- GPTP_LOG_STATUS("LINKUP");
- }
-
- if (automotive_profile) {
- asCapable = true;
-
- setStationState(STATION_STATE_ETHERNET_READY);
- if (testMode) {
- APMessageTestStatus *testStatusMsg = new APMessageTestStatus(this);
- if (testStatusMsg) {
- testStatusMsg->sendPort(this);
- delete testStatusMsg;
- }
- }
-
- log_mean_sync_interval = initialLogSyncInterval;
- log_mean_announce_interval = 0;
- log_min_mean_pdelay_req_interval = initialLogPdelayReqInterval;
-
- if (!isGM) {
- // Send an initial signaling message
- PTPMessageSignalling *sigMsg = new PTPMessageSignalling(this);
- if (sigMsg) {
- sigMsg->setintervals(PTPMessageSignalling::sigMsgInterval_NoSend, log_mean_sync_interval, PTPMessageSignalling::sigMsgInterval_NoSend);
- sigMsg->sendPort(this, NULL);
- delete sigMsg;
- }
-
- startSyncReceiptTimer((unsigned long long)
- (SYNC_RECEIPT_TIMEOUT_MULTIPLIER *
- ((double) pow((double)2, getSyncInterval()) *
- 1000000000.0)));
- }
-
- // Reset Sync count and pdelay count
- setPdelayCount(0);
- setSyncCount(0);
-
- // Start AVB SYNC at 2. It will decrement after each sync. When it reaches 0 the Test Status message
- // can be sent
- if (isGM) {
- avbSyncState = 1;
- }
- else {
- avbSyncState = 2;
- }
-
- if (testMode) {
- linkUpCount++;
- }
- }
- this->timestamper_init();
- break;
-
- case LINKDOWN:
- if (automotive_profile) {
- GPTP_LOG_EXCEPTION("LINK DOWN");
- }
- else {
- GPTP_LOG_STATUS("LINK DOWN");
- }
- if (testMode) {
- linkDownCount++;
- }
- break;
-
- case ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES:
- case SYNC_RECEIPT_TIMEOUT_EXPIRES:
- {
- if (e == ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES) {
- incCounter_ieee8021AsPortStatAnnounceReceiptTimeouts();
- }
- else if (e == SYNC_RECEIPT_TIMEOUT_EXPIRES) {
- incCounter_ieee8021AsPortStatRxSyncReceiptTimeouts();
- }
- if (!automotive_profile) {
-
- if( clock->getPriority1() == 255 ) {
- // Restart timer
- if( e == ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES ) {
- clock->addEventTimerLocked
- (this, ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES,
- (ANNOUNCE_RECEIPT_TIMEOUT_MULTIPLIER*
- (unsigned long long)
- (pow((double)2,getAnnounceInterval())*
- 1000000000.0)));
- } else {
- startSyncReceiptTimer((unsigned long long)
- (SYNC_RECEIPT_TIMEOUT_MULTIPLIER *
- ((double) pow((double)2, getSyncInterval()) *
- 1000000000.0)));
- }
- }
-
- if (port_state == PTP_INITIALIZING
- || port_state == PTP_UNCALIBRATED
- || port_state == PTP_SLAVE
- || port_state == PTP_PRE_MASTER) {
- GPTP_LOG_STATUS(
- "*** %s Timeout Expired - Becoming Master",
- e == ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES ? "Announce" :
- "Sync" );
- {
- // We're Grandmaster, set grandmaster info to me
- ClockIdentity clock_identity;
- unsigned char priority1;
- unsigned char priority2;
- ClockQuality clock_quality;
-
- clock_identity = getClock()->getClockIdentity();
- getClock()->setGrandmasterClockIdentity( clock_identity );
- priority1 = getClock()->getPriority1();
- getClock()->setGrandmasterPriority1( priority1 );
- priority2 = getClock()->getPriority2();
- getClock()->setGrandmasterPriority2( priority2 );
- clock_quality = getClock()->getClockQuality();
- getClock()->setGrandmasterClockQuality( clock_quality );
- }
- port_state = PTP_MASTER;
- Timestamp system_time;
- Timestamp device_time;
-
- uint32_t local_clock, nominal_clock_rate;
-
- getDeviceTime(system_time, device_time,
- local_clock, nominal_clock_rate);
-
- (void) clock->calcLocalSystemClockRateDifference
- ( device_time, system_time );
-
- delete qualified_announce;
- qualified_announce = NULL;
-
- // Add timers for Announce and Sync, this is as close to immediately as we get
- if( clock->getPriority1() != 255) {
- clock->addEventTimerLocked
- ( this, SYNC_INTERVAL_TIMEOUT_EXPIRES, 16000000 );
- }
- startAnnounce();
- }
-
- }
- else {
- // Automotive Profile
- if (e == SYNC_RECEIPT_TIMEOUT_EXPIRES) {
- GPTP_LOG_EXCEPTION("SYNC receipt timeout");
-
- startSyncReceiptTimer((unsigned long long)
- (SYNC_RECEIPT_TIMEOUT_MULTIPLIER *
- ((double) pow((double)2, getSyncInterval()) *
- 1000000000.0)));
- }
- }
-
- }
-
- break;
- case PDELAY_INTERVAL_TIMEOUT_EXPIRES:
- GPTP_LOG_DEBUG("PDELAY_INTERVAL_TIMEOUT_EXPIRES occured");
- {
- int ts_good;
- Timestamp req_timestamp;
- int iter = TX_TIMEOUT_ITER;
- long req = TX_TIMEOUT_BASE;
- unsigned req_timestamp_counter_value;
- long long wait_time = 0;
-
- PTPMessagePathDelayReq *pdelay_req =
- new PTPMessagePathDelayReq(this);
- PortIdentity dest_id;
- getPortIdentity(dest_id);
- pdelay_req->setPortIdentity(&dest_id);
-
- {
- Timestamp pending =
- PDELAY_PENDING_TIMESTAMP;
- pdelay_req->setTimestamp(pending);
- }
-
- if (last_pdelay_req != NULL) {
- delete last_pdelay_req;
- }
- setLastPDelayReq(pdelay_req);
-
- getTxLock();
- pdelay_req->sendPort(this, NULL);
- GPTP_LOG_DEBUG("Sent PDelay Request");
-
- OSTimer *timer = timer_factory->createTimer();
-
- ts_good = getTxTimestamp
- (pdelay_req, req_timestamp, req_timestamp_counter_value, false);
- while (ts_good != GPTP_EC_SUCCESS && iter-- != 0) {
- timer->sleep(req);
- wait_time += req;
- if (ts_good != GPTP_EC_EAGAIN && iter < 1)
- GPTP_LOG_ERROR(
- "Error (TX) timestamping PDelay request "
- "(Retrying-%d), error=%d", iter, ts_good);
- ts_good =
- getTxTimestamp
- (pdelay_req, req_timestamp,
- req_timestamp_counter_value, iter == 0);
- req *= 2;
- }
- delete timer;
- putTxLock();
-
- if (ts_good == GPTP_EC_SUCCESS) {
- pdelay_req->setTimestamp(req_timestamp);
- } else {
- Timestamp failed = INVALID_TIMESTAMP;
- pdelay_req->setTimestamp(failed);
- GPTP_LOG_ERROR( "Invalid TX" );
- }
-
- if (ts_good != GPTP_EC_SUCCESS) {
- char msg
- [HWTIMESTAMPER_EXTENDED_MESSAGE_SIZE];
- getExtendedError(msg);
- GPTP_LOG_ERROR(
- "Error (TX) timestamping PDelay request, error=%d\t%s",
- ts_good, msg);
- }
-#ifdef DEBUG
- if (ts_good == GPTP_EC_SUCCESS) {
- GPTP_LOG_DEBUG
- ("Successful PDelay Req timestamp, %u,%u",
- req_timestamp.seconds_ls,
- req_timestamp.nanoseconds);
- } else {
- GPTP_LOG_DEBUG
- ("*** Unsuccessful PDelay Req timestamp");
- }
-#endif
-
- {
- long long timeout;
- long long interval;
-
- timeout = PDELAY_RESP_RECEIPT_TIMEOUT_MULTIPLIER *
- ((long long)
- (pow((double)2,getPDelayInterval())*1000000000.0)) -
- wait_time*1000;
- timeout = timeout > EVENT_TIMER_GRANULARITY ?
- timeout : EVENT_TIMER_GRANULARITY;
- clock->addEventTimerLocked
- (this, PDELAY_RESP_RECEIPT_TIMEOUT_EXPIRES, timeout );
-
- interval =
- ((long long)
- (pow((double)2,getPDelayInterval())*1000000000.0)) -
- wait_time*1000;
- interval = interval > EVENT_TIMER_GRANULARITY ?
- interval : EVENT_TIMER_GRANULARITY;
- startPDelayIntervalTimer(interval);
- }
- }
- break;
- case SYNC_INTERVAL_TIMEOUT_EXPIRES:
- GPTP_LOG_DEBUG("SYNC_INTERVAL_TIMEOUT_EXPIRES occured");
- {
- /* Set offset from master to zero, update device vs
- system time offset */
- Timestamp system_time;
- Timestamp device_time;
- FrequencyRatio local_system_freq_offset;
- int64_t local_system_offset;
- long long wait_time = 0;
-
- uint32_t local_clock, nominal_clock_rate;
-
- // Send a sync message and then a followup to broadcast
- if (asCapable) {
- PTPMessageSync *sync = new PTPMessageSync(this);
- PortIdentity dest_id;
- getPortIdentity(dest_id);
- sync->setPortIdentity(&dest_id);
- getTxLock();
- sync->sendPort(this, NULL);
- GPTP_LOG_DEBUG("Sent SYNC message");
-
- if (automotive_profile && port_state == PTP_MASTER) {
- if (avbSyncState > 0) {
- avbSyncState--;
- if (avbSyncState == 0) {
- // Send Avnu Automotive Profile status message
- setStationState(STATION_STATE_AVB_SYNC);
- if (testMode) {
- APMessageTestStatus *testStatusMsg = new APMessageTestStatus(this);
- if (testStatusMsg) {
- testStatusMsg->sendPort(this);
- delete testStatusMsg;
- }
- }
- }
- }
- }
-
- int ts_good;
- Timestamp sync_timestamp;
- unsigned sync_timestamp_counter_value;
- int iter = TX_TIMEOUT_ITER;
- long req = TX_TIMEOUT_BASE;
-
- OSTimer *timer = timer_factory->createTimer();
-
- ts_good =
- getTxTimestamp(sync, sync_timestamp,
- sync_timestamp_counter_value,
- false);
- while (ts_good != GPTP_EC_SUCCESS && iter-- != 0) {
- timer->sleep(req);
- wait_time += req;
-
- if (ts_good != GPTP_EC_EAGAIN && iter < 1)
- GPTP_LOG_ERROR(
- "Error (TX) timestamping Sync (Retrying), "
- "error=%d", ts_good);
- ts_good =
- getTxTimestamp
- (sync, sync_timestamp,
- sync_timestamp_counter_value, iter == 0);
- req *= 2;
- }
- delete timer;
- putTxLock();
-
- if (ts_good != GPTP_EC_SUCCESS) {
- char msg [HWTIMESTAMPER_EXTENDED_MESSAGE_SIZE];
- getExtendedError(msg);
- GPTP_LOG_ERROR(
- "Error (TX) timestamping Sync, error="
- "%d\n%s",
- ts_good, msg );
- }
-
- if (ts_good == GPTP_EC_SUCCESS) {
- GPTP_LOG_VERBOSE("Successful Sync timestamp");
- GPTP_LOG_VERBOSE("Seconds: %u",
- sync_timestamp.seconds_ls);
- GPTP_LOG_VERBOSE("Nanoseconds: %u",
- sync_timestamp.nanoseconds);
- } else {
- GPTP_LOG_ERROR
- ("*** Unsuccessful Sync timestamp");
- }
-
- PTPMessageFollowUp *follow_up;
- if (ts_good == GPTP_EC_SUCCESS) {
-
- follow_up =
- new PTPMessageFollowUp(this);
- PortIdentity dest_id;
- getPortIdentity(dest_id);
-
- follow_up->setClockSourceTime(getClock()->getFUPInfo());
- follow_up->setPortIdentity(&dest_id);
- follow_up->setSequenceId(sync->getSequenceId());
- follow_up->setPreciseOriginTimestamp(sync_timestamp);
- follow_up->sendPort(this, NULL);
- delete follow_up;
- } else {
- }
- delete sync;
- }
- /* Do getDeviceTime() after transmitting sync frame
- causing an update to local/system timestamp */
- getDeviceTime
- (system_time, device_time, local_clock, nominal_clock_rate);
-
- GPTP_LOG_VERBOSE
- ("port::processEvent(): System time: %u,%u Device Time: %u,%u",
- system_time.seconds_ls, system_time.nanoseconds,
- device_time.seconds_ls, device_time.nanoseconds);
-
- local_system_offset =
- TIMESTAMP_TO_NS(system_time) -
- TIMESTAMP_TO_NS(device_time);
- local_system_freq_offset =
- clock->calcLocalSystemClockRateDifference
- ( device_time, system_time );
- clock->setMasterOffset
- (this, 0, device_time, 1.0, local_system_offset,
- system_time, local_system_freq_offset, sync_count,
- pdelay_count, port_state, asCapable );
-
- if (!automotive_profile) {
- /* If accelerated_sync is non-zero then start 16 ms sync
- timer, subtract 1, for last one start PDelay also */
- if( _accelerated_sync_count > 0 ) {
- clock->addEventTimerLocked
- ( this, SYNC_INTERVAL_TIMEOUT_EXPIRES, 8000000 );
- --_accelerated_sync_count;
- } else {
- syncDone();
- if( _accelerated_sync_count == 0 ) {
- --_accelerated_sync_count;
- }
- wait_time *= 1000; // to ns
- wait_time =
- ((long long)
- (pow((double)2,getSyncInterval())*1000000000.0)) -
- wait_time;
- wait_time = wait_time > EVENT_TIMER_GRANULARITY ? wait_time :
- EVENT_TIMER_GRANULARITY;
- startSyncIntervalTimer(wait_time);
- }
- }
- else {
- // Automotive Profile
- syncDone();
-
- wait_time = ((long long) (pow((double)2, getSyncInterval()) * 1000000000.0));
- wait_time = wait_time > EVENT_TIMER_GRANULARITY ? wait_time : EVENT_TIMER_GRANULARITY;
- startSyncIntervalTimer(wait_time);
- }
-
- }
- break;
- case ANNOUNCE_INTERVAL_TIMEOUT_EXPIRES:
- if (asCapable) {
- // Send an announce message
- PTPMessageAnnounce *annc = new PTPMessageAnnounce(this);
- PortIdentity dest_id;
- PortIdentity gmId;
- ClockIdentity clock_id = clock->getClockIdentity();
- gmId.setClockIdentity(clock_id);
- getPortIdentity(dest_id);
- annc->setPortIdentity(&dest_id);
- annc->sendPort(this, NULL);
- delete annc;
- }
- startAnnounceIntervalTimer(pow((double)2, getAnnounceInterval()) * 1000000000.0);
- break;
- case FAULT_DETECTED:
- GPTP_LOG_ERROR("Received FAULT_DETECTED event");
- if (!automotive_profile) {
- setAsCapable(false);
- }
- break;
- case PDELAY_DEFERRED_PROCESSING:
- pdelay_rx_lock->lock();
- if (last_pdelay_resp_fwup == NULL) {
- GPTP_LOG_ERROR("PDelay Response Followup is NULL!");
- abort();
- }
- last_pdelay_resp_fwup->processMessage(this);
- if (last_pdelay_resp_fwup->garbage()) {
- delete last_pdelay_resp_fwup;
- this->setLastPDelayRespFollowUp(NULL);
- }
- pdelay_rx_lock->unlock();
- break;
- case PDELAY_RESP_RECEIPT_TIMEOUT_EXPIRES:
- if (!automotive_profile) {
- GPTP_LOG_EXCEPTION("PDelay Response Receipt Timeout");
- setAsCapable(false);
- }
- pdelay_count = 0;
- break;
-
- case PDELAY_RESP_PEER_MISBEHAVING_TIMEOUT_EXPIRES:
- GPTP_LOG_EXCEPTION("PDelay Resp Peer Misbehaving timeout expired! Restarting PDelay");
-
- haltPdelay(false);
- if( port_state != PTP_SLAVE && port_state != PTP_MASTER ) {
- GPTP_LOG_STATUS("Starting PDelay" );
- startPDelay();
- }
- break;
- case SYNC_RATE_INTERVAL_TIMEOUT_EXPIRED:
- {
- GPTP_LOG_INFO("SYNC_RATE_INTERVAL_TIMEOUT_EXPIRED occured");
-
- sync_rate_interval_timer_started = false;
-
- bool sendSignalMessage = false;
- if (log_mean_sync_interval != operLogSyncInterval) {
- log_mean_sync_interval = operLogSyncInterval;
- sendSignalMessage = true;
- }
-
- if (log_min_mean_pdelay_req_interval != operLogPdelayReqInterval) {
- log_min_mean_pdelay_req_interval = operLogPdelayReqInterval;
- sendSignalMessage = true;
- }
-
- if (sendSignalMessage) {
- if (!isGM) {
- // Send operational signalling message
- PTPMessageSignalling *sigMsg = new PTPMessageSignalling(this);
- if (sigMsg) {
- if (automotive_profile)
- sigMsg->setintervals(PTPMessageSignalling::sigMsgInterval_NoChange, log_mean_sync_interval, PTPMessageSignalling::sigMsgInterval_NoChange);
- else
- sigMsg->setintervals(log_min_mean_pdelay_req_interval, log_mean_sync_interval, PTPMessageSignalling::sigMsgInterval_NoChange);
- sigMsg->sendPort(this, NULL);
- delete sigMsg;
- }
-
- startSyncReceiptTimer((unsigned long long)
- (SYNC_RECEIPT_TIMEOUT_MULTIPLIER *
- ((double) pow((double)2, getSyncInterval()) *
- 1000000000.0)));
- }
- }
- }
-
- break;
- default:
- GPTP_LOG_ERROR
- ("Unhandled event type in IEEE1588Port::processEvent(), %d",
- e);
- break;
- }
-
- return;
-}
-
-PTPMessageAnnounce *IEEE1588Port::calculateERBest(void)
-{
- return qualified_announce;
-}
-
-void IEEE1588Port::recoverPort(void)
-{
- return;
-}
-
-IEEE1588Clock *IEEE1588Port::getClock(void)
-{
- return clock;
-}
-
-void IEEE1588Port::getDeviceTime
-(Timestamp & system_time, Timestamp & device_time,
- uint32_t & local_clock, uint32_t & nominal_clock_rate)
-{
- if (_hw_timestamper) {
- _hw_timestamper->HWTimestamper_gettime
- (&system_time, &device_time, &local_clock, &nominal_clock_rate);
- } else {
- device_time = system_time = clock->getSystemTime();
- local_clock = nominal_clock_rate = 0;
- }
- return;
-}
-
-void IEEE1588Port::becomeMaster( bool annc ) {
- port_state = PTP_MASTER;
- // Stop announce receipt timeout timer
- clock->deleteEventTimerLocked( this, ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES );
-
- // Stop sync receipt timeout timer
- stopSyncReceiptTimer();
-
- if( annc ) {
- if (!automotive_profile) {
- startAnnounce();
- }
- }
- startSyncIntervalTimer(16000000);
- GPTP_LOG_STATUS("Switching to Master" );
-
- clock->updateFUPInfo();
-
- return;
-}
-
-void IEEE1588Port::becomeSlave( bool restart_syntonization ) {
- clock->deleteEventTimerLocked( this, ANNOUNCE_INTERVAL_TIMEOUT_EXPIRES );
- clock->deleteEventTimerLocked( this, SYNC_INTERVAL_TIMEOUT_EXPIRES );
-
- port_state = PTP_SLAVE;
-
- if (!automotive_profile) {
- clock->addEventTimerLocked
- (this, ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES,
- (ANNOUNCE_RECEIPT_TIMEOUT_MULTIPLIER*
- (unsigned long long)
- (pow((double)2,getAnnounceInterval())*1000000000.0)));
- }
-
- GPTP_LOG_STATUS("Switching to Slave" );
- if( restart_syntonization ) clock->newSyntonizationSetPoint();
-
- getClock()->updateFUPInfo();
-
- return;
-}
-
-void IEEE1588Port::recommendState
-( PortState state, bool changed_external_master )
-{
- bool reset_sync = false;
- switch (state) {
- case PTP_MASTER:
- if (port_state != PTP_MASTER) {
- port_state = PTP_MASTER;
- // Start announce receipt timeout timer
- // Start sync receipt timeout timer
- becomeMaster( true );
- reset_sync = true;
- }
- break;
- case PTP_SLAVE:
- if (port_state != PTP_SLAVE) {
- becomeSlave( true );
- reset_sync = true;
- } else {
- if( changed_external_master ) {
- GPTP_LOG_STATUS("Changed master!" );
- clock->newSyntonizationSetPoint();
- getClock()->updateFUPInfo();
- reset_sync = true;
- }
- }
- break;
- default:
- GPTP_LOG_ERROR
- ("Invalid state change requested by call to "
- "1588Port::recommendState()");
- break;
- }
- if( reset_sync ) sync_count = 0;
- return;
- }
-
-void IEEE1588Port::mapSocketAddr
-(PortIdentity * destIdentity, LinkLayerAddress * remote)
-{
- *remote = identity_map[*destIdentity];
- return;
-}
-
-void IEEE1588Port::addSockAddrMap
-(PortIdentity * destIdentity, LinkLayerAddress * remote)
-{
- identity_map[*destIdentity] = *remote;
- return;
-}
-
-int IEEE1588Port::getTxTimestamp
-(PTPMessageCommon * msg, Timestamp & timestamp, unsigned &counter_value,
- bool last)
-{
- PortIdentity identity;
- msg->getPortIdentity(&identity);
- return getTxTimestamp
- (&identity, msg->getSequenceId(), timestamp, counter_value, last);
-}
-
-int IEEE1588Port::getRxTimestamp(PTPMessageCommon * msg, Timestamp & timestamp,
- unsigned &counter_value, bool last)
-{
- PortIdentity identity;
- msg->getPortIdentity(&identity);
- return getRxTimestamp
- (&identity, msg->getSequenceId(), timestamp, counter_value, last);
-}
-
-int IEEE1588Port::getTxTimestamp(PortIdentity * sourcePortIdentity,
- uint16_t sequenceId, Timestamp & timestamp,
- unsigned &counter_value, bool last)
-{
- if (_hw_timestamper) {
- return _hw_timestamper->HWTimestamper_txtimestamp
- (sourcePortIdentity, sequenceId, timestamp, counter_value,
- last);
- }
- timestamp = clock->getSystemTime();
- return 0;
-}
-
-int IEEE1588Port::getRxTimestamp(PortIdentity * sourcePortIdentity,
- uint16_t sequenceId, Timestamp & timestamp,
- unsigned &counter_value, bool last)
-{
- if (_hw_timestamper) {
- return _hw_timestamper->HWTimestamper_rxtimestamp
- (sourcePortIdentity, sequenceId, timestamp, counter_value,
- last);
- }
- timestamp = clock->getSystemTime();
- return 0;
-}
-
-void IEEE1588Port::startSyncReceiptTimer(long long unsigned int waitTime) {
- syncReceiptTimerLock->lock();
- clock->deleteEventTimerLocked(this, SYNC_RECEIPT_TIMEOUT_EXPIRES);
- clock->addEventTimerLocked(this, SYNC_RECEIPT_TIMEOUT_EXPIRES, waitTime);
- syncReceiptTimerLock->unlock();
-}
-
-void IEEE1588Port::stopSyncReceiptTimer(void)
-{
- syncReceiptTimerLock->lock();
- clock->deleteEventTimerLocked(this, SYNC_RECEIPT_TIMEOUT_EXPIRES);
- syncReceiptTimerLock->unlock();
-}
-
-void IEEE1588Port::startSyncIntervalTimer(long long unsigned int waitTime)
-{
- syncIntervalTimerLock->lock();
- clock->deleteEventTimerLocked(this, SYNC_INTERVAL_TIMEOUT_EXPIRES);
- clock->addEventTimerLocked(this, SYNC_INTERVAL_TIMEOUT_EXPIRES, waitTime);
- syncIntervalTimerLock->unlock();
-}
-
-void IEEE1588Port::startAnnounceIntervalTimer(long long unsigned int waitTime)
-{
- announceIntervalTimerLock->lock();
- clock->deleteEventTimerLocked(this, ANNOUNCE_INTERVAL_TIMEOUT_EXPIRES);
- clock->addEventTimerLocked(this, ANNOUNCE_INTERVAL_TIMEOUT_EXPIRES, waitTime);
- announceIntervalTimerLock->unlock();
-}
-
-void IEEE1588Port::startPDelayIntervalTimer(long long unsigned int waitTime)
-{
- pDelayIntervalTimerLock->lock();
- clock->deleteEventTimerLocked(this, PDELAY_INTERVAL_TIMEOUT_EXPIRES);
- clock->addEventTimerLocked(this, PDELAY_INTERVAL_TIMEOUT_EXPIRES, waitTime);
- pDelayIntervalTimerLock->unlock();
-}
-
diff --git a/daemons/gptp/common/ipcdef.hpp b/daemons/gptp/common/ipcdef.hpp
index 2770fe06..670aeeed 100644
--- a/daemons/gptp/common/ipcdef.hpp
+++ b/daemons/gptp/common/ipcdef.hpp
@@ -66,16 +66,37 @@
* @brief Provides a data structure for gPTP time
*/
typedef struct {
- int64_t ml_phoffset; //!< Master to local phase offset
- int64_t ls_phoffset; //!< Local to system phase offset
- FrequencyRatio ml_freqoffset; //!< Master to local frequency offset
- FrequencyRatio ls_freqoffset; //!< Local to system frequency offset
- uint64_t local_time; //!< Local time of last update
- uint32_t sync_count; //!< Sync messages count
- uint32_t pdelay_count; //!< pdelay messages count
- bool asCapable; //!< asCapable flag: true = device is AS Capable; false otherwise
- PortState port_state; //!< gPTP port state. It can assume values defined at ::PortState
- PID_TYPE process_id; //!< Process id number
+ int64_t ml_phoffset; //!< Master to local phase offset
+ int64_t ls_phoffset; //!< Local to system phase offset
+ FrequencyRatio ml_freqoffset; //!< Master to local frequency offset
+ FrequencyRatio ls_freqoffset; //!< Local to system frequency offset
+ uint64_t local_time; //!< Local time of last update
+
+ /* Current grandmaster information */
+ /* Referenced by the IEEE Std 1722.1-2013 AVDECC Discovery Protocol Data Unit (ADPDU) */
+ uint8_t gptp_grandmaster_id[PTP_CLOCK_IDENTITY_LENGTH]; //!< Current grandmaster id (all 0's if no grandmaster selected)
+ uint8_t gptp_domain_number; //!< gPTP domain number
+
+ /* Grandmaster support for the network interface */
+ /* Referenced by the IEEE Std 1722.1-2013 AVDECC AVB_INTERFACE descriptor */
+ uint8_t clock_identity[PTP_CLOCK_IDENTITY_LENGTH]; //!< The clock identity of the interface
+ uint8_t priority1; //!< The priority1 field of the grandmaster functionality of the interface, or 0xFF if not supported
+ uint8_t clock_class; //!< The clockClass field of the grandmaster functionality of the interface, or 0xFF if not supported
+ int16_t offset_scaled_log_variance; //!< The offsetScaledLogVariance field of the grandmaster functionality of the interface, or 0x0000 if not supported
+ uint8_t clock_accuracy; //!< The clockAccuracy field of the grandmaster functionality of the interface, or 0xFF if not supported
+ uint8_t priority2; //!< The priority2 field of the grandmaster functionality of the interface, or 0xFF if not supported
+ uint8_t domain_number; //!< The domainNumber field of the grandmaster functionality of the interface, or 0 if not supported
+ int8_t log_sync_interval; //!< The currentLogSyncInterval field of the grandmaster functionality of the interface, or 0 if not supported
+ int8_t log_announce_interval; //!< The currentLogAnnounceInterval field of the grandmaster functionality of the interface, or 0 if not supported
+ int8_t log_pdelay_interval; //!< The currentLogPDelayReqInterval field of the grandmaster functionality of the interface, or 0 if not supported
+ uint16_t port_number; //!< The portNumber field of the interface, or 0x0000 if not supported
+
+ /* Linux-specific */
+ uint32_t sync_count; //!< Sync messages count
+ uint32_t pdelay_count; //!< pdelay messages count
+ bool asCapable; //!< asCapable flag: true = device is AS Capable; false otherwise
+ PortState port_state; //!< gPTP port state. It can assume values defined at ::PortState
+ PID_TYPE process_id; //!< Process id number
} gPtpTimeData;
/*
diff --git a/daemons/gptp/common/ptp_message.cpp b/daemons/gptp/common/ptp_message.cpp
index 694f284c..9219338b 100644
--- a/daemons/gptp/common/ptp_message.cpp
+++ b/daemons/gptp/common/ptp_message.cpp
@@ -34,14 +34,15 @@
#include <ieee1588.hpp>
#include <avbts_clock.hpp>
#include <avbts_message.hpp>
-#include <avbts_port.hpp>
+#include <ether_port.hpp>
#include <avbts_ostimer.hpp>
+#include <ether_tstamper.hpp>
#include <stdio.h>
#include <string.h>
#include <math.h>
-PTPMessageCommon::PTPMessageCommon(IEEE1588Port * port)
+PTPMessageCommon::PTPMessageCommon( CommonPort *port )
{
// Fill in fields using port/clock dataset as a template
versionPTP = GPTP_VERSION;
@@ -65,10 +66,12 @@ bool PTPMessageCommon::isSenderEqual(PortIdentity portIdentity)
}
PTPMessageCommon *buildPTPMessage
-(char *buf, int size, LinkLayerAddress * remote, IEEE1588Port * port)
+( char *buf, int size, LinkLayerAddress *remote,
+ EtherPort *port )
{
OSTimer *timer = port->getTimerFactory()->createTimer();
PTPMessageCommon *msg = NULL;
+ PTPMessageId messageId;
MessageType messageType;
unsigned char tspec_msg_t = 0;
unsigned char transportSpecific = 0;
@@ -113,13 +116,16 @@ PTPMessageCommon *buildPTPMessage
sequenceId = PLAT_ntohs(sequenceId);
GPTP_LOG_VERBOSE("Captured Sequence Id: %u", sequenceId);
+ messageId.setMessageType(messageType);
+ messageId.setSequenceId(sequenceId);
+
if (!(messageType >> 3)) {
int iter = 5;
long req = 4000; // = 1 ms
int ts_good =
port->getRxTimestamp
- (sourcePortIdentity, sequenceId, timestamp, counter_value, false);
+ (sourcePortIdentity, messageId, timestamp, counter_value, false);
while (ts_good != GPTP_EC_SUCCESS && iter-- != 0) {
// Waits at least 1 time slice regardless of size of 'req'
timer->sleep(req);
@@ -128,14 +134,14 @@ PTPMessageCommon *buildPTPMessage
"Error (RX) timestamping RX event packet (Retrying), error=%d",
ts_good );
ts_good =
- port->getRxTimestamp(sourcePortIdentity, sequenceId,
+ port->getRxTimestamp(sourcePortIdentity, messageId,
timestamp, counter_value,
iter == 0);
req *= 2;
}
if (ts_good != GPTP_EC_SUCCESS) {
- char msg[HWTIMESTAMPER_EXTENDED_MESSAGE_SIZE];
- port->getExtendedError(msg);
+ char err_msg[HWTIMESTAMPER_EXTENDED_MESSAGE_SIZE];
+ port->getExtendedError(err_msg);
GPTP_LOG_ERROR
("*** Received an event packet but cannot retrieve timestamp, discarding. messageType=%u,error=%d\n%s",
messageType, ts_good, msg);
@@ -157,7 +163,7 @@ PTPMessageCommon *buildPTPMessage
switch (messageType) {
case SYNC_MESSAGE:
- GPTP_LOG_DEBUG("*** Received Sync message\n" );
+ GPTP_LOG_DEBUG("*** Received Sync message" );
GPTP_LOG_VERBOSE("Sync RX timestamp = %hu,%u,%u", timestamp.seconds_ms, timestamp.seconds_ls, timestamp.nanoseconds );
// Be sure buffer is the correction size
@@ -279,7 +285,7 @@ PTPMessageCommon *buildPTPMessage
break;
case PATH_DELAY_RESP_MESSAGE:
- GPTP_LOG_DEBUG("*** Received PDelay Response message, %u, %u, %u",
+ GPTP_LOG_DEBUG("*** Received PDelay Response message, Timestamp %u (sec) %u (ns), seqID %u",
timestamp.seconds_ls, timestamp.nanoseconds,
sequenceId);
@@ -537,7 +543,51 @@ abort:
return NULL;
}
-void PTPMessageCommon::processMessage(IEEE1588Port * port)
+bool PTPMessageCommon::getTxTimestamp( EtherPort *port, uint32_t link_speed )
+{
+ OSTimer *timer = port->getTimerFactory()->createTimer();
+ int ts_good;
+ Timestamp tx_timestamp;
+ uint32_t unused;
+ unsigned req = TX_TIMEOUT_BASE;
+ int iter = TX_TIMEOUT_ITER;
+
+ ts_good = port->getTxTimestamp
+ ( this, tx_timestamp, unused, false );
+ while( ts_good != GPTP_EC_SUCCESS && iter-- != 0 )
+ {
+ timer->sleep(req);
+ if (ts_good != GPTP_EC_EAGAIN && iter < 1)
+ GPTP_LOG_ERROR(
+ "Error (TX) timestamping PDelay request "
+ "(Retrying-%d), error=%d", iter, ts_good);
+ ts_good = port->getTxTimestamp
+ ( this, tx_timestamp, unused , iter == 0 );
+ req *= 2;
+ }
+
+ if( ts_good == GPTP_EC_SUCCESS )
+ {
+ Timestamp phy_compensation = port->getTxPhyDelay( link_speed );
+ GPTP_LOG_DEBUG( "TX PHY compensation: %s sec",
+ phy_compensation.toString().c_str() );
+ phy_compensation._version = tx_timestamp._version;
+ _timestamp = tx_timestamp + phy_compensation;
+ } else
+ {
+ char msg[HWTIMESTAMPER_EXTENDED_MESSAGE_SIZE];
+ port->getExtendedError(msg);
+ GPTP_LOG_ERROR(
+ "Error (TX) timestamping PDelay request, error=%d\t%s",
+ ts_good, msg);
+ _timestamp = INVALID_TIMESTAMP;
+ }
+
+ delete timer;
+ return ts_good == GPTP_EC_SUCCESS;
+}
+
+void PTPMessageCommon::processMessage( EtherPort *port )
{
_gc = true;
return;
@@ -661,7 +711,8 @@ PTPMessageSync::PTPMessageSync() {
PTPMessageSync::~PTPMessageSync() {
}
-PTPMessageSync::PTPMessageSync(IEEE1588Port * port) : PTPMessageCommon(port)
+PTPMessageSync::PTPMessageSync( EtherPort *port ) :
+ PTPMessageCommon( port )
{
messageType = SYNC_MESSAGE; // This is an event message
sequenceId = port->getNextSyncSequenceId();
@@ -675,12 +726,15 @@ PTPMessageSync::PTPMessageSync(IEEE1588Port * port) : PTPMessageCommon(port)
return;
}
-void PTPMessageSync::sendPort(IEEE1588Port * port, PortIdentity * destIdentity)
+bool PTPMessageSync::sendPort
+( EtherPort *port, PortIdentity *destIdentity )
{
uint8_t buf_t[256];
uint8_t *buf_ptr = buf_t + port->getPayloadOffset();
unsigned char tspec_msg_t = 0x0;
Timestamp originTimestamp_BE;
+ uint32_t link_speed;
+
memset(buf_t, 0, 256);
// Create packet in buf
// Copy in common header
@@ -704,14 +758,16 @@ void PTPMessageSync::sendPort(IEEE1588Port * port, PortIdentity * destIdentity)
&(originTimestamp_BE.nanoseconds),
sizeof(originTimestamp.nanoseconds));
- port->sendEventPort(PTP_ETHERTYPE, buf_t, messageLength, MCAST_OTHER, destIdentity);
+ port->sendEventPort
+ ( PTP_ETHERTYPE, buf_t, messageLength, MCAST_OTHER,
+ destIdentity, &link_speed );
port->incCounter_ieee8021AsPortStatTxSyncCount();
- return;
+ return getTxTimestamp( port, link_speed );
}
- PTPMessageAnnounce::PTPMessageAnnounce(IEEE1588Port * port) : PTPMessageCommon
- (port)
+PTPMessageAnnounce::PTPMessageAnnounce( CommonPort *port ) :
+ PTPMessageCommon( port )
{
messageType = ANNOUNCE_MESSAGE; // This is an event message
sequenceId = port->getNextAnnounceSequenceId();
@@ -736,8 +792,8 @@ void PTPMessageSync::sendPort(IEEE1588Port * port, PortIdentity * destIdentity)
return;
}
-void PTPMessageAnnounce::sendPort(IEEE1588Port * port,
- PortIdentity * destIdentity)
+bool PTPMessageAnnounce::sendPort
+( CommonPort *port, PortIdentity *destIdentity )
{
uint8_t buf_t[256];
uint8_t *buf_ptr = buf_t + port->getPayloadOffset();
@@ -779,10 +835,10 @@ void PTPMessageAnnounce::sendPort(IEEE1588Port * port,
port->sendGeneralPort(PTP_ETHERTYPE, buf_t, messageLength, MCAST_OTHER, destIdentity);
port->incCounter_ieee8021AsPortStatTxAnnounce();
- return;
+ return true;
}
-void PTPMessageAnnounce::processMessage(IEEE1588Port * port)
+void PTPMessageAnnounce::processMessage( EtherPort *port )
{
ClockIdentity my_clock_identity;
@@ -805,7 +861,7 @@ void PTPMessageAnnounce::processMessage(IEEE1588Port * port)
}
// Add message to the list
- port->addQualifiedAnnounce(this);
+ port->setQualifiedAnnounce( this );
port->getClock()->addEventTimerLocked(port, STATE_CHANGE_EVENT, 16000000);
bail:
@@ -819,7 +875,7 @@ void PTPMessageAnnounce::processMessage(IEEE1588Port * port)
1000000000.0)));
}
-void PTPMessageSync::processMessage(IEEE1588Port * port)
+void PTPMessageSync::processMessage( EtherPort *port )
{
if (port->getPortState() == PTP_DISABLED ) {
// Do nothing Sync messages should be ignored when in this state
@@ -833,7 +889,9 @@ void PTPMessageSync::processMessage(IEEE1588Port * port)
port->incCounter_ieee8021AsPortStatRxSyncCount();
+#if CHECK_ASSIST_BIT
if( flags[PTP_ASSIST_BYTE] & (0x1<<PTP_ASSIST_BIT)) {
+#endif
PTPMessageSync *old_sync = port->getLastSync();
if (old_sync != NULL) {
@@ -842,18 +900,20 @@ void PTPMessageSync::processMessage(IEEE1588Port * port)
port->setLastSync(this);
_gc = false;
goto done;
+#if CHECK_ASSIST_BIT
} else {
GPTP_LOG_ERROR("PTP assist flag is not set, discarding invalid sync");
_gc = true;
goto done;
}
+#endif
done:
return;
}
- PTPMessageFollowUp::PTPMessageFollowUp(IEEE1588Port * port):PTPMessageCommon
- (port)
+PTPMessageFollowUp::PTPMessageFollowUp( EtherPort *port ) :
+ PTPMessageCommon( port )
{
messageType = FOLLOWUP_MESSAGE; /* This is an event message */
control = FOLLOWUP;
@@ -863,8 +923,8 @@ void PTPMessageSync::processMessage(IEEE1588Port * port)
return;
}
-void PTPMessageFollowUp::sendPort(IEEE1588Port * port,
- PortIdentity * destIdentity)
+bool PTPMessageFollowUp::sendPort
+( EtherPort *port, PortIdentity *destIdentity )
{
uint8_t buf_t[256];
uint8_t *buf_ptr = buf_t + port->getPayloadOffset();
@@ -920,10 +980,10 @@ void PTPMessageFollowUp::sendPort(IEEE1588Port * port,
port->incCounter_ieee8021AsPortStatTxFollowUpCount();
- return;
+ return true;
}
-void PTPMessageFollowUp::processMessage(IEEE1588Port * port)
+void PTPMessageFollowUp::processMessage( EtherPort *port )
{
uint64_t delay;
Timestamp sync_arrival;
@@ -1002,15 +1062,28 @@ void PTPMessageFollowUp::processMessage(IEEE1588Port * port)
if( correction > 0 )
TIMESTAMP_ADD_NS( preciseOriginTimestamp, correction );
else TIMESTAMP_SUB_NS( preciseOriginTimestamp, -correction );
+
+ local_clock_adjustment =
+ port->getClock()->
+ calcMasterLocalClockRateDifference
+ ( preciseOriginTimestamp, sync_arrival );
+
+ if( local_clock_adjustment == NEGATIVE_TIME_JUMP )
+ {
+ GPTP_LOG_VERBOSE("Received Follow Up but preciseOrigintimestamp indicates negative time jump");
+ goto done;
+ }
+
scalar_offset = TIMESTAMP_TO_NS( sync_arrival );
scalar_offset -= TIMESTAMP_TO_NS( preciseOriginTimestamp );
GPTP_LOG_VERBOSE
- ("Followup Correction Field: %Ld,%lu", correctionField >> 16,
+ ("Followup Correction Field: %Ld, Link Delay: %lu", correctionField,
delay);
GPTP_LOG_VERBOSE
("FollowUp Scalar = %lld", scalar_offset);
+
/* Otherwise synchronize clock with approximate time from Sync message */
uint32_t local_clock, nominal_clock_rate;
uint32_t device_sync_time_offset;
@@ -1023,7 +1096,7 @@ void PTPMessageFollowUp::processMessage(IEEE1588Port * port)
/* Adjust local_clock to correspond to sync_arrival */
device_sync_time_offset =
- TIMESTAMP_TO_NS(device_time) - TIMESTAMP_TO_NS(sync_arrival);
+ (uint32_t) (TIMESTAMP_TO_NS(device_time) - TIMESTAMP_TO_NS(sync_arrival));
GPTP_LOG_VERBOSE
("ptp_message::FollowUp::processMessage System time: %u,%u "
@@ -1031,11 +1104,6 @@ void PTPMessageFollowUp::processMessage(IEEE1588Port * port)
system_time.seconds_ls, system_time.nanoseconds,
device_time.seconds_ls, device_time.nanoseconds);
- local_clock_adjustment =
- port->getClock()->
- calcMasterLocalClockRateDifference
- ( preciseOriginTimestamp, sync_arrival );
-
/*Update information on local status structure.*/
scaledLastGmFreqChange = (int32_t)((1.0/local_clock_adjustment -1.0) * (1ULL << 41));
scaledLastGmPhaseChange.setLSB( tlv.getRateOffset() );
@@ -1092,8 +1160,8 @@ done:
return;
}
- PTPMessagePathDelayReq::PTPMessagePathDelayReq(IEEE1588Port * port):
- PTPMessageCommon (port)
+PTPMessagePathDelayReq::PTPMessagePathDelayReq
+( EtherPort *port ) : PTPMessageCommon( port )
{
logMeanMessageInterval = 0;
control = MESSAGE_OTHER;
@@ -1102,7 +1170,7 @@ done:
return;
}
-void PTPMessagePathDelayReq::processMessage(IEEE1588Port * port)
+void PTPMessagePathDelayReq::processMessage( EtherPort *port )
{
OSTimer *timer = port->getTimerFactory()->createTimer();
PortIdentity resp_fwup_id;
@@ -1111,12 +1179,6 @@ void PTPMessagePathDelayReq::processMessage(IEEE1588Port * port)
PortIdentity resp_id;
PTPMessagePathDelayRespFollowUp *resp_fwup;
- int ts_good;
- Timestamp resp_timestamp;
- unsigned resp_timestamp_counter_value;
- unsigned req = TX_TIMEOUT_BASE;
- int iter = TX_TIMEOUT_ITER;
-
if (port->getPortState() == PTP_DISABLED) {
// Do nothing all messages should be ignored when in this state
goto done;
@@ -1147,41 +1209,15 @@ void PTPMessagePathDelayReq::processMessage(IEEE1588Port * port)
this->getPortIdentity(&requestingPortIdentity_p);
resp->setRequestingPortIdentity(&requestingPortIdentity_p);
resp->setRequestReceiptTimestamp(_timestamp);
+
port->getTxLock();
resp->sendPort(port, sourcePortIdentity);
-
- GPTP_LOG_DEBUG("Sent path delay response");
-
- GPTP_LOG_VERBOSE("Start TS Read");
- ts_good = port->getTxTimestamp
- (resp, resp_timestamp, resp_timestamp_counter_value, false);
-
- GPTP_LOG_VERBOSE("Done TS Read");
-
- while (ts_good != GPTP_EC_SUCCESS && iter-- != 0) {
- timer->sleep(req);
- if (ts_good == GPTP_EC_EAGAIN && iter < 1)
- GPTP_LOG_ERROR( "Error (TX) timestamping PDelay Response "
- "(Retrying-%d), error=%d", iter, ts_good);
- ts_good = port->getTxTimestamp
- (resp, resp_timestamp, resp_timestamp_counter_value, iter == 0);
- req *= 2;
- }
+ GPTP_LOG_DEBUG("*** Sent PDelay Response message");
port->putTxLock();
- if (ts_good != GPTP_EC_SUCCESS) {
- char msg[HWTIMESTAMPER_EXTENDED_MESSAGE_SIZE];
- port->getExtendedError(msg);
- GPTP_LOG_ERROR
- ( "Error (TX) timestamping PDelay Response, error=%d\t%s",
- ts_good, msg);
- delete resp;
- goto done;
- }
-
- if( resp_timestamp._version != _timestamp._version ) {
+ if( resp->getTimestamp()._version != _timestamp._version ) {
GPTP_LOG_ERROR("TX timestamp version mismatch: %u/%u",
- resp_timestamp._version, _timestamp._version);
+ resp->getTimestamp()._version, _timestamp._version);
#if 0 // discarding the request could lead to the peer setting the link to non-asCapable
delete resp;
goto done;
@@ -1193,16 +1229,17 @@ void PTPMessagePathDelayReq::processMessage(IEEE1588Port * port)
resp_fwup->setPortIdentity(&resp_fwup_id);
resp_fwup->setSequenceId(sequenceId);
resp_fwup->setRequestingPortIdentity(sourcePortIdentity);
- resp_fwup->setResponseOriginTimestamp(resp_timestamp);
+ resp_fwup->setResponseOriginTimestamp(resp->getTimestamp());
long long turnaround;
- turnaround =
- (resp_timestamp.seconds_ls - _timestamp.seconds_ls) * 1000000000LL;
+ turnaround = (resp->getTimestamp().seconds_ls - _timestamp.seconds_ls)
+ * 1000000000LL;
- GPTP_LOG_VERBOSE("Response Depart(sec): %u", resp_timestamp.seconds_ls);
+ GPTP_LOG_VERBOSE("Response Depart(sec): %u",
+ resp->getTimestamp().seconds_ls);
GPTP_LOG_VERBOSE("Request Arrival(sec): %u", _timestamp.seconds_ls);
GPTP_LOG_VERBOSE("#1 Correction Field: %Ld", turnaround);
- turnaround += resp_timestamp.nanoseconds;
+ turnaround += resp->getTimestamp().nanoseconds;
GPTP_LOG_VERBOSE("#2 Correction Field: %Ld", turnaround);
@@ -1213,7 +1250,7 @@ void PTPMessagePathDelayReq::processMessage(IEEE1588Port * port)
resp_fwup->setCorrectionField(0);
resp_fwup->sendPort(port, sourcePortIdentity);
- GPTP_LOG_DEBUG("Sent path delay response fwup");
+ GPTP_LOG_DEBUG("*** Sent PDelay Response FollowUp message");
delete resp;
delete resp_fwup;
@@ -1224,11 +1261,13 @@ done:
return;
}
-void PTPMessagePathDelayReq::sendPort(IEEE1588Port * port,
- PortIdentity * destIdentity)
+bool PTPMessagePathDelayReq::sendPort
+( EtherPort *port, PortIdentity *destIdentity )
{
+ uint32_t link_speed;
+
if(port->pdelayHalted())
- return;
+ return false;
uint8_t buf_t[256];
uint8_t *buf_ptr = buf_t + port->getPayloadOffset();
@@ -1239,13 +1278,16 @@ void PTPMessagePathDelayReq::sendPort(IEEE1588Port * port,
messageLength = PTP_COMMON_HDR_LENGTH + PTP_PDELAY_REQ_LENGTH;
tspec_msg_t |= messageType & 0xF;
buildCommonHeader(buf_ptr);
- port->sendEventPort(PTP_ETHERTYPE, buf_t, messageLength, MCAST_PDELAY, destIdentity);
+ port->sendEventPort
+ ( PTP_ETHERTYPE, buf_t, messageLength, MCAST_PDELAY,
+ destIdentity, &link_speed );
port->incCounter_ieee8021AsPortStatTxPdelayRequest();
- return;
+
+ return getTxTimestamp( port, link_speed );
}
- PTPMessagePathDelayResp::PTPMessagePathDelayResp(IEEE1588Port * port) :
- PTPMessageCommon(port)
+PTPMessagePathDelayResp::PTPMessagePathDelayResp
+( EtherPort *port ) : PTPMessageCommon( port )
{
/*TODO: Why 0x7F?*/
logMeanMessageInterval = 0x7F;
@@ -1264,7 +1306,7 @@ PTPMessagePathDelayResp::~PTPMessagePathDelayResp()
delete requestingPortIdentity;
}
-void PTPMessagePathDelayResp::processMessage(IEEE1588Port * port)
+void PTPMessagePathDelayResp::processMessage( EtherPort *port )
{
if (port->getPortState() == PTP_DISABLED) {
// Do nothing all messages should be ignored when in this state
@@ -1342,13 +1384,15 @@ bypass_verify_duplicate:
return;
}
-void PTPMessagePathDelayResp::sendPort(IEEE1588Port * port,
- PortIdentity * destIdentity)
+bool PTPMessagePathDelayResp::sendPort
+( EtherPort *port, PortIdentity *destIdentity )
{
uint8_t buf_t[256];
uint8_t *buf_ptr = buf_t + port->getPayloadOffset();
unsigned char tspec_msg_t = 0;
Timestamp requestReceiptTimestamp_BE;
+ uint32_t link_speed;
+
memset(buf_t, 0, 256);
// Create packet in buf
// Copy in common header
@@ -1384,9 +1428,12 @@ void PTPMessagePathDelayResp::sendPort(IEEE1588Port * port,
requestReceiptTimestamp.seconds_ls,
requestReceiptTimestamp.nanoseconds);
- port->sendEventPort(PTP_ETHERTYPE, buf_t, messageLength, MCAST_PDELAY, destIdentity);
+ port->sendEventPort
+ ( PTP_ETHERTYPE, buf_t, messageLength, MCAST_PDELAY,
+ destIdentity, &link_speed );
port->incCounter_ieee8021AsPortStatTxPdelayResponse();
- return;
+
+ return getTxTimestamp( port, link_speed );
}
void PTPMessagePathDelayResp::setRequestingPortIdentity
@@ -1402,7 +1449,7 @@ void PTPMessagePathDelayResp::getRequestingPortIdentity
}
PTPMessagePathDelayRespFollowUp::PTPMessagePathDelayRespFollowUp
-(IEEE1588Port * port) : PTPMessageCommon (port)
+( EtherPort *port ) : PTPMessageCommon( port )
{
logMeanMessageInterval = 0x7F;
control = MESSAGE_OTHER;
@@ -1419,7 +1466,8 @@ PTPMessagePathDelayRespFollowUp::~PTPMessagePathDelayRespFollowUp()
}
#define US_PER_SEC 1000000
-void PTPMessagePathDelayRespFollowUp::processMessage(IEEE1588Port * port)
+void PTPMessagePathDelayRespFollowUp::processMessage
+( EtherPort *port )
{
Timestamp remote_resp_tx_timestamp(0, 0, 0);
Timestamp request_tx_timestamp(0, 0, 0);
@@ -1613,6 +1661,7 @@ void PTPMessagePathDelayRespFollowUp::processMessage(IEEE1588Port * port)
/* Subtract turn-around time from link delay after rate adjustment */
link_delay -= turn_around;
link_delay /= 2;
+ GPTP_LOG_DEBUG( "Link delay: %ld ns", link_delay );
{
uint64_t mine_elapsed;
@@ -1662,8 +1711,8 @@ void PTPMessagePathDelayRespFollowUp::processMessage(IEEE1588Port * port)
return;
}
-void PTPMessagePathDelayRespFollowUp::sendPort(IEEE1588Port * port,
- PortIdentity * destIdentity)
+bool PTPMessagePathDelayRespFollowUp::sendPort
+( EtherPort *port, PortIdentity *destIdentity )
{
uint8_t buf_t[256];
uint8_t *buf_ptr = buf_t + port->getPayloadOffset();
@@ -1709,7 +1758,8 @@ void PTPMessagePathDelayRespFollowUp::sendPort(IEEE1588Port * port,
port->sendGeneralPort(PTP_ETHERTYPE, buf_t, messageLength, MCAST_PDELAY, destIdentity);
port->incCounter_ieee8021AsPortStatTxPdelayResponseFollowUp();
- return;
+
+ return true;
}
void PTPMessagePathDelayRespFollowUp::setRequestingPortIdentity
@@ -1723,12 +1773,13 @@ void PTPMessagePathDelayRespFollowUp::setRequestingPortIdentity
{
}
- PTPMessageSignalling::PTPMessageSignalling(IEEE1588Port * port) : PTPMessageCommon(port)
+PTPMessageSignalling::PTPMessageSignalling
+( EtherPort *port ) : PTPMessageCommon( port )
{
messageType = SIGNALLING_MESSAGE;
sequenceId = port->getNextSignalSequenceId();
- targetPortIdentify = 0xff;
+ targetPortIdentify = (int8_t)0xff;
control = MESSAGE_OTHER;
@@ -1746,7 +1797,8 @@ void PTPMessageSignalling::setintervals(int8_t linkDelayInterval, int8_t timeSyn
tlv.setAnnounceInterval(announceInterval);
}
-void PTPMessageSignalling::sendPort(IEEE1588Port * port, PortIdentity * destIdentity)
+bool PTPMessageSignalling::sendPort
+( EtherPort *port, PortIdentity *destIdentity )
{
uint8_t buf_t[256];
uint8_t *buf_ptr = buf_t + port->getPayloadOffset();
@@ -1765,9 +1817,11 @@ void PTPMessageSignalling::sendPort(IEEE1588Port * port, PortIdentity * destIden
tlv.toByteString(buf_ptr + PTP_COMMON_HDR_LENGTH + PTP_SIGNALLING_LENGTH);
port->sendGeneralPort(PTP_ETHERTYPE, buf_t, messageLength, MCAST_OTHER, destIdentity);
+
+ return true;
}
-void PTPMessageSignalling::processMessage(IEEE1588Port * port)
+void PTPMessageSignalling::processMessage( EtherPort *port )
{
long long unsigned int waitTime;
@@ -1802,7 +1856,7 @@ void PTPMessageSignalling::processMessage(IEEE1588Port * port)
}
if (timeSyncInterval == PTPMessageSignalling::sigMsgInterval_Initial) {
- port->setInitSyncInterval();
+ port->resetInitSyncInterval();
waitTime = ((long long) (pow((double)2, port->getSyncInterval()) * 1000000000.0));
waitTime = waitTime > EVENT_TIMER_GRANULARITY ? waitTime : EVENT_TIMER_GRANULARITY;
diff --git a/daemons/gptp/common/ptptypes.hpp b/daemons/gptp/common/ptptypes.hpp
index bcc72f9d..03cd57be 100644
--- a/daemons/gptp/common/ptptypes.hpp
+++ b/daemons/gptp/common/ptptypes.hpp
@@ -36,12 +36,19 @@
/**@file*/
-typedef long double FrequencyRatio; /*!< Frequency Ratio */
+#if defined(__clang__) && defined(__x86_64__)
+// Clang/llvm has incompatible long double (fp128) for x86_64.
+typedef double FrequencyRatio; /*!< Frequency Ratio */
+#else
+typedef long double FrequencyRatio; /*!< Frequency Ratio */
+#endif
#define ETHER_ADDR_OCTETS 6 /*!< Number of octets in a link layer address*/
#define IP_ADDR_OCTETS 4 /*!< Number of octets in a ip address*/
#define PTP_ETHERTYPE 0x88F7 /*!< PTP ethertype */
-#define AVTP_ETHERTYPE 0x22F0 /*!< AVTP ethertype used for Test Status Message */
+#define AVTP_ETHERTYPE 0x22F0 /*!< AVTP ethertype used for Test Status Message */
+
+#define PTP_CLOCK_IDENTITY_LENGTH 8 /*!< Size of a clock identifier stored in the ClockIndentity class, described at IEEE 802.1AS-2011 Clause 8.5.2.4*/
/**
* @brief PortState enumeration
diff --git a/daemons/gptp/gptp_cfg.ini b/daemons/gptp/gptp_cfg.ini
index 35a00848..ee593e9e 100644
--- a/daemons/gptp/gptp_cfg.ini
+++ b/daemons/gptp/gptp_cfg.ini
@@ -31,19 +31,32 @@ syncReceiptThresh = 8
[eth]
+# Older deprecated format
# PHY delay GB TX in nanoseconds
# The default for I210 is 184
-phy_delay_gb_tx = 184
+#phy_delay_gb_tx = 184
+# Older deprecated format
# PHY delay GB RX in nanoseconds
-# The default for I210 is 382
-phy_delay_gb_rx = 382
+# The default for I210 is 184
+#phy_delay_gb_rx = 382
-# PHY delay MB TX in nanoseconds
+# Older deprecated format
+# PHY delay 100 MB TX in nanoseconds
# The default for I210 is 1044
-phy_delay_mb_tx = 1044
+#phy_delay_mb_tx = 1044
-# PHY delay MB RX in nanoseconds
+# Older deprecated format
+# PHY delay 100 MB RX in nanoseconds
# The default for I210 is 2133
-phy_delay_mb_rx = 2133
+#phy_delay_mb_rx = 2133
+
+# Newer flexible format
+# PHY delay GB RX/TX in nanoseconds
+# Link speed may be specified numerically or by name
+#phy_delay = 1000000 184 382
+phy_delay = LINKSPEED_1G 184 382
+
+# PHY delay 100 MB RX/TX in nanoseconds
+phy_delay = LINKSPEED_100MB 1044 2133
diff --git a/daemons/gptp/linux/build/Makefile b/daemons/gptp/linux/build/Makefile
index 21048c06..1e00b1a5 100644
--- a/daemons/gptp/linux/build/Makefile
+++ b/daemons/gptp/linux/build/Makefile
@@ -30,7 +30,7 @@
ALTERNATE_LINUX_INCPATH=$(HOME)/header/include/
-CFLAGS_G = -Wall -std=c++0x -g -I. -I../../common -I../src \
+CFLAGS_G = -Wall -g -I. -I../../common -I../src \
-I$(ALTERNATE_LINUX_INCPATH)
# Check to see if PTP cross-timestamping is supported in hardware/driver
@@ -39,16 +39,15 @@ CFLAGS_G = -Wall -std=c++0x -g -I. -I../../common -I../src \
PRECISE_TIME_TEST = "\#include <linux/ptp_clock.h>\\n\
\#ifdef PTP_SYS_OFFSET_PRECISE\\nint main(){return 0;}\\n\#endif"
-HAS_PRECISE_TIME = $(shell echo $(PRECISE_TIME_TEST) | gcc -xc - \
+HAS_PRECISE_TIME = $(shell echo $(PRECISE_TIME_TEST) | $(CC) -xc - \
-I$(ALTERNATE_LINUX_INCPATH) -o /dev/null > /dev/null 2>&1 ; echo $$?)
ifeq ($(HAS_PRECISE_TIME),0)
CFLAGS_G += -DPTP_HW_CROSSTSTAMP
endif
-CPPFLAGS_G = $(CFLAGS_G) -Wnon-virtual-dtor
-
-LDFLAGS_G = -lpthread -lrt
+CPPFLAGS_G = $(CFLAGS_G) -std=c++0x -Wnon-virtual-dtor
+LDFLAGS_G =
COMMON_DIR = ../../common
SRC_DIR = ../src
@@ -57,7 +56,8 @@ OBJ_DIR = obj
OBJ_FILES = $(OBJ_DIR)/ptp_message.o\
$(OBJ_DIR)/ap_message.o\
$(OBJ_DIR)/avbts_osnet.o\
- $(OBJ_DIR)/ieee1588port.o\
+ $(OBJ_DIR)/ether_port.o\
+ $(OBJ_DIR)/common_port.o\
$(OBJ_DIR)/ieee1588clock.o \
$(OBJ_DIR)/linux_hal_common.o\
$(OBJ_DIR)/linux_hal_persist_file.o\
@@ -66,7 +66,8 @@ OBJ_FILES = $(OBJ_DIR)/ptp_message.o\
$(OBJ_DIR)/ini.o \
$(OBJ_DIR)/gptp_cfg.o
-HEADER_FILES = $(COMMON_DIR)/avbts_port.hpp\
+HEADER_FILES = $(COMMON_DIR)/ether_port.hpp\
+ $(COMMON_DIR)/common_port.hpp\
$(COMMON_DIR)/avbts_ostimerq.hpp\
$(COMMON_DIR)/avbts_ostimer.hpp\
$(COMMON_DIR)/avbts_osthread.hpp\
@@ -112,6 +113,22 @@ else
HEADER_FILES += $(SRC_DIR)/linux_hal_generic.hpp
endif
+ifeq ($(GENIVI_DLT),1)
+ GENIVI_DLT_INCLUDE_PATH=/usr/local/include/dlt/
+ GENIVI_DLT_LIB_PATH=/usr/local/lib/x86_64-linux-gnu/static/
+ CFLAGS_G += -I$(GENIVI_DLT_INCLUDE_PATH) -DGENIVI_DLT
+ LDFLAGS_G += -ldlt -L$(GENIVI_DLT_LIB_PATH)
+endif
+
+ifeq ($(SYSTEMD_WATCHDOG),1)
+ CFLAGS_G += -DSYSTEMD_WATCHDOG
+ LDFLAGS_G += -lsystemd
+ OBJ_FILES += $(OBJ_DIR)/watchdog.o
+ HEADER_FILES += $(SRC_DIR)/watchdog.hpp
+endif
+
+LDFLAGS_G += -lpthread -lrt
+
CFLAGS = $(CFLAGS_G)
CPPFLAGS = $(CPPFLAGS_G)
LDFLAGS = $(LDFLAGS_G)
@@ -141,8 +158,11 @@ $(OBJ_DIR)/linux_hal_i210.o: $(SRC_DIR)/linux_hal_i210.cpp $(HEADER_FILES)
$(OBJ_DIR)/linux_hal_intelce.o: $(SRC_DIR)/linux_hal_intelce.cpp $(HEADER_FILES)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(SRC_DIR)/linux_hal_intelce.cpp -o $(OBJ_DIR)/linux_hal_intelce.o
-$(OBJ_DIR)/ieee1588port.o: $(COMMON_DIR)/ieee1588port.cpp $(HEADER_FILES)
- $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(COMMON_DIR)/ieee1588port.cpp -o $(OBJ_DIR)/ieee1588port.o
+$(OBJ_DIR)/ether_port.o: $(COMMON_DIR)/ether_port.cpp $(HEADER_FILES)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
+
+$(OBJ_DIR)/common_port.o: $(COMMON_DIR)/common_port.cpp $(HEADER_FILES)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
$(OBJ_DIR)/ieee1588clock.o: $(COMMON_DIR)/ieee1588clock.cpp $(HEADER_FILES)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(COMMON_DIR)/ieee1588clock.cpp -o $(OBJ_DIR)/ieee1588clock.o
@@ -168,6 +188,8 @@ $(OBJ_DIR)/gptp_cfg.o: $(COMMON_DIR)/gptp_cfg.cpp $(HEADER_FILES)
$(OBJ_DIR)/ini.o: $(COMMON_DIR)/ini.c $(HEADER_FILES)
$(CC) $(CFLAGS) -c $(COMMON_DIR)/ini.c -o $(OBJ_DIR)/ini.o
+$(OBJ_DIR)/watchdog.o: $(SRC_DIR)/watchdog.cpp $(HEADER_FILES)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(SRC_DIR)/watchdog.cpp -o $(OBJ_DIR)/watchdog.o
clean:
$(RM) *~ $(OBJ_DIR)/*.o $(OBJ_DIR)/daemon_cl
diff --git a/daemons/gptp/linux/shm_test/shm_test.cpp b/daemons/gptp/linux/shm_test/shm_test.cpp
index 134f8462..dbe01c5b 100644
--- a/daemons/gptp/linux/shm_test/shm_test.cpp
+++ b/daemons/gptp/linux/shm_test/shm_test.cpp
@@ -97,11 +97,36 @@ int main(int argc, char *argv[])
fprintf(stdout, "ml freq offset %Lf\n", ptpData->ml_freqoffset);
fprintf(stdout, "ls phoffset %ld\n", ptpData->ls_phoffset);
fprintf(stdout, "ls freq offset %Lf\n", ptpData->ls_freqoffset);
- fprintf(stdout, "local time %lu\n", ptpData->local_time);
+ fprintf(stdout, "local time %llu\n\n", (unsigned long long) ptpData->local_time);
+
+ fprintf(stdout, "gptp grandmaster id %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
+ (unsigned int) ptpData->gptp_grandmaster_id[0], (unsigned int) ptpData->gptp_grandmaster_id[1],
+ (unsigned int) ptpData->gptp_grandmaster_id[2], (unsigned int) ptpData->gptp_grandmaster_id[3],
+ (unsigned int) ptpData->gptp_grandmaster_id[4], (unsigned int) ptpData->gptp_grandmaster_id[5],
+ (unsigned int) ptpData->gptp_grandmaster_id[6], (unsigned int) ptpData->gptp_grandmaster_id[7]);
+ fprintf(stdout, "gptp domain number %u\n\n", (unsigned int) ptpData->gptp_domain_number);
+
+ fprintf(stdout, "clock identity %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
+ (unsigned int) ptpData->clock_identity[0], (unsigned int) ptpData->clock_identity[1],
+ (unsigned int) ptpData->clock_identity[2], (unsigned int) ptpData->clock_identity[3],
+ (unsigned int) ptpData->clock_identity[4], (unsigned int) ptpData->clock_identity[5],
+ (unsigned int) ptpData->clock_identity[6], (unsigned int) ptpData->clock_identity[7]);
+ fprintf(stdout, "priority1 %u\n", (unsigned int) ptpData->priority1);
+ fprintf(stdout, "clock_class %u\n", (unsigned int) ptpData->clock_class);
+ fprintf(stdout, "offset_scaled_log_variance %d\n", (int) ptpData->offset_scaled_log_variance);
+ fprintf(stdout, "clock_accuracy %u\n", (unsigned int) ptpData->clock_accuracy);
+ fprintf(stdout, "priority2 %u\n", (unsigned int) ptpData->priority2);
+ fprintf(stdout, "domain_number %u\n", (unsigned int) ptpData->domain_number);
+ fprintf(stdout, "log_sync_interval %d\n", (int) ptpData->log_sync_interval);
+ fprintf(stdout, "log_announce_interval %d\n", (int) ptpData->log_announce_interval);
+ fprintf(stdout, "log_pdelay_interval %d\n", (int) ptpData->log_pdelay_interval);
+ fprintf(stdout, "port_number %u\n\n", (unsigned int) ptpData->port_number);
+
fprintf(stdout, "sync count %u\n", ptpData->sync_count);
fprintf(stdout, "pdelay count %u\n", ptpData->pdelay_count);
fprintf(stdout, "asCapable %s\n", ptpData->asCapable ? "True" : "False");
fprintf(stdout, "Port State %d\n", (int)ptpData->port_state);
+ fprintf(stdout, "process_id %d\n\n", (int)ptpData->process_id);
return 0;
}
diff --git a/daemons/gptp/linux/src/daemon_cl.cpp b/daemons/gptp/linux/src/daemon_cl.cpp
index b5b46a10..86806783 100644
--- a/daemons/gptp/linux/src/daemon_cl.cpp
+++ b/daemons/gptp/linux/src/daemon_cl.cpp
@@ -43,6 +43,7 @@
#else
#include "linux_hal_generic.hpp"
#endif
+
#include "linux_hal_persist_file.hpp"
#include <ctype.h>
#include <inttypes.h>
@@ -55,6 +56,10 @@
#include <unistd.h>
#include <string.h>
+#ifdef SYSTEMD_WATCHDOG
+#include <watchdog.hpp>
+#endif
+
#define PHY_DELAY_GB_TX_I20 184 //1G delay
#define PHY_DELAY_GB_RX_I20 382 //1G delay
#define PHY_DELAY_MB_TX_I20 1044//100M delay
@@ -65,7 +70,7 @@ void gPTPPersistWriteCB(char *bufPtr, uint32_t bufSize);
void print_usage( char *arg0 ) {
fprintf( stderr,
"%s <network interface> [-S] [-P] [-M <filename>] "
- "[-A <count>] [-G <group>] [-R <priority 1>] "
+ "[-G <group>] [-R <priority 1>] "
"[-D <gb_tx_delay,gb_rx_delay,mb_tx_delay,mb_rx_delay>] "
"[-T] [-L] [-E] [-GM] [-INITSYNC <value>] [-OPERSYNC <value>] "
"[-INITPDELAY <value>] [-OPERPDELAY <value>] "
@@ -77,7 +82,6 @@ void print_usage( char *arg0 ) {
"\t-S start syntonization\n"
"\t-P pulse per second\n"
"\t-M <filename> save/restore state\n"
- "\t-A <count> initial accelerated sync count\n"
"\t-G <group> group id for shared memory\n"
"\t-R <priority 1> priority 1 value\n"
"\t-D Phy Delay <gb_tx_delay,gb_rx_delay,mb_tx_delay,mb_rx_delay>\n"
@@ -94,14 +98,38 @@ void print_usage( char *arg0 ) {
);
}
+int watchdog_setup(OSThreadFactory *thread_factory)
+{
+#ifdef SYSTEMD_WATCHDOG
+ SystemdWatchdogHandler *watchdog = new SystemdWatchdogHandler();
+ OSThread *watchdog_thread = thread_factory->createThread();
+ int watchdog_result;
+ long unsigned int watchdog_interval;
+ watchdog_interval = watchdog->getSystemdWatchdogInterval(&watchdog_result);
+ if (watchdog_result) {
+ GPTP_LOG_INFO("Watchtog interval read from service file: %lu us", watchdog_interval);
+ watchdog->update_interval = watchdog_interval / 2;
+ GPTP_LOG_STATUS("Starting watchdog handler (Update every: %lu us)", watchdog->update_interval);
+ watchdog_thread->start(watchdogUpdateThreadFunction, watchdog);
+ return 0;
+ } else if (watchdog_result < 0) {
+ GPTP_LOG_ERROR("Watchdog settings read error.");
+ return -1;
+ } else {
+ GPTP_LOG_STATUS("Watchdog disabled");
+ return 0;
+ }
+#else
+ return 0;
+#endif
+}
+
static IEEE1588Clock *pClock = NULL;
-static IEEE1588Port *pPort = NULL;
+static EtherPort *pPort = NULL;
int main(int argc, char **argv)
{
- GPTP_LOG_INFO("gPTP starting");
-
- IEEE1588PortInit_t portInit;
+ PortInit_t portInit;
sigset_t set;
InterfaceName *ifname;
@@ -112,31 +140,48 @@ int main(int argc, char **argv)
bool pps = false;
uint8_t priority1 = 248;
bool override_portstate = false;
- PortState port_state;
-
+ PortState port_state = PTP_SLAVE;
char *restoredata = NULL;
char *restoredataptr = NULL;
off_t restoredatalength = 0;
off_t restoredatacount = 0;
bool restorefailed = false;
LinuxIPCArg *ipc_arg = NULL;
- int accelerated_sync_count = 0;
bool use_config_file = false;
char config_file_path[512];
memset(config_file_path, 0, 512);
GPTPPersist *pGPTPPersist = NULL;
+ LinuxThreadFactory *thread_factory = new LinuxThreadFactory();
+
+ // Block SIGUSR1
+ {
+ sigset_t block;
+ sigemptyset( &block );
+ sigaddset( &block, SIGUSR1 );
+ if( pthread_sigmask( SIG_BLOCK, &block, NULL ) != 0 ) {
+ GPTP_LOG_ERROR("Failed to block SIGUSR1");
+ return -1;
+ }
+ }
+
+ GPTP_LOG_REGISTER();
+ GPTP_LOG_INFO("gPTP starting");
+ if (watchdog_setup(thread_factory) != 0) {
+ GPTP_LOG_ERROR("Watchdog handler setup error");
+ return -1;
+ }
+ phy_delay_map_t ether_phy_delay;
+ bool input_delay=false;
portInit.clock = NULL;
portInit.index = 0;
- portInit.forceSlave = false;
- portInit.accelerated_sync_count = 0;
portInit.timestamper = NULL;
- portInit.offset = 0;
portInit.net_label = NULL;
portInit.automotive_profile = false;
portInit.isGM = false;
portInit.testMode = false;
+ portInit.linkUp = false;
portInit.initialLogSyncInterval = LOG2_INTERVAL_INVALID;
portInit.initialLogPdelayReqInterval = LOG2_INTERVAL_INVALID;
portInit.operLogPdelayReqInterval = LOG2_INTERVAL_INVALID;
@@ -145,26 +190,15 @@ int main(int argc, char **argv)
portInit.thread_factory = NULL;
portInit.timer_factory = NULL;
portInit.lock_factory = NULL;
-
- // Block SIGUSR1
- {
- sigset_t block;
- sigemptyset( &block );
- sigaddset( &block, SIGUSR1 );
- if( pthread_sigmask( SIG_BLOCK, &block, NULL ) != 0 ) {
- fprintf( stderr, "Failed to block SIGUSR1\n" );
- return -1;
- }
- }
-
- int phy_delay[4]={0,0,0,0};
- bool input_delay=false;
+ portInit.syncReceiptThreshold =
+ CommonPort::DEFAULT_SYNC_RECEIPT_THRESH;
+ portInit.neighborPropDelayThreshold =
+ CommonPort::NEIGHBOR_PROP_DELAY_THRESH;
LinuxNetworkInterfaceFactory *default_factory =
new LinuxNetworkInterfaceFactory;
OSNetworkInterfaceFactory::registerFactory
(factory_name_t("default"), default_factory);
- LinuxThreadFactory *thread_factory = new LinuxThreadFactory();
LinuxTimerQueueFactory *timerq_factory = new LinuxTimerQueueFactory();
LinuxLockFactory *lock_factory = new LinuxLockFactory();
LinuxTimerFactory *timer_factory = new LinuxTimerFactory();
@@ -207,14 +241,6 @@ int main(int argc, char **argv)
"command line\n" );
}
}
- else if( strcmp(argv[i] + 1, "A" ) == 0 ) {
- if( i+1 < argc ) {
- accelerated_sync_count = atoi( argv[++i] );
- } else {
- printf( "Accelerated sync count must be specified on the "
- "command line with A option\n" );
- }
- }
else if( strcmp(argv[i] + 1, "G") == 0 ) {
if( i+1 < argc ) {
ipc_arg = new LinuxIPCArg(argv[++i]);
@@ -227,6 +253,7 @@ int main(int argc, char **argv)
}
else if( strcmp(argv[i] + 1, "H") == 0 ) {
print_usage( argv[0] );
+ GPTP_LOG_UNREGISTER();
return 0;
}
else if( strcmp(argv[i] + 1, "R") == 0 ) {
@@ -244,6 +271,7 @@ int main(int argc, char **argv)
}
}
else if (strcmp(argv[i] + 1, "D") == 0) {
+ int phy_delay[4];
input_delay=true;
int delay_count=0;
char *cli_inp_delay = strtok(argv[i+1],",");
@@ -253,6 +281,7 @@ int main(int argc, char **argv)
{
printf("Too many values\n");
print_usage( argv[0] );
+ GPTP_LOG_UNREGISTER();
return 0;
}
phy_delay[delay_count]=atoi(cli_inp_delay);
@@ -263,8 +292,13 @@ int main(int argc, char **argv)
{
printf("All four delay values must be specified\n");
print_usage( argv[0] );
+ GPTP_LOG_UNREGISTER();
return 0;
}
+ ether_phy_delay[LINKSPEED_1G].set_delay
+ ( phy_delay[0], phy_delay[1] );
+ ether_phy_delay[LINKSPEED_100MB].set_delay
+ ( phy_delay[2], phy_delay[3] );
}
else if (strcmp(argv[i] + 1, "V") == 0) {
portInit.automotive_profile = true;
@@ -301,11 +335,12 @@ int main(int argc, char **argv)
if (!input_delay)
{
- phy_delay[0] = PHY_DELAY_GB_TX_I20;
- phy_delay[1] = PHY_DELAY_GB_RX_I20;
- phy_delay[2] = PHY_DELAY_MB_TX_I20;
- phy_delay[3] = PHY_DELAY_MB_RX_I20;
+ ether_phy_delay[LINKSPEED_1G].set_delay
+ ( PHY_DELAY_GB_TX_I20, PHY_DELAY_GB_RX_I20 );
+ ether_phy_delay[LINKSPEED_100MB].set_delay
+ ( PHY_DELAY_MB_TX_I20, PHY_DELAY_MB_RX_I20 );
}
+ portInit.phy_delay = &ether_phy_delay;
if( !ipc->init( ipc_arg ) ) {
delete ipc;
@@ -316,16 +351,16 @@ int main(int argc, char **argv)
if( pGPTPPersist ) {
uint32_t bufSize = 0;
if (!pGPTPPersist->readStorage(&restoredata, &bufSize))
- printf( "Failed to stat restore file\n");
+ GPTP_LOG_ERROR("Failed to stat restore file");
restoredatalength = bufSize;
restoredatacount = restoredatalength;
restoredataptr = (char *)restoredata;
}
#ifdef ARCH_INTELCE
- HWTimestamper *timestamper = new LinuxTimestamperIntelCE();
+ EtherTimestamper *timestamper = new LinuxTimestamperIntelCE();
#else
- HWTimestamper *timestamper = new LinuxTimestamperGeneric();
+ EtherTimestamper *timestamper = new LinuxTimestamperGeneric();
#endif
sigemptyset(&set);
@@ -335,11 +370,13 @@ int main(int argc, char **argv)
sigaddset(&set, SIGUSR2);
if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0) {
perror("pthread_sigmask()");
+ GPTP_LOG_UNREGISTER();
return -1;
}
- pClock = new IEEE1588Clock( false, syntonize, priority1, timestamper,
- timerq_factory, ipc, lock_factory );
+ pClock = new IEEE1588Clock
+ ( false, syntonize, priority1, timerq_factory, ipc,
+ lock_factory );
if( restoredataptr != NULL ) {
if( !restorefailed )
@@ -352,60 +389,54 @@ int main(int argc, char **argv)
// just set directly into the portInit struct.
portInit.clock = pClock;
portInit.index = 1;
- portInit.forceSlave = false;
- portInit.accelerated_sync_count = accelerated_sync_count;
portInit.timestamper = timestamper;
- portInit.offset = 0;
portInit.net_label = ifname;
portInit.condition_factory = condition_factory;
portInit.thread_factory = thread_factory;
portInit.timer_factory = timer_factory;
portInit.lock_factory = lock_factory;
- pPort = new IEEE1588Port(&portInit);
-
if(use_config_file)
{
GptpIniParser iniParser(config_file_path);
if (iniParser.parserError() < 0) {
- fprintf(stderr, "Cant parse ini file. Aborting file reading.\n");
+ GPTP_LOG_ERROR("Cant parse ini file. Aborting file reading.");
}
else
{
- fprintf(stdout, "priority1 = %d\n", iniParser.getPriority1());
- fprintf(stdout, "announceReceiptTimeout: %d\n", iniParser.getAnnounceReceiptTimeout());
- fprintf(stdout, "syncReceiptTimeout: %d\n", iniParser.getSyncReceiptTimeout());
- fprintf(stdout, "phy_delay_gb_tx: %d\n", iniParser.getPhyDelayGbTx());
- fprintf(stdout, "phy_delay_gb_rx: %d\n", iniParser.getPhyDelayGbRx());
- fprintf(stdout, "phy_delay_mb_tx: %d\n", iniParser.getPhyDelayMbTx());
- fprintf(stdout, "phy_delay_mb_rx: %d\n", iniParser.getPhyDelayMbRx());
- fprintf(stdout, "neighborPropDelayThresh: %ld\n", iniParser.getNeighborPropDelayThresh());
- fprintf(stdout, "syncReceiptThreshold: %d\n", iniParser.getSyncReceiptThresh());
+ GPTP_LOG_INFO("priority1 = %d", iniParser.getPriority1());
+ GPTP_LOG_INFO("announceReceiptTimeout: %d", iniParser.getAnnounceReceiptTimeout());
+ GPTP_LOG_INFO("syncReceiptTimeout: %d", iniParser.getSyncReceiptTimeout());
+ iniParser.print_phy_delay();
+ GPTP_LOG_INFO("neighborPropDelayThresh: %ld", iniParser.getNeighborPropDelayThresh());
+ GPTP_LOG_INFO("syncReceiptThreshold: %d", iniParser.getSyncReceiptThresh());
/* If using config file, set the neighborPropDelayThresh.
* Otherwise it will use its default value (800ns) */
- pPort->setNeighPropDelayThresh(iniParser.getNeighborPropDelayThresh());
+ portInit.neighborPropDelayThreshold =
+ iniParser.getNeighborPropDelayThresh();
/* If using config file, set the syncReceiptThreshold, otherwise
* it will use the default value (SYNC_RECEIPT_THRESH)
*/
- pPort->setSyncReceiptThresh(iniParser.getSyncReceiptThresh());
+ portInit.syncReceiptThreshold =
+ iniParser.getSyncReceiptThresh();
/*Only overwrites phy_delay default values if not input_delay switch enabled*/
if(!input_delay)
{
- phy_delay[0] = iniParser.getPhyDelayGbTx();
- phy_delay[1] = iniParser.getPhyDelayGbRx();
- phy_delay[2] = iniParser.getPhyDelayMbTx();
- phy_delay[3] = iniParser.getPhyDelayMbRx();
+ ether_phy_delay = iniParser.getPhyDelay();
}
}
}
- if (!pPort->init_port(phy_delay)) {
- printf("failed to initialize port \n");
+ pPort = new EtherPort(&portInit);
+
+ if (!pPort->init_port()) {
+ GPTP_LOG_ERROR("failed to initialize port");
+ GPTP_LOG_UNREGISTER();
return -1;
}
@@ -435,7 +466,7 @@ int main(int argc, char **argv)
// Start PPS if requested
if( pps ) {
if( !timestamper->HWTimestamper_PPS_start()) {
- printf( "Failed to start pulse per second I/O\n" );
+ GPTP_LOG_ERROR("Failed to start pulse per second I/O");
}
}
@@ -458,6 +489,7 @@ int main(int argc, char **argv)
if (sigwait(&set, &sig) != 0) {
perror("sigwait()");
+ GPTP_LOG_UNREGISTER();
return -1;
}
@@ -475,7 +507,7 @@ int main(int argc, char **argv)
}
} while (sig == SIGHUP || sig == SIGUSR2);
- fprintf(stderr, "Exiting on %d\n", sig);
+ GPTP_LOG_ERROR("Exiting on %d", sig);
if (pGPTPPersist) {
pGPTPPersist->closeStorage();
@@ -484,12 +516,13 @@ int main(int argc, char **argv)
// Stop PPS if previously started
if( pps ) {
if( !timestamper->HWTimestamper_PPS_stop()) {
- printf( "Failed to stop pulse per second I/O\n" );
+ GPTP_LOG_ERROR("Failed to stop pulse per second I/O");
}
}
if( ipc ) delete ipc;
+ GPTP_LOG_UNREGISTER();
return 0;
}
@@ -499,7 +532,7 @@ void gPTPPersistWriteCB(char *bufPtr, uint32_t bufSize)
off_t restoredatacount = restoredatalength;
char *restoredataptr = NULL;
- printf("Signal received to write restore data\n");
+ GPTP_LOG_INFO("Signal received to write restore data");
restoredataptr = (char *)bufPtr;
pClock->serializeState(restoredataptr, &restoredatacount);
diff --git a/daemons/gptp/linux/src/linux_hal_common.cpp b/daemons/gptp/linux/src/linux_hal_common.cpp
index ed986b07..cd880ba9 100644
--- a/daemons/gptp/linux/src/linux_hal_common.cpp
+++ b/daemons/gptp/linux/src/linux_hal_common.cpp
@@ -34,7 +34,7 @@
#include <linux_hal_common.hpp>
#include <sys/types.h>
#include <avbts_clock.hpp>
-#include <avbts_port.hpp>
+#include <ether_port.hpp>
#include <pthread.h>
#include <linux_ipc.hpp>
@@ -56,10 +56,11 @@
#include <sys/stat.h>
#include <sys/socket.h>
-#include <net/if.h>
#include <netinet/in.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
+#include <linux/sockios.h>
+#include <gptp_cfg.hpp>
Timestamp tsToTimestamp(struct timespec *ts)
{
@@ -105,7 +106,7 @@ net_result LinuxNetworkInterface::send
err = sendto
( sd_general, payload, length, 0, (sockaddr *) remote,
sizeof( *remote ));
- }
+ }
delete remote;
if( err == -1 ) {
GPTP_LOG_ERROR( "Failed to send: %s(%d)", strerror(errno), errno );
@@ -169,7 +170,8 @@ void LinuxNetworkInterface::clear_reenable_rx_queue() {
}
}
-static void x_readEvent(int sockint, IEEE1588Port *pPort)
+static void x_readEvent
+( int sockint, EtherPort *pPort, int ifindex )
{
int status;
char buf[4096];
@@ -204,24 +206,121 @@ static void x_readEvent(int sockint, IEEE1588Port *pPort)
if (msgHdr->nlmsg_type == RTM_NEWLINK) {
ifi = (struct ifinfomsg *)NLMSG_DATA(msgHdr);
- if ((ifi->ifi_flags & IFF_RUNNING)) {
- pPort->processEvent(LINKUP);
- }
- else {
- pPort->processEvent(LINKDOWN);
+ if (ifi->ifi_index == ifindex) {
+ bool linkUp = ifi->ifi_flags & IFF_RUNNING;
+ if (linkUp != pPort->getLinkUpState()) {
+ pPort->setLinkUpState(linkUp);
+ if (linkUp) {
+ pPort->processEvent(LINKUP);
+ }
+ else {
+ pPort->processEvent(LINKDOWN);
+ }
+ }
+ else {
+ GPTP_LOG_DEBUG("False (repeated) %s event for the interface", linkUp ? "LINKUP" : "LINKDOWN");
+ }
}
}
}
return;
}
-void LinuxNetworkInterface::watchNetLink(IEEE1588Port *pPort)
+static void x_initLinkUpStatus( EtherPort *pPort, int ifindex )
+{
+ struct ifreq device;
+ memset(&device, 0, sizeof(device));
+ device.ifr_ifindex = ifindex;
+
+ int inetSocket = socket (AF_INET, SOCK_STREAM, 0);
+ if (inetSocket < 0) {
+ GPTP_LOG_ERROR("initLinkUpStatus error opening socket: %s", strerror(errno));
+ return;
+ }
+
+ int r = ioctl(inetSocket, SIOCGIFNAME, &device);
+ if (r < 0) {
+ GPTP_LOG_ERROR("initLinkUpStatus error reading interface name: %s", strerror(errno));
+ close(inetSocket);
+ return;
+ }
+ r = ioctl(inetSocket, SIOCGIFFLAGS, &device);
+ if (r < 0) {
+ GPTP_LOG_ERROR("initLinkUpStatus error reading flags: %s", strerror(errno));
+ close(inetSocket);
+ return;
+ }
+ if (device.ifr_flags & IFF_RUNNING) {
+ GPTP_LOG_DEBUG("Interface %s is up", device.ifr_name);
+ pPort->setLinkUpState(true);
+ } //linkUp == false by default
+ close(inetSocket);
+}
+
+
+bool LinuxNetworkInterface::getLinkSpeed( int sd, uint32_t *speed )
+{
+ struct ifreq ifr;
+ struct ethtool_cmd edata;
+
+ ifr.ifr_ifindex = ifindex;
+ if( ioctl( sd, SIOCGIFNAME, &ifr ) == -1 )
+ {
+ GPTP_LOG_ERROR
+ ( "%s: SIOCGIFNAME failed: %s", __PRETTY_FUNCTION__,
+ strerror( errno ));
+ return false;
+ }
+
+ ifr.ifr_data = (char *) &edata;
+ edata.cmd = ETHTOOL_GSET;
+ if( ioctl( sd, SIOCETHTOOL, &ifr ) == -1 )
+ {
+ GPTP_LOG_ERROR
+ ( "%s: SIOCETHTOOL failed: %s", __PRETTY_FUNCTION__,
+ strerror( errno ));
+ return false;
+ }
+
+ switch (ethtool_cmd_speed(&edata))
+ {
+ default:
+ GPTP_LOG_ERROR( "%s: Unknown/Unsupported Speed!",
+ __PRETTY_FUNCTION__ );
+ return false;
+ case SPEED_100:
+ *speed = LINKSPEED_100MB;
+ break;
+ case SPEED_1000:
+ *speed = LINKSPEED_1G;
+ break;
+ case SPEED_2500:
+ *speed = LINKSPEED_2_5G;
+ break;
+ case SPEED_10000:
+ *speed = LINKSPEED_10G;
+ break;
+ }
+ GPTP_LOG_STATUS( "Link Speed: %d kb/sec", *speed );
+
+ return true;
+}
+
+void LinuxNetworkInterface::watchNetLink( CommonPort *iPort )
{
fd_set netLinkFD;
int netLinkSocket;
-
+ int inetSocket;
struct sockaddr_nl addr;
+ EtherPort *pPort =
+ dynamic_cast<EtherPort *>(iPort);
+ if( pPort == NULL )
+ {
+ GPTP_LOG_ERROR("NETLINK socket open error");
+ return;
+ }
+
netLinkSocket = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (netLinkSocket < 0) {
GPTP_LOG_ERROR("NETLINK socket open error");
@@ -236,9 +335,34 @@ void LinuxNetworkInterface::watchNetLink(IEEE1588Port *pPort)
if (bind (netLinkSocket, (struct sockaddr *) &addr, sizeof (addr)) < 0) {
GPTP_LOG_ERROR("Socket bind failed");
+ close (netLinkSocket);
return;
}
+ /*
+ * Open an INET family socket to be passed to getLinkSpeed() which calls
+ * ioctl() because NETLINK sockets do not support ioctl(). Since we will
+ * enter an infinite loop, there are no apparent close() calls for the
+ * open sockets, but they will be closed on process termination.
+ */
+ inetSocket = socket (AF_INET, SOCK_STREAM, 0);
+ if (inetSocket < 0) {
+ GPTP_LOG_ERROR("watchNetLink error opening socket: %s", strerror(errno));
+ close (netLinkSocket);
+ return;
+ }
+
+ x_initLinkUpStatus(pPort, ifindex);
+ if( pPort->getLinkUpState() )
+ {
+ uint32_t link_speed;
+ getLinkSpeed( inetSocket, &link_speed );
+ pPort->setLinkSpeed((int32_t) link_speed );
+ } else
+ {
+ pPort->setLinkSpeed( INVALID_LINKSPEED );
+ }
+
while (1) {
FD_ZERO(&netLinkFD);
FD_CLR(netLinkSocket, &netLinkFD);
@@ -249,7 +373,21 @@ void LinuxNetworkInterface::watchNetLink(IEEE1588Port *pPort)
if (retval == -1)
; // Error on select. We will ignore and keep going
else if (retval) {
- x_readEvent(netLinkSocket, pPort);
+ bool prev_link_up = pPort->getLinkUpState();
+ x_readEvent(netLinkSocket, pPort, ifindex);
+
+ // Don't do anything else if link state is the same
+ if( prev_link_up == pPort->getLinkUpState() )
+ continue;
+ if( pPort->getLinkUpState() )
+ {
+ uint32_t link_speed;
+ getLinkSpeed( inetSocket, &link_speed );
+ pPort->setLinkSpeed((int32_t) link_speed );
+ } else
+ {
+ pPort->setLinkSpeed( INVALID_LINKSPEED );
+ }
}
else {
; // Would be timeout but Won't happen because we wait forever
@@ -325,7 +463,7 @@ void *LinuxTimerQueueHandler( void *arg ) {
void LinuxTimerQueue::LinuxTimerQueueAction( LinuxTimerQueueActionArg *arg ) {
arg->func( arg->inner_arg );
- return;
+ return;
}
OSTimerQueue *LinuxTimerQueueFactory::createOSTimerQueue
@@ -422,10 +560,10 @@ bool LinuxTimerQueue::cancelEvent( int type, unsigned *event ) {
void* OSThreadCallback( void* input ) {
- OSThreadArg *arg = (OSThreadArg*) input;
+ OSThreadArg *arg = (OSThreadArg*) input;
- arg->ret = arg->func( arg->arg );
- return 0;
+ arg->ret = arg->func( arg->arg );
+ return 0;
}
bool LinuxTimestamper::post_init( int ifindex, int sd, TicketingLock *lock ) {
@@ -435,8 +573,10 @@ bool LinuxTimestamper::post_init( int ifindex, int sd, TicketingLock *lock ) {
LinuxTimestamper::~LinuxTimestamper() {}
unsigned long LinuxTimer::sleep(unsigned long micros) {
- struct timespec req = { 0, (long int)(micros * 1000) };
+ struct timespec req;
struct timespec rem;
+ req.tv_sec = micros / 1000000;
+ req.tv_nsec = micros % 1000000 * 1000;
int ret = nanosleep( &req, &rem );
while( ret == -1 && errno == EINTR ) {
req = rem;
@@ -546,7 +686,7 @@ TicketingLock::~TicketingLock() {
}
struct LinuxLockPrivate {
- pthread_t thread_id;
+ pthread_t thread_id;
pthread_mutexattr_t mta;
pthread_mutex_t mutex;
pthread_cond_t port_ready_signal;
@@ -775,10 +915,17 @@ bool LinuxSharedMemoryIPC::init( OS_IPC_ARG *barg ) {
return false;
}
-bool LinuxSharedMemoryIPC::update
-(int64_t ml_phoffset, int64_t ls_phoffset, FrequencyRatio ml_freqoffset,
- FrequencyRatio ls_freqoffset, uint64_t local_time, uint32_t sync_count,
- uint32_t pdelay_count, PortState port_state, bool asCapable ) {
+bool LinuxSharedMemoryIPC::update(
+ int64_t ml_phoffset,
+ int64_t ls_phoffset,
+ FrequencyRatio ml_freqoffset,
+ FrequencyRatio ls_freqoffset,
+ uint64_t local_time,
+ uint32_t sync_count,
+ uint32_t pdelay_count,
+ PortState port_state,
+ bool asCapable )
+{
int buf_offset = 0;
pid_t process_id = getpid();
char *shm_buffer = master_offset_buffer;
@@ -795,7 +942,7 @@ bool LinuxSharedMemoryIPC::update
ptimedata->local_time = local_time;
ptimedata->sync_count = sync_count;
ptimedata->pdelay_count = pdelay_count;
- ptimedata->asCapable = asCapable;
+ ptimedata->asCapable = asCapable;
ptimedata->port_state = port_state;
ptimedata->process_id = process_id;
/* unlock */
@@ -804,6 +951,64 @@ bool LinuxSharedMemoryIPC::update
return true;
}
+bool LinuxSharedMemoryIPC::update_grandmaster(
+ uint8_t gptp_grandmaster_id[],
+ uint8_t gptp_domain_number )
+{
+ int buf_offset = 0;
+ char *shm_buffer = master_offset_buffer;
+ gPtpTimeData *ptimedata;
+ if( shm_buffer != NULL ) {
+ /* lock */
+ pthread_mutex_lock((pthread_mutex_t *) shm_buffer);
+ buf_offset += sizeof(pthread_mutex_t);
+ ptimedata = (gPtpTimeData *) (shm_buffer + buf_offset);
+ memcpy(ptimedata->gptp_grandmaster_id, gptp_grandmaster_id, PTP_CLOCK_IDENTITY_LENGTH);
+ ptimedata->gptp_domain_number = gptp_domain_number;
+ /* unlock */
+ pthread_mutex_unlock((pthread_mutex_t *) shm_buffer);
+ }
+ return true;
+}
+
+bool LinuxSharedMemoryIPC::update_network_interface(
+ uint8_t clock_identity[],
+ uint8_t priority1,
+ uint8_t clock_class,
+ int16_t offset_scaled_log_variance,
+ uint8_t clock_accuracy,
+ uint8_t priority2,
+ uint8_t domain_number,
+ int8_t log_sync_interval,
+ int8_t log_announce_interval,
+ int8_t log_pdelay_interval,
+ uint16_t port_number )
+{
+ int buf_offset = 0;
+ char *shm_buffer = master_offset_buffer;
+ gPtpTimeData *ptimedata;
+ if( shm_buffer != NULL ) {
+ /* lock */
+ pthread_mutex_lock((pthread_mutex_t *) shm_buffer);
+ buf_offset += sizeof(pthread_mutex_t);
+ ptimedata = (gPtpTimeData *) (shm_buffer + buf_offset);
+ memcpy(ptimedata->clock_identity, clock_identity, PTP_CLOCK_IDENTITY_LENGTH);
+ ptimedata->priority1 = priority1;
+ ptimedata->clock_class = clock_class;
+ ptimedata->offset_scaled_log_variance = offset_scaled_log_variance;
+ ptimedata->clock_accuracy = clock_accuracy;
+ ptimedata->priority2 = priority2;
+ ptimedata->domain_number = domain_number;
+ ptimedata->log_sync_interval = log_sync_interval;
+ ptimedata->log_announce_interval = log_announce_interval;
+ ptimedata->log_pdelay_interval = log_pdelay_interval;
+ ptimedata->port_number = port_number;
+ /* unlock */
+ pthread_mutex_unlock((pthread_mutex_t *) shm_buffer);
+ }
+ return true;
+}
+
void LinuxSharedMemoryIPC::stop() {
if( master_offset_buffer != NULL ) {
munmap( master_offset_buffer, SHM_SIZE );
@@ -813,7 +1018,7 @@ void LinuxSharedMemoryIPC::stop() {
bool LinuxNetworkInterfaceFactory::createInterface
( OSNetworkInterface **net_iface, InterfaceLabel *label,
- HWTimestamper *timestamper ) {
+ CommonTimestamper *timestamper ) {
struct ifreq device;
int err;
struct sockaddr_ll ifsock_addr;
@@ -847,7 +1052,7 @@ bool LinuxNetworkInterfaceFactory::createInterface
}
memset( &device, 0, sizeof(device));
- ifname->toString( device.ifr_name, IFNAMSIZ );
+ ifname->toString( device.ifr_name, IFNAMSIZ - 1 );
err = ioctl( net_iface_l->sd_event, SIOCGIFHWADDR, &device );
if( err == -1 ) {
GPTP_LOG_ERROR
diff --git a/daemons/gptp/linux/src/linux_hal_common.hpp b/daemons/gptp/linux/src/linux_hal_common.hpp
index fb77be19..28332f01 100644
--- a/daemons/gptp/linux/src/linux_hal_common.hpp
+++ b/daemons/gptp/linux/src/linux_hal_common.hpp
@@ -44,6 +44,8 @@
#include "avbts_osthread.hpp"
#include "avbts_osipc.hpp"
#include "ieee1588.hpp"
+#include <ether_tstamper.hpp>
+#include <linux/ethtool.h>
#include <list>
@@ -123,7 +125,7 @@ private:
* @brief LinuxTimestamper: Provides a generic hardware
* timestamp interface for linux based systems.
*/
-class LinuxTimestamper : public HWTimestamper {
+class LinuxTimestamper : public EtherTimestamper {
public:
/**
* @brief Destructor
@@ -157,7 +159,7 @@ public:
/**
* @brief Sends a packet to a remote address
* @param addr [in] Remote link layer address
- * @param etherType [in] The EtherType of the message
+ * @param etherType [in] The EtherType of the message in host order
* @param payload [in] Data buffer
* @param length Size of data buffer
* @param timestamp TRUE if to use the event socket with the PTP multicast address. FALSE if to use
@@ -177,7 +179,7 @@ public:
* an error on the transmit side, net_fatal if error on reception
*/
virtual net_result nrecv
- ( LinkLayerAddress *addr, uint8_t *payload, size_t &length, struct phy_delay *delay );
+ ( LinkLayerAddress *addr, uint8_t *payload, size_t &length );
/**
* @brief Disables rx socket descriptor rx queue
@@ -201,9 +203,18 @@ public:
}
/**
+ * @brief Get speed of network link
+ *
+ * @param [in] sd Open socket descriptor
+ * @param [out] speed Link speed in kb/sec
+ * @return false on error
+ */
+ bool getLinkSpeed( int sd, uint32_t *speed );
+
+ /**
* @brief Watch for net link changes.
*/
- virtual void watchNetLink(IEEE1588Port *pPort);
+ virtual void watchNetLink( CommonPort *pPort );
/**
* @brief Gets the payload offset
@@ -292,7 +303,8 @@ public:
* @param type OSLockType enumeration
* @return Pointer to OSLock object
*/
- OSLock * createLock(OSLockType type) {
+ OSLock * createLock( OSLockType type ) const
+ {
LinuxLock *lock = new LinuxLock();
if (lock->initialize(type) != oslock_ok) {
delete lock;
@@ -365,7 +377,8 @@ public:
* @brief Creates LinuxCondition objects
* @return Pointer to the OSCondition object in case of success. NULL otherwise
*/
- OSCondition * createCondition() {
+ OSCondition *createCondition() const
+ {
LinuxCondition *result = new LinuxCondition();
return result->initialize() ? result : NULL;
}
@@ -487,7 +500,8 @@ class LinuxTimerFactory : public OSTimerFactory {
* @brief Creates the linux timer
* @return Pointer to OSTimer object
*/
- virtual OSTimer * createTimer() {
+ virtual OSTimer *createTimer() const
+ {
return new LinuxTimer();
}
};
@@ -551,7 +565,7 @@ class LinuxThreadFactory:public OSThreadFactory {
* @brief Creates a new LinuxThread
* @return Pointer to LinuxThread object
*/
- OSThread * createThread() {
+ OSThread *createThread() const {
return new LinuxThread();
}
};
@@ -570,7 +584,7 @@ public:
*/
virtual bool createInterface
( OSNetworkInterface **net_iface, InterfaceLabel *label,
- HWTimestamper *timestamper );
+ CommonTimestamper *timestamper );
};
/**
@@ -632,6 +646,7 @@ public:
/**
* @brief Updates IPC values
+ *
* @param ml_phoffset Master to local phase offset
* @param ls_phoffset Local to slave phase offset
* @param ml_freqoffset Master to local frequency offset
@@ -641,12 +656,61 @@ public:
* @param pdelay_count Count of pdelays
* @param port_state Port's state
* @param asCapable asCapable flag
+ *
+ * @return TRUE
+ */
+ virtual bool update(
+ int64_t ml_phoffset,
+ int64_t ls_phoffset,
+ FrequencyRatio ml_freqoffset,
+ FrequencyRatio ls_freqoffset,
+ uint64_t local_time,
+ uint32_t sync_count,
+ uint32_t pdelay_count,
+ PortState port_state,
+ bool asCapable );
+
+ /**
+ * @brief Updates grandmaster IPC values
+ *
+ * @param gptp_grandmaster_id Current grandmaster id (all 0's if no grandmaster selected)
+ * @param gptp_domain_number gPTP domain number
+ *
+ * @return TRUE
+ */
+ virtual bool update_grandmaster(
+ uint8_t gptp_grandmaster_id[],
+ uint8_t gptp_domain_number );
+
+ /**
+ * @brief Updates network interface IPC values
+ *
+ * @param clock_identity The clock identity of the interface
+ * @param priority1 The priority1 field of the grandmaster functionality of the interface, or 0xFF if not supported
+ * @param clock_class The clockClass field of the grandmaster functionality of the interface, or 0xFF if not supported
+ * @param offset_scaled_log_variance The offsetScaledLogVariance field of the grandmaster functionality of the interface, or 0x0000 if not supported
+ * @param clock_accuracy The clockAccuracy field of the grandmaster functionality of the interface, or 0xFF if not supported
+ * @param priority2 The priority2 field of the grandmaster functionality of the interface, or 0xFF if not supported
+ * @param domain_number The domainNumber field of the grandmaster functionality of the interface, or 0 if not supported
+ * @param log_sync_interval The currentLogSyncInterval field of the grandmaster functionality of the interface, or 0 if not supported
+ * @param log_announce_interval The currentLogAnnounceInterval field of the grandmaster functionality of the interface, or 0 if not supported
+ * @param log_pdelay_interval The currentLogPDelayReqInterval field of the grandmaster functionality of the interface, or 0 if not supported
+ * @param port_number The portNumber field of the interface, or 0x0000 if not supported
+ *
* @return TRUE
*/
- virtual bool update
- (int64_t ml_phoffset, int64_t ls_phoffset, FrequencyRatio ml_freqoffset,
- FrequencyRatio ls_freqoffset, uint64_t local_time, uint32_t sync_count,
- uint32_t pdelay_count, PortState port_state, bool asCapable );
+ virtual bool update_network_interface(
+ uint8_t clock_identity[],
+ uint8_t priority1,
+ uint8_t clock_class,
+ int16_t offset_scaled_log_variance,
+ uint8_t clock_accuracy,
+ uint8_t priority2,
+ uint8_t domain_number,
+ int8_t log_sync_interval,
+ int8_t log_announce_interval,
+ int8_t log_pdelay_interval,
+ uint16_t port_number );
/**
* @brief unmaps and unlink shared memory
diff --git a/daemons/gptp/linux/src/linux_hal_generic.cpp b/daemons/gptp/linux/src/linux_hal_generic.cpp
index 1dbcbc18..5364fa6a 100644
--- a/daemons/gptp/linux/src/linux_hal_generic.cpp
+++ b/daemons/gptp/linux/src/linux_hal_generic.cpp
@@ -52,7 +52,8 @@
#define RX_PHY_TIME 382
net_result LinuxNetworkInterface::nrecv
-( LinkLayerAddress *addr, uint8_t *payload, size_t &length,struct phy_delay *delay ) {
+( LinkLayerAddress *addr, uint8_t *payload, size_t &length )
+{
fd_set readfds;
int err;
struct msghdr msg;
@@ -71,7 +72,7 @@ net_result LinuxNetworkInterface::nrecv
struct timeval timeout = { 0, 16000 }; // 16 ms
if( !net_lock.lock( &got_net_lock )) {
- fprintf( stderr, "A Failed to lock mutex\n" );
+ GPTP_LOG_ERROR("A Failed to lock mutex");
return net_fatal;
}
if( !got_net_lock ) {
@@ -88,11 +89,11 @@ net_result LinuxNetworkInterface::nrecv
} else if( err == -1 ) {
if( err == EINTR ) {
// Caught signal
- GPTP_LOG_ERROR( "select() recv signal" );
+ GPTP_LOG_ERROR("select() recv signal");
ret = net_trfail;
goto done;
} else {
- GPTP_LOG_ERROR( "select() failed" );
+ GPTP_LOG_ERROR("select() failed");
ret = net_fatal;
goto done;
}
@@ -118,11 +119,11 @@ net_result LinuxNetworkInterface::nrecv
err = recvmsg( sd_event, &msg, 0 );
if( err < 0 ) {
if( errno == ENOMSG ) {
- fprintf( stderr, "Got ENOMSG: %s:%d\n", __FILE__, __LINE__ );
+ GPTP_LOG_ERROR("Got ENOMSG: %s:%d", __FILE__, __LINE__);
ret = net_trfail;
goto done;
}
- GPTP_LOG_ERROR( "recvmsg() failed: %s", strerror(errno) );
+ GPTP_LOG_ERROR("recvmsg() failed: %s", strerror(errno));
ret = net_fatal;
goto done;
}
@@ -136,13 +137,11 @@ net_result LinuxNetworkInterface::nrecv
if
( cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SO_TIMESTAMPING ) {
- Timestamp latency( delay->gb_rx_phy_delay, 0, 0 );
struct timespec *ts_device, *ts_system;
Timestamp device, system;
ts_system = ((struct timespec *) CMSG_DATA(cmsg)) + 1;
system = tsToTimestamp( ts_system );
ts_device = ts_system + 1; device = tsToTimestamp( ts_device );
- device = device - latency;
gtimestamper->pushRXTimestamp( &device );
break;
}
@@ -154,7 +153,7 @@ net_result LinuxNetworkInterface::nrecv
done:
if( !net_lock.unlock()) {
- fprintf( stderr, "A Failed to unlock, %d\n", err );
+ GPTP_LOG_ERROR("A Failed to unlock, %d", err);
return net_fatal;
}
@@ -168,13 +167,13 @@ int findPhcIndex( InterfaceLabel *iface_label ) {
struct ifreq ifr;
if(( ifname = dynamic_cast<InterfaceName *>(iface_label)) == NULL ) {
- fprintf( stderr, "findPTPIndex requires InterfaceName\n" );
+ GPTP_LOG_ERROR("findPTPIndex requires InterfaceName");
return -1;
}
sd = socket( AF_UNIX, SOCK_DGRAM, 0 );
if( sd < 0 ) {
- fprintf( stderr, "findPTPIndex: failed to open socket\n" );
+ GPTP_LOG_ERROR("findPTPIndex: failed to open socket");
return -1;
}
@@ -185,7 +184,7 @@ int findPhcIndex( InterfaceLabel *iface_label ) {
ifr.ifr_data = (char *) &info;
if( ioctl( sd, SIOCETHTOOL, &ifr ) < 0 ) {
- fprintf( stderr, "findPTPIndex: ioctl(SIOETHTOOL) failed\n" );
+ GPTP_LOG_ERROR("findPTPIndex: ioctl(SIOETHTOOL) failed");
return -1;
}
@@ -209,9 +208,9 @@ LinuxTimestamperGeneric::LinuxTimestamperGeneric() {
sd = -1;
}
-bool LinuxTimestamperGeneric::Adjust( void *tmx ) {
+bool LinuxTimestamperGeneric::Adjust( void *tmx ) const {
if( syscall(__NR_clock_adjtime, _private->clockid, tmx ) != 0 ) {
- GPTP_LOG_ERROR( "Failed to adjust PTP clock rate" );
+ GPTP_LOG_ERROR("Failed to adjust PTP clock rate");
return false;
}
return true;
@@ -232,17 +231,17 @@ bool LinuxTimestamperGeneric::HWTimestamper_init
// Determine the correct PTP clock interface
phc_index = findPhcIndex( iface_label );
if( phc_index < 0 ) {
- fprintf( stderr, "Failed to find PTP device index\n" );
+ GPTP_LOG_ERROR("Failed to find PTP device index");
return false;
}
snprintf
( ptp_device+PTP_DEVICE_IDX_OFFS,
sizeof(ptp_device)-PTP_DEVICE_IDX_OFFS, "%d", phc_index );
- fprintf( stderr, "Using clock device: %s\n", ptp_device );
+ GPTP_LOG_ERROR("Using clock device: %s", ptp_device);
phc_fd = open( ptp_device, O_RDWR );
if( phc_fd == -1 || (_private->clockid = FD_TO_CLOCKID(phc_fd)) == -1 ) {
- fprintf( stderr, "Failed to open PTP clock device\n" );
+ GPTP_LOG_ERROR("Failed to open PTP clock device");
return false;
}
@@ -250,14 +249,14 @@ bool LinuxTimestamperGeneric::HWTimestamper_init
// Query PTP stack for availability of HW cross-timestamp
if( ioctl( phc_fd, PTP_CLOCK_GETCAPS, &ptp_capability ) == -1 )
{
- GPTP_LOG_ERROR( "Failed to query PTP clock capabilities" );
+ GPTP_LOG_ERROR("Failed to query PTP clock capabilities");
return false;
}
precise_timestamp_enabled = ptp_capability.cross_timestamping;
#endif
if( !resetFrequencyAdjustment() ) {
- GPTP_LOG_ERROR( "Failed to reset (zero) frequency adjustment" );
+ GPTP_LOG_ERROR("Failed to reset (zero) frequency adjustment");
return false;
}
@@ -269,9 +268,17 @@ bool LinuxTimestamperGeneric::HWTimestamper_init
return true;
}
+void LinuxTimestamperGeneric::HWTimestamper_reset()
+{
+ if( !resetFrequencyAdjustment() ) {
+ GPTP_LOG_ERROR("Failed to reset (zero) frequency adjustment");
+ }
+}
+
int LinuxTimestamperGeneric::HWTimestamper_txtimestamp
-( PortIdentity *identity, uint16_t sequenceId, Timestamp &timestamp,
- unsigned &clock_value, bool last ) {
+( PortIdentity *identity, PTPMessageId messageId, Timestamp &timestamp,
+ unsigned &clock_value, bool last )
+{
int err;
int ret = GPTP_EC_EAGAIN;
struct msghdr msg;
@@ -282,10 +289,7 @@ int LinuxTimestamperGeneric::HWTimestamper_txtimestamp
struct cmsghdr cm;
char control[256];
} control;
- struct phy_delay delay_val;
- get_phy_delay (&delay_val);//gets the phy delay
- Timestamp latency( delay_val.gb_tx_phy_delay, 0, 0 );
if( sd == -1 ) return -1;
memset( &msg, 0, sizeof( msg ));
@@ -324,7 +328,6 @@ int LinuxTimestamperGeneric::HWTimestamper_txtimestamp
system = tsToTimestamp( ts_system );
ts_device = ts_system + 1; device = tsToTimestamp( ts_device );
system._version = version;
- device = device + latency;
device._version = version;
timestamp = device;
ret = 0;
@@ -334,7 +337,7 @@ int LinuxTimestamperGeneric::HWTimestamper_txtimestamp
}
if( ret != 0 ) {
- fprintf( stderr, "Received a error message, but didn't find a valid timestamp\n" );
+ GPTP_LOG_ERROR("Received a error message, but didn't find a valid timestamp");
}
done:
@@ -359,7 +362,7 @@ bool LinuxTimestamperGeneric::post_init( int ifindex, int sd, TicketingLock *loc
err = ioctl( sd, SIOCGIFNAME, &device );
if( err == -1 ) {
GPTP_LOG_ERROR
- ( "Failed to get interface name: %s", strerror( errno ));
+ ("Failed to get interface name: %s", strerror(errno));
return false;
}
@@ -370,7 +373,7 @@ bool LinuxTimestamperGeneric::post_init( int ifindex, int sd, TicketingLock *loc
err = ioctl( sd, SIOCSHWTSTAMP, &device );
if( err == -1 ) {
GPTP_LOG_ERROR
- ( "Failed to configure timestamping: %s", strerror( errno ));
+ ("Failed to configure timestamping: %s", strerror(errno));
return false;
}
@@ -383,8 +386,8 @@ bool LinuxTimestamperGeneric::post_init( int ifindex, int sd, TicketingLock *loc
sizeof(timestamp_flags) );
if( err == -1 ) {
GPTP_LOG_ERROR
- ( "Failed to configure timestamping on socket: %s",
- strerror( errno ));
+ ("Failed to configure timestamping on socket: %s",
+ strerror(errno));
return false;
}
@@ -426,7 +429,8 @@ static inline Timestamp pctTimestamp( struct ptp_clock_time *t ) {
// Use HW cross-timestamp if available
bool LinuxTimestamperGeneric::HWTimestamper_gettime
( Timestamp *system_time, Timestamp *device_time, uint32_t *local_clock,
- uint32_t *nominal_clock_rate ) {
+ uint32_t *nominal_clock_rate ) const
+{
if( phc_fd == -1 )
return false;
@@ -448,7 +452,7 @@ bool LinuxTimestamperGeneric::HWTimestamper_gettime
{
unsigned i;
struct ptp_clock_time *pct;
- struct ptp_clock_time *system_time_l, *device_time_l;
+ struct ptp_clock_time *system_time_l = NULL, *device_time_l = NULL;
int64_t interval = LLONG_MAX;
struct ptp_sys_offset offset;
@@ -468,8 +472,10 @@ bool LinuxTimestamperGeneric::HWTimestamper_gettime
}
}
- *device_time = pctTimestamp( device_time_l );
- *system_time = pctTimestamp( system_time_l );
+ if (device_time_l)
+ *device_time = pctTimestamp( device_time_l );
+ if (system_time_l)
+ *system_time = pctTimestamp( system_time_l );
}
return true;
diff --git a/daemons/gptp/linux/src/linux_hal_generic.hpp b/daemons/gptp/linux/src/linux_hal_generic.hpp
index abe1f276..943294f4 100644
--- a/daemons/gptp/linux/src/linux_hal_generic.hpp
+++ b/daemons/gptp/linux/src/linux_hal_generic.hpp
@@ -91,7 +91,7 @@ public:
* the struct timex
* @return TRUE if ok, FALSE if error.
*/
- bool Adjust( void *tmx );
+ bool Adjust( void *tmx ) const;
/**
* @brief Initializes the Hardware timestamp interface
@@ -103,6 +103,12 @@ public:
( InterfaceLabel *iface_label, OSNetworkInterface *iface );
/**
+ * @brief Reset the Hardware timestamp interface
+ * @return void
+ */
+ virtual void HWTimestamper_reset();
+
+ /**
* @brief Inserts a new timestamp to the beginning of the
* RX timestamp list.
* @param tstamp [in] RX timestamp
@@ -131,34 +137,34 @@ public:
* @return TRUE if got the time successfully, FALSE otherwise
*/
virtual bool HWTimestamper_gettime
- ( Timestamp *system_time, Timestamp *device_time, uint32_t *local_clock,
- uint32_t *nominal_clock_rate );
+ ( Timestamp *system_time, Timestamp *device_time,
+ uint32_t *local_clock, uint32_t *nominal_clock_rate ) const;
/**
* @brief Gets the TX timestamp from hardware interface
* @param identity PTP port identity
- * @param sequenceId Sequence ID
+ * @param PTPMessageId Message ID
* @param timestamp [out] Timestamp value
* @param clock_value [out] Clock value
* @param last Signalizes that it is the last timestamp to get. When TRUE, releases the lock when its done.
* @return GPTP_EC_SUCCESS if no error, GPTP_EC_FAILURE if error and GPTP_EC_EAGAIN to try again.
*/
virtual int HWTimestamper_txtimestamp
- ( PortIdentity *identity, uint16_t sequenceId, Timestamp &timestamp,
+ ( PortIdentity *identity, PTPMessageId messageId, Timestamp &timestamp,
unsigned &clock_value, bool last );
/**
* @brief Gets the RX timestamp from the hardware interface. This
* Currently the RX timestamp is retrieved at LinuxNetworkInterface::nrecv method.
* @param identity PTP port identity
- * @param sequenceId Sequence ID
+ * @param PTPMessageId Message ID
* @param timestamp [out] Timestamp value
* @param clock_value [out] Clock value
* @param last Signalizes that it is the last timestamp to get. When TRUE, releases the lock when its done.
* @return GPTP_EC_SUCCESS if no error, GPTP_EC_FAILURE if error and GPTP_EC_EAGAIN to try again.
*/
virtual int HWTimestamper_rxtimestamp
- ( PortIdentity *identity, uint16_t sequenceId, Timestamp &timestamp,
+ ( PortIdentity *identity, PTPMessageId messageId, Timestamp &timestamp,
unsigned &clock_value, bool last ) {
/* This shouldn't happen. Ever. */
if( rxTimestampList.empty() ) return GPTP_EC_EAGAIN;
@@ -180,7 +186,7 @@ public:
* @param freq_offset Frequency adjustment
* @return TRUE in case of sucess, FALSE if error.
*/
- virtual bool HWTimestamper_adjclockrate( float freq_offset );
+ virtual bool HWTimestamper_adjclockrate( float freq_offset ) const;
#ifdef WITH_IGBLIB
bool HWTimestamper_PPS_start( );
diff --git a/daemons/gptp/linux/src/linux_hal_generic_adj.cpp b/daemons/gptp/linux/src/linux_hal_generic_adj.cpp
index d1122a09..f722ac4a 100644
--- a/daemons/gptp/linux/src/linux_hal_generic_adj.cpp
+++ b/daemons/gptp/linux/src/linux_hal_generic_adj.cpp
@@ -94,7 +94,7 @@ bool LinuxTimestamperGeneric::HWTimestamper_adjclockphase( int64_t phase_adjust
return ret;
}
-bool LinuxTimestamperGeneric::HWTimestamper_adjclockrate( float freq_offset ) {
+bool LinuxTimestamperGeneric::HWTimestamper_adjclockrate( float freq_offset ) const {
struct timex tx;
tx.modes = ADJ_FREQUENCY;
tx.freq = long(freq_offset) << 16;
diff --git a/daemons/gptp/linux/src/linux_hal_i210.cpp b/daemons/gptp/linux/src/linux_hal_i210.cpp
index 391b797d..117a590a 100644
--- a/daemons/gptp/linux/src/linux_hal_i210.cpp
+++ b/daemons/gptp/linux/src/linux_hal_i210.cpp
@@ -78,10 +78,10 @@ pci_connect( device_t *igb_dev )
if (err) {
continue;
}
- printf("attaching to %s\n", devpath);
+ GPTP_LOG_INFO("attaching to %s", devpath);
err = igb_attach(devpath, igb_dev);
if (err) {
- printf("attach failed! (%s)\n", strerror(err));
+ GPTP_LOG_ERROR("attach failed! (%s)", strerror(err));
continue;
}
/*igb_attach_tx missing here ???*/
diff --git a/daemons/gptp/linux/src/linux_hal_intelce.cpp b/daemons/gptp/linux/src/linux_hal_intelce.cpp
index 1d58fa88..99c0fe2a 100644
--- a/daemons/gptp/linux/src/linux_hal_intelce.cpp
+++ b/daemons/gptp/linux/src/linux_hal_intelce.cpp
@@ -121,17 +121,17 @@ int LinuxTimestamperIntelCE::ce_timestamp_common
}
int LinuxTimestamperIntelCE::HWTimestamper_txtimestamp
-( PortIdentity *identity, uint16_t sequenceId, Timestamp &timestamp,
+( PortIdentity *identity, PTPMessageId messageId, Timestamp &timestamp,
unsigned &clock_value, bool last ) {
return ce_timestamp_common
- ( identity, sequenceId, timestamp, clock_value, true );
+ ( identity, messageId.getSequenceId(), timestamp, clock_value, true );
}
int LinuxTimestamperIntelCE::HWTimestamper_rxtimestamp
-( PortIdentity *identity, uint16_t sequenceId, Timestamp &timestamp,
+( PortIdentity *identity, PTPMessageId messageId, Timestamp &timestamp,
unsigned &clock_value, bool last ) {
return ce_timestamp_common
- ( identity, sequenceId, timestamp, clock_value, false );
+ ( identity, messageId.getSequenceId(), timestamp, clock_value, false );
}
bool LinuxTimestamperIntelCE::post_init( int ifindex, int sd, TicketingLock *lock ) {
diff --git a/daemons/gptp/linux/src/linux_hal_intelce.hpp b/daemons/gptp/linux/src/linux_hal_intelce.hpp
index c6e1e31b..f0f57814 100644
--- a/daemons/gptp/linux/src/linux_hal_intelce.hpp
+++ b/daemons/gptp/linux/src/linux_hal_intelce.hpp
@@ -64,7 +64,7 @@ public:
/**
* @brief Gets the TX hardware timestamp value
* @param identity Clock Identity
- * @param sequenceId Sequence ID
+ * @param PTPMessageId Message ID
* @param timestamp [out] Reference to the TX timestamps
* @param clock_value [out] 64 bit timestamp value
* @param last Not used
@@ -72,13 +72,13 @@ public:
* is no data available. -1 in case of error when reading data from hardware interface.
*/
virtual int HWTimestamper_txtimestamp
- ( PortIdentity *identity, uint16_t sequenceId, Timestamp &timestamp,
+ ( PortIdentity *identity, PTPMessageId messageId, Timestamp &timestamp,
unsigned &clock_value, bool last );
/**
* @brief Gets the RX hardware timestamp value
* @param identity Clock identity
- * @param sequenceId Sequence ID
+ * @param PTPMessageId Message ID
* @param timestamp [out] Reference to the RX timestamps
* @param clock_value [out] 64 bit timestamp value
* @param last Not used
@@ -86,7 +86,7 @@ public:
* is no data available. -1 in case of error when reading data from hardware interface.
*/
virtual int HWTimestamper_rxtimestamp
- ( PortIdentity *identity, uint16_t sequenceId, Timestamp &timestamp,
+ ( PortIdentity *identity, PTPMessageId messageId, Timestamp &timestamp,
unsigned &clock_value, bool last );
/**
diff --git a/daemons/gptp/linux/src/linux_hal_persist_file.cpp b/daemons/gptp/linux/src/linux_hal_persist_file.cpp
index e3539473..335c44c6 100644
--- a/daemons/gptp/linux/src/linux_hal_persist_file.cpp
+++ b/daemons/gptp/linux/src/linux_hal_persist_file.cpp
@@ -35,7 +35,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <sys/stat.h>
#include <unistd.h>
-
+#include <gptp_log.hpp>
#include "linux_hal_persist_file.hpp"
class LinuxGPTPPersistFile : public GPTPPersist {
@@ -63,7 +63,7 @@ public:
persistFD = open(persistID, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
if (persistFD == -1) {
- printf("Failed to open restore file\n");
+ GPTP_LOG_ERROR("Failed to open restore file");
return false;
}
return true;
@@ -84,14 +84,14 @@ public:
// MMAP file
struct stat stat0;
if (fstat(persistFD, &stat0) == -1) {
- printf("Failed to stat restore file, %s\n", strerror(errno));
+ GPTP_LOG_ERROR("Failed to stat restore file, %s", strerror(errno));
storedDataLength = 0;
}
else {
storedDataLength = stat0.st_size;
if (storedDataLength != 0) {
if ((restoredata = mmap(NULL, storedDataLength, PROT_READ | PROT_WRITE, MAP_SHARED, persistFD, 0)) == ((void *)-1)) {
- printf("Failed to mmap restore file, %s\n", strerror(errno));
+ GPTP_LOG_ERROR("Failed to mmap restore file, %s", strerror(errno));
}
else {
*bufSize = storedDataLength;
@@ -118,12 +118,15 @@ public:
bool triggerWriteStorage(void)
{
if (!writeCB) {
- printf("Persistent write callback not registered\n");
+ GPTP_LOG_ERROR("Persistent write callback not registered");
}
bool result = false;
if (memoryDataLength > storedDataLength) {
- ftruncate(persistFD, memoryDataLength);
+ int ret = ftruncate(persistFD, memoryDataLength);
+ if (ret != 0) {
+ GPTP_LOG_ERROR("Failed to extend stored data length from %ld to %ld, %s", storedDataLength, memoryDataLength, strerror(errno));
+ }
if (restoredata != ((void *)-1)) {
restoredata = mremap(restoredata, storedDataLength, memoryDataLength, MREMAP_MAYMOVE);
}
diff --git a/daemons/gptp/linux/src/watchdog.cpp b/daemons/gptp/linux/src/watchdog.cpp
new file mode 100644
index 00000000..1406fb55
--- /dev/null
+++ b/daemons/gptp/linux/src/watchdog.cpp
@@ -0,0 +1,46 @@
+#include "watchdog.hpp"
+#include "avbts_osthread.hpp"
+#include "gptp_log.hpp"
+#include <systemd/sd-daemon.h>
+
+
+OSThreadExitCode watchdogUpdateThreadFunction(void *arg)
+{
+ SystemdWatchdogHandler *watchdog = (SystemdWatchdogHandler*) arg;
+ watchdog->run_update();
+ return osthread_ok;
+}
+
+
+SystemdWatchdogHandler::SystemdWatchdogHandler()
+{
+ GPTP_LOG_INFO("Creating Systemd watchdog handler.");
+ LinuxTimerFactory timer_factory = LinuxTimerFactory();
+ timer = timer_factory.createTimer();
+}
+
+SystemdWatchdogHandler::~SystemdWatchdogHandler()
+{
+ //Do nothing
+}
+
+long unsigned int
+SystemdWatchdogHandler::getSystemdWatchdogInterval(int *result)
+{
+ long unsigned int watchdog_interval; //in microseconds
+ *result = sd_watchdog_enabled(0, &watchdog_interval);
+ return watchdog_interval;
+}
+
+void SystemdWatchdogHandler::run_update()
+{
+ while(1)
+ {
+ GPTP_LOG_DEBUG("NOTIFYING WATCHDOG.");
+ sd_notify(0, "WATCHDOG=1");
+ GPTP_LOG_DEBUG("GOING TO SLEEP %lld", update_interval);
+ timer->sleep(update_interval);
+ GPTP_LOG_DEBUG("WATCHDOG WAKE UP");
+ }
+}
+
diff --git a/daemons/gptp/linux/src/watchdog.hpp b/daemons/gptp/linux/src/watchdog.hpp
new file mode 100644
index 00000000..b2e05ccf
--- /dev/null
+++ b/daemons/gptp/linux/src/watchdog.hpp
@@ -0,0 +1,21 @@
+#ifndef SYSTEMDWATCHDOGHANDLER_H
+#define SYSTEMDWATCHDOGHANDLER_H
+#include <linux_hal_common.hpp>
+#include <avbts_ostimer.hpp>
+
+
+OSThreadExitCode watchdogUpdateThreadFunction(void *arg);
+
+class SystemdWatchdogHandler
+{
+public:
+ long unsigned int update_interval;
+ long unsigned int getSystemdWatchdogInterval(int *result);
+ void run_update();
+ SystemdWatchdogHandler();
+ virtual ~SystemdWatchdogHandler();
+private:
+ OSTimer *timer;
+};
+
+#endif // SYSTEMDWATCHDOGHANDLER_H
diff --git a/daemons/gptp/windows/daemon_cl/IPCListener.hpp b/daemons/gptp/windows/daemon_cl/IPCListener.hpp
index 9cc47bce..1ef521b1 100644
--- a/daemons/gptp/windows/daemon_cl/IPCListener.hpp
+++ b/daemons/gptp/windows/daemon_cl/IPCListener.hpp
@@ -57,6 +57,21 @@ public:
ls_phoffset = 0;
ls_freqoffset = 0.0;
local_time = 0;
+
+ memset(gptp_grandmaster_id, 0, sizeof(gptp_grandmaster_id));
+ gptp_domain_number = 0;
+
+ memset(clock_identity, 0, sizeof(clock_identity));
+ priority1 = 0xFF;
+ clock_class = 0xFF;
+ offset_scaled_log_variance = 0x0000;
+ clock_accuracy = 0xFF;
+ priority2 = 0xFF;
+ domain_number = 0;
+ log_sync_interval = 0;
+ log_announce_interval = 0;
+ log_pdelay_interval = 0;
+ port_number = 0x0000;
}
/**
* @brief Get Internal ready flag
diff --git a/daemons/gptp/windows/daemon_cl/daemon_cl.cpp b/daemons/gptp/windows/daemon_cl/daemon_cl.cpp
index 2e5e98db..5bb2f3c5 100644
--- a/daemons/gptp/windows/daemon_cl/daemon_cl.cpp
+++ b/daemons/gptp/windows/daemon_cl/daemon_cl.cpp
@@ -31,6 +31,7 @@ POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
+#include <winsock2.h>
#include <Windows.h>
#include <winnt.h>
#include "ieee1588.hpp"
@@ -38,16 +39,34 @@ POSSIBILITY OF SUCH DAMAGE.
#include "avbts_osnet.hpp"
#include "avbts_oslock.hpp"
#include "windows_hal.hpp"
+#include "avbts_message.hpp"
+#include "gptp_cfg.hpp"
#include <tchar.h>
+#include <iphlpapi.h>
+
+/* Generic PCH delays */
+#define PHY_DELAY_GB_TX_PCH 7750 //1G delay
+#define PHY_DELAY_GB_RX_PCH 7750 //1G delay
+#define PHY_DELAY_MB_TX_PCH 27500 //100M delay
+#define PHY_DELAY_MB_RX_PCH 27500 //100M delay
+
+/* I210 delays */
+#define PHY_DELAY_GB_TX_I210 184 //1G delay
+#define PHY_DELAY_GB_RX_I210 382 //1G delay
+#define PHY_DELAY_MB_TX_I210 1044 //100M delay
+#define PHY_DELAY_MB_RX_I210 2133 //100M delay
#define MACSTR_LENGTH 17
+uint32_t findLinkSpeed(LinkLayerAddress *local_addr);
+
static bool exit_flag;
void print_usage( char *arg0 ) {
fprintf( stderr,
"%s "
- "[-R <priority 1>] <network interface>\n",
+ "[-R <priority 1>] <network interface>\n"
+ "where <network interface> is a MAC address entered as xx-xx-xx-xx-xx-xx\n",
arg0 );
}
@@ -78,14 +97,18 @@ int parseMacAddr( _TCHAR *macstr, uint8_t *octet_string ) {
int _tmain(int argc, _TCHAR* argv[])
{
- IEEE1588PortInit_t portInit;
+ PortInit_t portInit;
+
+ phy_delay_map_t ether_phy_delay;
+ ether_phy_delay[LINKSPEED_1G].set_delay
+ (PHY_DELAY_GB_TX_PCH, PHY_DELAY_GB_RX_PCH);
+ ether_phy_delay[LINKSPEED_100MB].set_delay
+ (PHY_DELAY_MB_TX_PCH, PHY_DELAY_MB_RX_PCH);
+
portInit.clock = NULL;
portInit.index = 1;
- portInit.forceSlave = false;
- portInit.accelerated_sync_count = 0;
portInit.timestamper = NULL;
- portInit.offset = 0;
portInit.net_label = NULL;
portInit.automotive_profile = false;
portInit.isGM = false;
@@ -98,6 +121,8 @@ int _tmain(int argc, _TCHAR* argv[])
portInit.thread_factory = NULL;
portInit.timer_factory = NULL;
portInit.lock_factory = NULL;
+ portInit.neighborPropDelayThreshold =
+ CommonPort::NEIGHBOR_PROP_DELAY_THRESH;
bool syntonize = false;
uint8_t priority1 = 248;
@@ -121,8 +146,15 @@ int _tmain(int argc, _TCHAR* argv[])
ipc = NULL;
}
+ // If there are no arguments, output usage
+ if (1 == argc) {
+ print_usage(argv[0]);
+ return -1;
+ }
+
+
/* Process optional arguments */
- for( i = 1; i < argc-1; ++i ) {
+ for( i = 1; i < argc; ++i ) {
if( ispunct(argv[i][0]) ) {
if( toupper( argv[i][1] ) == 'H' ) {
print_usage( argv[0] );
@@ -145,22 +177,23 @@ int _tmain(int argc, _TCHAR* argv[])
}
}
+ // the last argument is supposed to be a MAC address, so decrement argv index to read it
+ i--;
+
// Create Low level network interface object
uint8_t local_addr_ostr[ETHER_ADDR_OCTETS];
- if( i >= argc ) {
- print_usage( argv[0] );
- return -1;
- }
parseMacAddr( argv[i], local_addr_ostr );
LinkLayerAddress local_addr(local_addr_ostr);
portInit.net_label = &local_addr;
// Create HWTimestamper object
portInit.timestamper = new WindowsTimestamper();
// Create Clock object
- portInit.clock = new IEEE1588Clock( false, false, priority1, portInit.timestamper, timerq_factory, ipc, portInit.lock_factory ); // Do not force slave
+ portInit.clock = new IEEE1588Clock( false, false, priority1, timerq_factory, ipc, portInit.lock_factory ); // Do not force slave
// Create Port Object linked to clock and low level
- IEEE1588Port *port = new IEEE1588Port( &portInit );
- if (!port->init_port(phy_delays)) {
+ portInit.phy_delay = &ether_phy_delay;
+ EtherPort *port = new EtherPort( &portInit );
+ port->setLinkSpeed(findLinkSpeed(&local_addr));
+ if ( !port->init_port() ) {
printf( "Failed to initialize port\n" );
return -1;
}
@@ -179,3 +212,47 @@ int _tmain(int argc, _TCHAR* argv[])
return 0;
}
+#define WIN_LINKSPEED_MULT (1000/*1 Kbit*/)
+
+uint32_t findLinkSpeed( LinkLayerAddress *local_addr )
+{
+ ULONG ret_sz;
+ char *buffer;
+ PIP_ADAPTER_ADDRESSES pAddr;
+ ULONG err;
+ uint32_t ret;
+
+ buffer = (char *) malloc((size_t)15000);
+ ret_sz = 15000;
+ pAddr = (PIP_ADAPTER_ADDRESSES)buffer;
+ err = GetAdaptersAddresses( AF_UNSPEC, 0, NULL, pAddr, &ret_sz );
+ for (; pAddr != NULL; pAddr = pAddr->Next)
+ {
+ //fprintf(stderr, "** here : %p\n", pAddr);
+ if (pAddr->PhysicalAddressLength == ETHER_ADDR_OCTETS &&
+ *local_addr == LinkLayerAddress(pAddr->PhysicalAddress))
+ {
+ break;
+ }
+ }
+
+ if (pAddr == NULL)
+ return INVALID_LINKSPEED;
+
+ switch ( pAddr->ReceiveLinkSpeed / WIN_LINKSPEED_MULT )
+ {
+ default:
+ GPTP_LOG_ERROR("Can't find link speed, %llu", pAddr->ReceiveLinkSpeed);
+ ret = INVALID_LINKSPEED;
+ break;
+ case LINKSPEED_1G:
+ ret = LINKSPEED_1G;
+ break;
+ case LINKSPEED_100MB:
+ ret = LINKSPEED_100MB;
+ break;
+ }
+
+ delete buffer;
+ return ret;
+} \ No newline at end of file
diff --git a/daemons/gptp/windows/daemon_cl/gptp.manifest b/daemons/gptp/windows/daemon_cl/gptp.manifest
new file mode 100644
index 00000000..fde96021
--- /dev/null
+++ b/daemons/gptp/windows/daemon_cl/gptp.manifest
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
+ <security>
+ <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
+ <requestedExecutionLevel level="asInvoker" uiAccess="false" />
+ </requestedPrivileges>
+ </security>
+ </trustInfo>
+
+ <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+ <application>
+ <!-- Windows Vista and Windows Server 2008 -->
+ <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"></supportedOS>
+
+ <!-- Windows 7 and Windows Server 2008 R2 -->
+ <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+
+ <!-- Windows 8 and Windows Server 2012 -->
+ <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"></supportedOS>
+
+ <!-- Windows 8.1 and Windows Server 2012 R2 -->
+ <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+
+ <!-- Windows 10 -->
+ <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+
+ </application>
+ </compatibility>
+</asmv1:assembly>
diff --git a/daemons/gptp/windows/daemon_cl/tsc.hpp b/daemons/gptp/windows/daemon_cl/tsc.hpp
index a958f461..ed22752c 100644
--- a/daemons/gptp/windows/daemon_cl/tsc.hpp
+++ b/daemons/gptp/windows/daemon_cl/tsc.hpp
@@ -38,11 +38,6 @@
#include <intrin.h>
#include <stdint.h>
-#include <VersionHelpers.h>
-
-#define WIN10_MAJOR 0x0A
-#define WIN10_MINOR 0x00
-#define WIN10_SVC 0x00
/**
* @brief Gets the processor timestamp
@@ -106,6 +101,7 @@ inline uint32_t FindFrequencyByModel(uint8_t model_query) {
inline uint64_t getTSCFrequency( unsigned millis ) {
int max_cpuid_level;
int tmp[4];
+ BOOL is_windows_10;
// Find the max cpuid level, and if possible find clock info
__cpuid(tmp, 0);
@@ -113,11 +109,22 @@ inline uint64_t getTSCFrequency( unsigned millis ) {
if (max_cpuid_level >= CLOCK_INFO_CPUID_LEAF)
__cpuid(tmp, CLOCK_INFO_CPUID_LEAF);
+ // Determine if the OS is Windows 10 or later.
+ {
+ OSVERSIONINFOEXW osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 };
+ DWORDLONG const dwlConditionMask = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL);
+ osvi.dwMajorVersion = 10;
+
+ // NOTE: VerifyVersionInfo returns false when called by applications that do not have a compatibility manifest for Windows 10,
+ // even when the current operating system version is Windows 10.
+ is_windows_10 = VerifyVersionInfoW(&osvi, VER_MAJORVERSION, dwlConditionMask) != FALSE;
+ }
+
// For pre-Win10 on 6th Generation or greater Intel CPUs the raw hardware
// clock will be returned, *else* use QPC for everything else
//
// EAX (tmp[0]) must be >= 1, See Intel SDM 17.15.4 "Invariant Time-keeping"
- if (!IsWindowsVersionOrGreater(WIN10_MAJOR, WIN10_MINOR, WIN10_SVC) &&
+ if (is_windows_10 &&
max_cpuid_level >= CLOCK_INFO_CPUID_LEAF &&
tmp[0] >= 1) {
SYSTEM_INFO info;
diff --git a/daemons/gptp/windows/daemon_cl/windows_hal.cpp b/daemons/gptp/windows/daemon_cl/windows_hal.cpp
index ede0fdb2..a05d473c 100644
--- a/daemons/gptp/windows/daemon_cl/windows_hal.cpp
+++ b/daemons/gptp/windows/daemon_cl/windows_hal.cpp
@@ -75,7 +75,6 @@ bool WindowsTimestamper::HWTimestamper_init( InterfaceLabel *iface_label, OSNetw
PIP_ADAPTER_INFO pAdapterInfo;
IP_ADAPTER_INFO AdapterInfo[32]; // Allocate information for up to 32 NICs
DWORD dwBufLen = sizeof(AdapterInfo); // Save memory size of buffer
- struct phy_delay delay_val;
DWORD dwStatus = GetAdaptersInfo( AdapterInfo, &dwBufLen );
if( dwStatus != ERROR_SUCCESS ) return false;
@@ -88,8 +87,6 @@ bool WindowsTimestamper::HWTimestamper_init( InterfaceLabel *iface_label, OSNetw
if( pAdapterInfo == NULL ) return false;
- get_phy_delay(&delay_val);
-
DeviceClockRateMapping *rate_map = DeviceClockRateMap;
while (rate_map->device_desc != NULL)
{
@@ -105,42 +102,6 @@ bool WindowsTimestamper::HWTimestamper_init( InterfaceLabel *iface_label, OSNetw
return false;
}
- DevicePhyDelayMapping *phy_map = DevicePhyDelayMap;
- while (phy_map->device_desc != NULL)
- {
- if (strstr(pAdapterInfo->Description, phy_map->device_desc) != NULL)
- break;
- ++phy_map;
- }
- if (phy_map->device_desc != NULL) {
- if(delay_val.gb_rx_phy_delay == -1)
- delay_val.gb_rx_phy_delay = phy_map->delay.gb_rx_phy_delay;
- if (delay_val.gb_tx_phy_delay == -1)
- delay_val.gb_tx_phy_delay = phy_map->delay.gb_tx_phy_delay;
- if (delay_val.mb_rx_phy_delay == -1)
- delay_val.mb_rx_phy_delay = phy_map->delay.mb_rx_phy_delay;
- if (delay_val.mb_tx_phy_delay == -1)
- delay_val.mb_tx_phy_delay = phy_map->delay.mb_tx_phy_delay;
- set_phy_delay(&delay_val);
- }
-
- if (delay_val.gb_rx_phy_delay == -1) {
- GPTP_LOG_ERROR("Warning: Gbit receive PHY delay is unknown using 0");
- delay_val.gb_rx_phy_delay = 0;
- }
- if (delay_val.gb_tx_phy_delay == -1) {
- GPTP_LOG_ERROR("Warning: Gbit transmit PHY delay is unknown using 0");
- delay_val.gb_tx_phy_delay = 0;
- }
- if (delay_val.mb_rx_phy_delay == -1) {
- GPTP_LOG_ERROR("Warning: Mbit receive PHY delay is unknown using 0");
- delay_val.mb_rx_phy_delay = 0;
- }
- if (delay_val.mb_tx_phy_delay == -1) {
- GPTP_LOG_ERROR("Warning: Mbit transmit PHY delay is unknown using 0");
- delay_val.gb_tx_phy_delay = 0;
- }
-
GPTP_LOG_INFO( "Adapter UID: %s\n", pAdapterInfo->AdapterName );
PLAT_strncpy( network_card_id, NETWORK_CARD_ID_PREFIX, 63 );
PLAT_strncpy( network_card_id+strlen(network_card_id), pAdapterInfo->AdapterName, 63-strlen(network_card_id) );
@@ -175,10 +136,17 @@ bool WindowsNamedPipeIPC::init(OS_IPC_ARG *arg) {
return true;
}
-bool WindowsNamedPipeIPC::update(int64_t ml_phoffset, int64_t ls_phoffset, FrequencyRatio ml_freqoffset, FrequencyRatio ls_freq_offset, uint64_t local_time,
- uint32_t sync_count, uint32_t pdelay_count, PortState port_state, bool asCapable) {
-
-
+bool WindowsNamedPipeIPC::update(
+ int64_t ml_phoffset,
+ int64_t ls_phoffset,
+ FrequencyRatio ml_freqoffset,
+ FrequencyRatio ls_freq_offset,
+ uint64_t local_time,
+ uint32_t sync_count,
+ uint32_t pdelay_count,
+ PortState port_state,
+ bool asCapable )
+{
lOffset_.get();
lOffset_.local_time = local_time;
lOffset_.ml_freqoffset = ml_freqoffset;
@@ -191,8 +159,52 @@ bool WindowsNamedPipeIPC::update(int64_t ml_phoffset, int64_t ls_phoffset, Frequ
return true;
}
+bool WindowsNamedPipeIPC::update_grandmaster(
+ uint8_t gptp_grandmaster_id[],
+ uint8_t gptp_domain_number )
+{
+ lOffset_.get();
+ memcpy(lOffset_.gptp_grandmaster_id, gptp_grandmaster_id, PTP_CLOCK_IDENTITY_LENGTH);
+ lOffset_.gptp_domain_number = gptp_domain_number;
+
+ if (!lOffset_.isReady()) lOffset_.setReady(true);
+ lOffset_.put();
+ return true;
+}
+
+bool WindowsNamedPipeIPC::update_network_interface(
+ uint8_t clock_identity[],
+ uint8_t priority1,
+ uint8_t clock_class,
+ int16_t offset_scaled_log_variance,
+ uint8_t clock_accuracy,
+ uint8_t priority2,
+ uint8_t domain_number,
+ int8_t log_sync_interval,
+ int8_t log_announce_interval,
+ int8_t log_pdelay_interval,
+ uint16_t port_number )
+{
+ lOffset_.get();
+ memcpy(lOffset_.clock_identity, clock_identity, PTP_CLOCK_IDENTITY_LENGTH);
+ lOffset_.priority1 = priority1;
+ lOffset_.clock_class = clock_class;
+ lOffset_.offset_scaled_log_variance = offset_scaled_log_variance;
+ lOffset_.clock_accuracy = clock_accuracy;
+ lOffset_.priority2 = priority2;
+ lOffset_.domain_number = domain_number;
+ lOffset_.log_sync_interval = log_sync_interval;
+ lOffset_.log_announce_interval = log_announce_interval;
+ lOffset_.log_pdelay_interval = log_pdelay_interval;
+ lOffset_.port_number = port_number;
+
+ if (!lOffset_.isReady()) lOffset_.setReady(true);
+ lOffset_.put();
+ return true;
+}
+
-void WindowsPCAPNetworkInterface::watchNetLink(IEEE1588Port *pPort)
+void WindowsPCAPNetworkInterface::watchNetLink( CommonPort *pPort)
{
/* ToDo add link up/down detection, Google MIB_IPADDR_DISCONNECTED */
}
diff --git a/daemons/gptp/windows/daemon_cl/windows_hal.hpp b/daemons/gptp/windows/daemon_cl/windows_hal.hpp
index 8c12c807..f5192910 100644
--- a/daemons/gptp/windows/daemon_cl/windows_hal.hpp
+++ b/daemons/gptp/windows/daemon_cl/windows_hal.hpp
@@ -46,6 +46,7 @@
#include "avbts_osthread.hpp"
#include "packet.hpp"
#include "ieee1588.hpp"
+#include "ether_tstamper.hpp"
#include "iphlpapi.h"
#include "windows_ipc.hpp"
#include "tsc.hpp"
@@ -70,6 +71,7 @@ public:
/**
* @brief Sends a packet to a remote address
* @param addr [in] Destination link Layer address
+ * @param etherType [in] The EtherType of the message in host order
* @param payload [in] Data buffer
* @param length Size of buffer
* @param timestamp TRUE: Use timestamp, FALSE otherwise
@@ -89,7 +91,8 @@ public:
* @param delay [in] Specifications for PHY input and output delays in nanoseconds
* @return net_result structure
*/
- virtual net_result nrecv(LinkLayerAddress *addr, uint8_t *payload, size_t &length, struct phy_delay *delay) {
+ virtual net_result nrecv( LinkLayerAddress *addr, uint8_t *payload, size_t &length )
+ {
packet_addr_t dest;
packet_error_t pferror = recvFrame( handle, &dest, payload, length );
if( pferror != PACKET_NO_ERROR && pferror != PACKET_RECVTIMEOUT_ERROR ) return net_fatal;
@@ -109,7 +112,7 @@ public:
/**
* @brief Watch for netlink changes.
*/
- virtual void watchNetLink(IEEE1588Port *pPort);
+ virtual void watchNetLink( CommonPort *pPort );
/**
* @brief Gets the offset to the start of data in the Layer 2 Frame
@@ -145,7 +148,7 @@ public:
* @param timestamper [in] HWTimestamper instance
* @return TRUE success; FALSE error
*/
- virtual bool createInterface( OSNetworkInterface **net_iface, InterfaceLabel *label, HWTimestamper *timestamper ) {
+ virtual bool createInterface( OSNetworkInterface **net_iface, InterfaceLabel *label, CommonTimestamper *timestamper ) {
WindowsPCAPNetworkInterface *net_iface_l = new WindowsPCAPNetworkInterface();
LinkLayerAddress *addr = dynamic_cast<LinkLayerAddress *>(label);
if( addr == NULL ) goto error_nofree;
@@ -257,7 +260,7 @@ public:
* @param type Lock type - OSLockType
* @return New lock on OSLock format
*/
- OSLock *createLock( OSLockType type ) {
+ OSLock *createLock( OSLockType type ) const {
WindowsLock *lock = new WindowsLock();
if( !lock->initialize( type )) {
delete lock;
@@ -326,7 +329,7 @@ public:
*/
class WindowsConditionFactory : public OSConditionFactory {
public:
- OSCondition *createCondition() {
+ OSCondition *createCondition() const {
WindowsCondition *result = new WindowsCondition();
return result->initialize() ? result : NULL;
}
@@ -513,7 +516,7 @@ public:
* @brief Creates a new timer
* @return New windows OSTimer
*/
- virtual OSTimer *createTimer() {
+ virtual OSTimer *createTimer() const {
return new WindowsTimer();
}
};
@@ -582,7 +585,7 @@ public:
* @brief Creates a new windows thread
* @return New thread of type OSThread
*/
- OSThread *createThread() {
+ OSThread *createThread() const {
return new WindowsThread();
}
};
@@ -602,6 +605,9 @@ typedef struct
char *device_desc;
} DeviceClockRateMapping;
+/**
+* @brief Maps network device type to device clock rate
+*/
static DeviceClockRateMapping DeviceClockRateMap[] =
{
{ 1000000000, I217_DESC },
@@ -609,30 +615,16 @@ static DeviceClockRateMapping DeviceClockRateMap[] =
{ 0, NULL },
};
-typedef struct
-{
- struct phy_delay delay;
- char *device_desc;
-} DevicePhyDelayMapping;
-
-static DevicePhyDelayMapping DevicePhyDelayMap[] =
-{
- {{ -1, -1, 6950, 8050, }, I217_DESC },
- {{ -1, -1, 6700, 7750, }, I219_DESC },
- {{ -1, -1, -1, -1 }, NULL },
-};
-
-
/**
* @brief Windows HWTimestamper implementation
*/
-class WindowsTimestamper : public HWTimestamper {
+class WindowsTimestamper : public EtherTimestamper {
private:
// No idea whether the underlying implementation is thread safe
HANDLE miniport;
LARGE_INTEGER tsc_hz;
LARGE_INTEGER netclock_hz;
- DWORD readOID( NDIS_OID oid, void *output_buffer, DWORD size, DWORD *size_returned ) {
+ DWORD readOID( NDIS_OID oid, void *output_buffer, DWORD size, DWORD *size_returned ) const {
NDIS_OID oid_l = oid;
DWORD rc = DeviceIoControl(
miniport,
@@ -646,19 +638,19 @@ private:
if( rc == 0 ) return GetLastError();
return ERROR_SUCCESS;
}
- Timestamp nanoseconds64ToTimestamp( uint64_t time ) {
+ Timestamp nanoseconds64ToTimestamp( uint64_t time ) const {
Timestamp timestamp;
timestamp.nanoseconds = time % 1000000000;
timestamp.seconds_ls = (time / 1000000000) & 0xFFFFFFFF;
timestamp.seconds_ms = (uint16_t)((time / 1000000000) >> 32);
return timestamp;
}
- uint64_t scaleNativeClockToNanoseconds( uint64_t time ) {
+ uint64_t scaleNativeClockToNanoseconds( uint64_t time ) const {
long double scaled_output = ((long double)netclock_hz.QuadPart)/1000000000;
scaled_output = ((long double) time)/scaled_output;
return (uint64_t) scaled_output;
}
- uint64_t scaleTSCClockToNanoseconds( uint64_t time ) {
+ uint64_t scaleTSCClockToNanoseconds( uint64_t time ) const {
long double scaled_output = ((long double)tsc_hz.QuadPart)/1000000000;
scaled_output = ((long double) time)/scaled_output;
return (uint64_t) scaled_output;
@@ -685,7 +677,7 @@ public:
* @return True in case of success. FALSE in case of error
*/
virtual bool HWTimestamper_gettime( Timestamp *system_time, Timestamp *device_time, uint32_t *local_clock,
- uint32_t *nominal_clock_rate ) {
+ uint32_t *nominal_clock_rate ) const {
DWORD buf[6];
DWORD returned;
uint64_t now_net, now_tsc;
@@ -710,22 +702,18 @@ public:
/**
* @brief Gets the TX timestamp
* @param identity [in] PortIdentity interface
- * @param sequenceId Sequence ID
+ * @param PTPMessageId Message ID
* @param timestamp [out] TX hardware timestamp
* @param clock_value Not used
* @param last Not used
* @return GPTP_EC_SUCCESS if no error, GPTP_EC_FAILURE if error and GPTP_EC_EAGAIN to try again.
*/
- virtual int HWTimestamper_txtimestamp( PortIdentity *identity, uint16_t sequenceId, Timestamp &timestamp, unsigned &clock_value, bool last )
+ virtual int HWTimestamper_txtimestamp(PortIdentity *identity, PTPMessageId messageId, Timestamp &timestamp, unsigned &clock_value, bool last)
{
DWORD buf[4], buf_tmp[4];
DWORD returned = 0;
uint64_t tx_r,tx_s;
DWORD result;
- struct phy_delay delay_val;
-
- get_phy_delay(&delay_val);//gets the phy delay
- Timestamp latency(delay_val.gb_tx_phy_delay, 0, 0);
while(( result = readOID( OID_INTEL_GET_TXSTAMP, buf_tmp, sizeof(buf_tmp), &returned )) == ERROR_SUCCESS ) {
memcpy( buf, buf_tmp, sizeof( buf ));
@@ -737,7 +725,7 @@ public:
if( returned != sizeof(buf_tmp) ) return GPTP_EC_EAGAIN;
tx_r = (((uint64_t)buf[1]) << 32) | buf[0];
tx_s = scaleNativeClockToNanoseconds( tx_r );
- timestamp = nanoseconds64ToTimestamp( tx_s ) + latency;
+ timestamp = nanoseconds64ToTimestamp( tx_s );
timestamp._version = version;
return GPTP_EC_SUCCESS;
@@ -746,23 +734,19 @@ public:
/**
* @brief Gets the RX timestamp
* @param identity PortIdentity interface
- * @param sequenceId Sequence ID
+ * @param PTPMessageId Message ID
* @param timestamp [out] RX hardware timestamp
* @param clock_value [out] Not used
* @param last Not used
* @return GPTP_EC_SUCCESS if no error, GPTP_EC_FAILURE if error and GPTP_EC_EAGAIN to try again.
*/
- virtual int HWTimestamper_rxtimestamp( PortIdentity *identity, uint16_t sequenceId, Timestamp &timestamp, unsigned &clock_value, bool last )
+ virtual int HWTimestamper_rxtimestamp(PortIdentity *identity, PTPMessageId messageId, Timestamp &timestamp, unsigned &clock_value, bool last)
{
DWORD buf[4], buf_tmp[4];
DWORD returned;
uint64_t rx_r,rx_s;
DWORD result;
uint16_t packet_sequence_id;
- struct phy_delay delay_val;
-
- get_phy_delay(&delay_val);//gets the phy delay
- Timestamp latency(delay_val.gb_rx_phy_delay, 0, 0);
while(( result = readOID( OID_INTEL_GET_RXSTAMP, buf_tmp, sizeof(buf_tmp), &returned )) == ERROR_SUCCESS ) {
memcpy( buf, buf_tmp, sizeof( buf ));
@@ -770,10 +754,10 @@ public:
if( result != ERROR_GEN_FAILURE ) return GPTP_EC_FAILURE;
if( returned != sizeof(buf_tmp) ) return GPTP_EC_EAGAIN;
packet_sequence_id = *((uint32_t *) buf+3) >> 16;
- if( PLAT_ntohs( packet_sequence_id ) != sequenceId ) return GPTP_EC_EAGAIN;
+ if (PLAT_ntohs(packet_sequence_id) != messageId.getSequenceId()) return GPTP_EC_EAGAIN;
rx_r = (((uint64_t)buf[1]) << 32) | buf[0];
rx_s = scaleNativeClockToNanoseconds( rx_r );
- timestamp = nanoseconds64ToTimestamp( rx_s ) - latency;
+ timestamp = nanoseconds64ToTimestamp( rx_s );
timestamp._version = version;
return GPTP_EC_SUCCESS;
@@ -794,6 +778,7 @@ public:
* @brief Default constructor. Initializes the IPC interface
*/
WindowsNamedPipeIPC() : pipe_(INVALID_HANDLE_VALUE) { };
+
/**
* @brief Destroys the IPC interface
*/
@@ -801,27 +786,81 @@ public:
if (pipe_ != 0 && pipe_ != INVALID_HANDLE_VALUE)
::CloseHandle(pipe_);
}
+
/**
* @brief Initializes the IPC arguments
* @param arg [in] IPC arguments. Not in use
* @return Always returns TRUE.
*/
virtual bool init(OS_IPC_ARG *arg = NULL);
+
/**
* @brief Updates IPC interface values
+ *
* @param ml_phoffset Master to local phase offset
* @param ls_phoffset Local to system phase offset
* @param ml_freqoffset Master to local frequency offset
* @param ls_freq_offset Local to system frequency offset
* @param local_time Local time
- * @param sync_count Counts of sync mesasges
+ * @param sync_count Counts of sync messages
* @param pdelay_count Counts of pdelays
* @param port_state PortState information
- * @param asCapable asCapable flag
- * @return TRUE if sucess; FALSE if error
+ * @param asCapable asCapable flag
+ *
+ * @return TRUE if success; FALSE if error
+ */
+ virtual bool update(
+ int64_t ml_phoffset,
+ int64_t ls_phoffset,
+ FrequencyRatio ml_freqoffset,
+ FrequencyRatio ls_freq_offset,
+ uint64_t local_time,
+ uint32_t sync_count,
+ uint32_t pdelay_count,
+ PortState port_state,
+ bool asCapable );
+
+ /**
+ * @brief Updates grandmaster IPC interface values
+ *
+ * @param gptp_grandmaster_id Current grandmaster id (all 0's if no grandmaster selected)
+ * @param gptp_domain_number gPTP domain number
+ *
+ * @return TRUE if success; FALSE if error
+ */
+ virtual bool update_grandmaster(
+ uint8_t gptp_grandmaster_id[],
+ uint8_t gptp_domain_number );
+
+ /**
+ * @brief Updates network interface IPC interface values
+ *
+ * @param clock_identity The clock identity of the interface
+ * @param priority1 The priority1 field of the grandmaster functionality of the interface, or 0xFF if not supported
+ * @param clock_class The clockClass field of the grandmaster functionality of the interface, or 0xFF if not supported
+ * @param offset_scaled_log_variance The offsetScaledLogVariance field of the grandmaster functionality of the interface, or 0x0000 if not supported
+ * @param clock_accuracy The clockAccuracy field of the grandmaster functionality of the interface, or 0xFF if not supported
+ * @param priority2 The priority2 field of the grandmaster functionality of the interface, or 0xFF if not supported
+ * @param domain_number The domainNumber field of the grandmaster functionality of the interface, or 0 if not supported
+ * @param log_sync_interval The currentLogSyncInterval field of the grandmaster functionality of the interface, or 0 if not supported
+ * @param log_announce_interval The currentLogAnnounceInterval field of the grandmaster functionality of the interface, or 0 if not supported
+ * @param log_pdelay_interval The currentLogPDelayReqInterval field of the grandmaster functionality of the interface, or 0 if not supported
+ * @param port_number The portNumber field of the interface, or 0x0000 if not supported
+ *
+ * @return TRUE if success; FALSE if error
*/
- virtual bool update(int64_t ml_phoffset, int64_t ls_phoffset, FrequencyRatio ml_freqoffset, FrequencyRatio ls_freq_offset, uint64_t local_time,
- uint32_t sync_count, uint32_t pdelay_count, PortState port_state, bool asCapable);
+ virtual bool update_network_interface(
+ uint8_t clock_identity[],
+ uint8_t priority1,
+ uint8_t clock_class,
+ int16_t offset_scaled_log_variance,
+ uint8_t clock_accuracy,
+ uint8_t priority2,
+ uint8_t domain_number,
+ int8_t log_sync_interval,
+ int8_t log_announce_interval,
+ int8_t log_pdelay_interval,
+ uint16_t port_number );
};
#endif
diff --git a/daemons/gptp/windows/daemon_cl/windows_ipc.hpp b/daemons/gptp/windows/daemon_cl/windows_ipc.hpp
index 79da7d10..c1628ac4 100644
--- a/daemons/gptp/windows/daemon_cl/windows_ipc.hpp
+++ b/daemons/gptp/windows/daemon_cl/windows_ipc.hpp
@@ -152,16 +152,39 @@ class WindowsNPipeMessage {
NPIPE_MSG_TYPE getType() { return type; }
};
+#ifndef PTP_CLOCK_IDENTITY_LENGTH
+#define PTP_CLOCK_IDENTITY_LENGTH 8 /*!< Size of a clock identifier stored in the ClockIndentity class, described at IEEE 802.1AS-2011 Clause 8.5.2.4*/
+#endif
+
/**
* @brief Provides an interface for the phase/frequency offsets
*/
class Offset {
public:
- int64_t ml_phoffset; /*!< Master to local phase offset */
- FrequencyRatio ml_freqoffset; /*!< Master to local frequency offset */
- int64_t ls_phoffset; /*!< Local to system phase offset */
- FrequencyRatio ls_freqoffset; /*!< Local to system frequency offset*/
- uint64_t local_time; /*!< Local time*/
+ int64_t ml_phoffset; //!< Master to local phase offset
+ FrequencyRatio ml_freqoffset; //!< Master to local frequency offset
+ int64_t ls_phoffset; //!< Local to system phase offset
+ FrequencyRatio ls_freqoffset; //!< Local to system frequency offset
+ uint64_t local_time; //!< Local time
+
+ /* Current grandmaster information */
+ /* Referenced by the IEEE Std 1722.1-2013 AVDECC Discovery Protocol Data Unit (ADPDU) */
+ uint8_t gptp_grandmaster_id[PTP_CLOCK_IDENTITY_LENGTH]; //!< Current grandmaster id (all 0's if no grandmaster selected)
+ uint8_t gptp_domain_number; //!< gPTP domain number
+
+ /* Grandmaster support for the network interface */
+ /* Referenced by the IEEE Std 1722.1-2013 AVDECC AVB_INTERFACE descriptor */
+ uint8_t clock_identity[PTP_CLOCK_IDENTITY_LENGTH]; //!< The clock identity of the interface
+ uint8_t priority1; //!< The priority1 field of the grandmaster functionality of the interface, or 0xFF if not supported
+ uint8_t clock_class; //!< The clockClass field of the grandmaster functionality of the interface, or 0xFF if not supported
+ int16_t offset_scaled_log_variance; //!< The offsetScaledLogVariance field of the grandmaster functionality of the interface, or 0x0000 if not supported
+ uint8_t clock_accuracy; //!< The clockAccuracy field of the grandmaster functionality of the interface, or 0xFF if not supported
+ uint8_t priority2; //!< The priority2 field of the grandmaster functionality of the interface, or 0xFF if not supported
+ uint8_t domain_number; //!< The domainNumber field of the grandmaster functionality of the interface, or 0 if not supported
+ int8_t log_sync_interval; //!< The currentLogSyncInterval field of the grandmaster functionality of the interface, or 0 if not supported
+ int8_t log_announce_interval; //!< The currentLogAnnounceInterval field of the grandmaster functionality of the interface, or 0 if not supported
+ int8_t log_pdelay_interval; //!< The currentLogPDelayReqInterval field of the grandmaster functionality of the interface, or 0 if not supported
+ uint16_t port_number; //!< The portNumber field of the interface, or 0x0000 if not supported
};
/**
@@ -188,23 +211,6 @@ class WinNPipeOffsetUpdateMessage : public WindowsNPipeMessage {
memset( &this->offset, 0, sizeof( this->offset ));
}
/**
- * @brief Initializes the interface with specific values
- * @param ml_phoffset Master to local phase offset in nano-seconds
- * @param ml_freqoffset Master to local frequency offset in the ::FrequencyRatio format
- * @param ls_phoffset Local to system phase offset in nano-seconds
- * @param ls_freqoffset Local to system frequency offset in the ::FrequencyRatio format
- * @param local_time Local time in nanoseconds
- * @return void
- */
- void init( int64_t ml_phoffset, FrequencyRatio ml_freqoffset, int64_t ls_phoffset, FrequencyRatio ls_freqoffset, uint64_t local_time ) {
- _init();
- this->offset.ml_phoffset = ml_phoffset;
- this->offset.ml_freqoffset = ml_freqoffset;
- this->offset.ls_phoffset = ls_phoffset;
- this->offset.ls_freqoffset = ls_freqoffset;
- this->offset.local_time = local_time;
- }
- /**
* @brief Initializes the interface based on the Offset structure
* @param offset [in] Offset structure
* @return void
@@ -319,7 +325,7 @@ class WinNPipeCtrlMessage : public WindowsNPipeMessage {
uint16_t flags;
public:
/**
- * @brief Initializes interace's internal variables.
+ * @brief Initializes interface's internal variables.
* @return void
*/
void init() {
diff --git a/daemons/gptp/windows/gptp.sln b/daemons/gptp/windows/gptp.sln
deleted file mode 100644
index 8e0cdf65..00000000
--- a/daemons/gptp/windows/gptp.sln
+++ /dev/null
@@ -1,38 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2013
-VisualStudioVersion = 12.0.30110.0
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "daemon_cl", "daemon_cl\daemon_cl.vcxproj", "{590D3055-A068-4B31-B4F9-B2ACC5F93663}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "named_pipe_test", "named_pipe_test\named_pipe_test.vcxproj", "{303FACBB-2A44-4511-A855-2B5B2C0E3A89}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Win32 = Debug|Win32
- Debug|x64 = Debug|x64
- Release|Win32 = Release|Win32
- Release|x64 = Release|x64
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {590D3055-A068-4B31-B4F9-B2ACC5F93663}.Debug|Win32.ActiveCfg = Debug|Win32
- {590D3055-A068-4B31-B4F9-B2ACC5F93663}.Debug|Win32.Build.0 = Debug|Win32
- {590D3055-A068-4B31-B4F9-B2ACC5F93663}.Debug|x64.ActiveCfg = Debug|x64
- {590D3055-A068-4B31-B4F9-B2ACC5F93663}.Debug|x64.Build.0 = Debug|x64
- {590D3055-A068-4B31-B4F9-B2ACC5F93663}.Release|Win32.ActiveCfg = Release|Win32
- {590D3055-A068-4B31-B4F9-B2ACC5F93663}.Release|Win32.Build.0 = Release|Win32
- {590D3055-A068-4B31-B4F9-B2ACC5F93663}.Release|x64.ActiveCfg = Release|x64
- {590D3055-A068-4B31-B4F9-B2ACC5F93663}.Release|x64.Build.0 = Release|x64
- {303FACBB-2A44-4511-A855-2B5B2C0E3A89}.Debug|Win32.ActiveCfg = Debug|Win32
- {303FACBB-2A44-4511-A855-2B5B2C0E3A89}.Debug|Win32.Build.0 = Debug|Win32
- {303FACBB-2A44-4511-A855-2B5B2C0E3A89}.Debug|x64.ActiveCfg = Debug|x64
- {303FACBB-2A44-4511-A855-2B5B2C0E3A89}.Debug|x64.Build.0 = Debug|x64
- {303FACBB-2A44-4511-A855-2B5B2C0E3A89}.Release|Win32.ActiveCfg = Release|Win32
- {303FACBB-2A44-4511-A855-2B5B2C0E3A89}.Release|Win32.Build.0 = Release|Win32
- {303FACBB-2A44-4511-A855-2B5B2C0E3A89}.Release|x64.ActiveCfg = Release|x64
- {303FACBB-2A44-4511-A855-2B5B2C0E3A89}.Release|x64.Build.0 = Release|x64
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
-EndGlobal
diff --git a/daemons/maap/CMakeLists.txt b/daemons/maap/CMakeLists.txt
new file mode 100644
index 00000000..522a776f
--- /dev/null
+++ b/daemons/maap/CMakeLists.txt
@@ -0,0 +1,39 @@
+cmake_minimum_required (VERSION 2.8)
+project (maap)
+
+set (ComDir "./common")
+set (ComSource
+ "${ComDir}/intervals.c"
+ "${ComDir}/maap.c"
+ "${ComDir}/maap_net.c"
+ "${ComDir}/maap_packet.c"
+ "${ComDir}/maap_parse.c"
+ "${ComDir}/maap_log_queue.c"
+)
+include_directories( ${ComDir} )
+
+if(UNIX)
+ set (OsDir "./linux/src")
+ set (OsSource
+ "${OsDir}/maap_daemon.c"
+ "${OsDir}/maap_log_linux.c"
+ "${OsDir}/maap_timer_linux.c"
+ )
+ include_directories( ${OsDir} )
+ add_executable(maap_daemon ${ComSource} ${OsSource})
+ target_link_libraries(maap_daemon rt pthread)
+elseif(WIN32)
+ set (OsDir "./windows/src")
+ set (OsSource
+ "${OsDir}/maap_main.c"
+ "${OsDir}/maap_log_windows.c"
+ "${OsDir}/maap_timer_windows.c"
+ )
+ add_definitions(-D_CRT_SECURE_NO_WARNINGS -DHAVE_REMOTE)
+ include_directories( ${OsDir} )
+ add_executable(maap_daemon ${ComSource} ${OsSource})
+ target_link_libraries(maap_daemon ws2_32)
+endif()
+
+add_subdirectory("test")
+add_subdirectory("tests")
diff --git a/daemons/maap/README.rst b/daemons/maap/README.rst
index 4615ffbc..1832705a 100644
--- a/daemons/maap/README.rst
+++ b/daemons/maap/README.rst
@@ -1,3 +1,20 @@
+OpenAvnu MAAP
+=============
+
+.. contents::
+..
+ 1 Introduction
+ 2 MAAP Server and Client
+ 2.1 Implementation Details
+ 2.2 Linux Specific
+ 2.3 Windows Specific
+ 2.4 Tests
+ 2.5 Known Issues and Future Enhancements
+ 3 API Documentation
+ 4 Client/Server Protocol
+ 4.1 Commands
+ 4.2 Notifications
+
Introduction
------------
@@ -8,59 +25,373 @@ addresses dynamically. MAAP is designed to provide a way to allocate dynamically
the multicast MAC addresses needed by AVTP. MAAP is not designed to allocate locally
administered unicast addresses.
-A block of Multicast MAC addresses has been reserved for the use of AVTP. These addresses are listed in
-MAAP Dynamic Allocation Pool below shown. These addresses are available for dynamic allocation by the MAAP.
-91:E0:F0:00:00:00 – 91:E0:F0:00:FD:FF
+A block of Multicast MAC addresses has been reserved for the use of AVTP. These
+addresses are listed in MAAP Dynamic Allocation Pool below shown. These
+addresses are available for dynamic allocation by MAAP: ``91:E0:F0:00:00:00`` –
+``91:E0:F0:00:FD:FF``.
+
+When you initialize the MAAP server, it will use the reserved range by default,
+but you can override this if your network administration has set aside a
+different range for dynamic allocation to streams.
+
+MAAP Server and Client
+----------------------
+Implementation Details
+++++++++++++++++++++++
+
+This implementation provides a binary that runs in two modes, *client* and
+*server*. A single server instance manages the MAAP protocol for a single
+network interface. The server, which must have sufficient access rights, listens
+for raw network frames matching the MAAP destination MAC address. It also opens
+a local stream socket and listens for client connections. If the server is not
+asked to daemonize itself, it will also listen for commands from the console.
+
+The client opens a socket connection to the server, after which it can send
+commands to the server and receive notifications from it. The binary version of
+this communication protocol is outlined in the ``maap_iface.h`` file in the
+``common`` source directory. Commands and notifications on the console (of
+either the server or client binary) operate in the plain text version of the
+protocol; the client binary translates these to the binary version before
+sending them over the socket to the server.
+
+**Note:** Socket clients may send plain text commands directly to the server,
+but currently the server will only send binary notifications back to socket
+clients. If you build a client into your application, you should include
+``maap_iface.h`` and use the binary protocol.
Linux Specific
++++++++++++++
-To build, execute the linux makefile.
+The MAAP programs can be built in several ways.
-To execute(in root), go to build directory(where binary is created) and run
- maap_daemon [-d] -i interface-name
-such as
- ./maap_daemon -i eth0
+First, the top-level makefile of the OpenAvnu repository will build them as part
+of the ``daemons_all`` and ``maap`` targets.
-The daemon creates a 6 bytes shared memory segment with the key 1234 and writes the allocated mac-addr there.
-The client applications will have to use this key value 1234 in the applications and read the allocated mac-addr
-and use it as dest mac-addr for the packets transmission.
+Second, the makefile can be used directly from the build directory::
+ $ cd daemons/maap/linux/build
+ $ make
-Execute Command :
-------------
+There is also support for building with ``cmake``, both from the top-level
+``CMakeLists.txt`` of the OpenAvnu repository and from the ``CMakeLists.txt`` of
+the ``maap`` directory. The ``cmake`` build rules include testing targets for
+automatically running unit tests.
- sudo ./maap_daemon -i eth0
+Command Line Usage::
+ maap_daemon [ -c | -i interface_name [-d log_file] ] [-p port_num]
-OUTPUT :
-------------
+Command Line Options:
+
+ -c Run as a client (sends commands to the daemon)
+ -i Run as a server monitoring *interface_name*
+ -d Daemonize the server and log to *log_file*
+ -p Specify the control port to connect to (client) or
+ listen to (server). The default *port_num* is ``15364``.
+
+When running the ``maap_daemon`` binary, you select the client mode with the
+``-c`` flag or server mode with ``-i interface_name``. For either case, the ``-p
+port_num`` option will allow changing the client/server communication port. The
+client and server must have the same port selected to communicate.
+
+Without the ``-d log_file`` option, the server will stay in the foreground. It
+will accept plain text commands from ``stdin`` and write plain text
+notifications and log messages to ``stdout``. It will also listen for and accept
+socket clients.
+
+With the ``-d log_file`` option, the server will *daemonize*, i.e. it will
+disassociate itself from the process environment in which it was launched and
+run in the background. Its ``stdin`` and ``stdout`` will go to ``/dev/null`` and
+its ``stderr`` will go to the file named by *log_file*. In this mode, it can
+only be controlled via socket clients.
+
+With the ``-c`` option, the binary runs in *client* mode. It opens a local
+socket on *port_num* to the server process and listens on ``stdin`` for plain
+text commands. The commands a translated to the binary protocol and sent to the
+server. When the server sends notifications, they are translated from binary to
+plain text and they are printed to ``stdout``.
+
+Windows Specific
+++++++++++++++++
+
+A Windows build of the ``common`` code and unit tests has been implemented, but
+platform-specific client and server code still needs to be written.
+
+The Windows build must be performed with ``cmake``, either from the top-level
+``CMakeLists.txt`` of the OpenAvnu repository or from the ``CMakeLists.txt`` of
+the ``maap`` directory. The ``cmake`` build rules include testing targets for
+automatically running unit tests.
+
+Tests
++++++
+
+The code includes unit tests and an integration test program for testing basic
+protocol operation. The unit tests are found in the ``tests`` subdirectory, and
+they are integrated into the ``cmake`` builds. Some support code for the unit
+tests can be found in the files matching the pattern ``test/maap_*_dummy.*``.
+
+A stress test for the interval tree library is also built and run by the
+``cmake`` test rules; the code for this is in ``test/test_intervals.c``.
+
+The integration test program is in the ``test/maap_test.c`` file. This will
+listen on an interface using the *pcap* library and run a series of scripted
+interactions against a MAAP implementation on the other side of the network
+interface. This code is currently Linux-only, and is built by the Linux
+makefile.
+
+Known Issues and Future Enhancements
+++++++++++++++++++++++++++++++++++++
+
+- The server currently only tracks its own reservations. Tracking the
+ ``ANNOUNCE`` messages of other servers on the network would allow us to rule
+ out overlapping request ranges without sending ``PROBE`` messages.
+
+- The server always sends binary protocol notifications to socket clients;
+ sending plain text notifications when commands are sent in plain text would
+ allow using ``telnet`` or ``netcat`` for command line clients instead of the
+ ``-c`` flag to the binary.
+
+- The Windows platform-specific code is incomplete and nonfunctional.
+
+API Documentation
+-----------------
+
+The ``doc`` directory contains a ``CMakeLists.txt`` file that, when included,
+adds the custom target ``doc`` when the build option ``BUILD_DOCUMENTATION`` is
+set. It is not currently included from any higher-level ``CMakeLists.txt``.
+
+A manual documentation build can be achieved by executing the following command
+from the ``doc`` directory::
+
+ $ doxygen Doxyfile.in
+
+The resulting html documentation will be in the ``build`` subdirectory.
+
+Client/Server Protocol
+----------------------
+
+Clients communicate with the server over a binary protocol based on *commands*,
+which are sent from the client to the server; and *notifications*, which are
+sent from the server to the client. This section gives an overview of how the
+commands and responses work; for code-level detail on constructing or
+interpreting them, see the ``common/maap_iface.h`` file.
+
+The supplied client and server binaries also support a plain text version of the
+protocol for testing at the command line; the command *kinds* will be described
+below with their plain text names instead of ther *enum* symbols for the sake of
+readability and to provide some reference for command line usage. When an
+invalid command is given on the plain text console interface, the following
+usage statement will be given::
+
+ init [<range_base> <range_size>] - Initialize the MAAP daemon to recognize
+ the specified range of addresses. If not specified, it uses
+ range_base=0x91e0f0000000, range_size=0xfe00.
+ reserve [<addr_base>] <addr_size> - Reserve a range of addresses of size
+ <addr_size> in the initialized range. If <addr_base> is specified,
+ that address base will be attempted first.
+ release <id> - Release the range of addresses with identifier ID
+ status <id> - Get the range of addresses associated with identifier ID
+ exit - Shutdown the MAAP daemon
+
+Commands
+++++++++
+
+The commands accepted by the server are identified by the ``kind`` field of the
+``Maap_Cmd`` structure, and the fields ``id``, ``start``, and ``count`` contain
+command parameters. The exact meaning of the fields depends on the command, but
+``start`` typically identifies a base MAC address, ``count`` determines the size
+of the range that begins with the address in ``start``, and ``id`` is used to
+reference an existing range allocation.
+
+The following are the command parameter fields:
+
+``kind``
+ This field holds the command kind identifier, which are described below.
+
+``start``
+ This field holds an unsigned 64-bit integer, which should contain a MAC
+ address converted to a native integer with the first-to-transmit bytes of the
+ address in the most significant bits of the 48-bit integer and then
+ zero-extended to 64-bits; e.g. the default MAAP range uses a ``start``
+ parameter of ``0x000091E0F0000000ULL`` for the MAC address
+ ``91:E0:F0:00:00:00``. This way of interpreting an address as an integer
+ corresponds to the ordering rule that SRP uses to determine contiguous ranges.
+
+``count``
+ This field holds an unsigned 32-bit integer, which represents the number of
+ addresses in a range. The default MAAP range uses ``0x0000FE00UL`` as the
+ count, which means that the range extends from ``91:E0:F0:00:00:00`` to
+ ``91:E0:F0:00:FD:FF``.
+
+``id``
+ This field holds a signed 32-bit integer, but all current commands expect a
+ positive value.
+
+In the plain text interface to the protocol, numbers are parsed via the
+``strtol`` family with ``base`` parameter ``16`` for ``start`` and ``0`` for the
+others. This means that for ``base``, all digits are interpreted as hexadecimal
+digits and the ``"0x"`` prefix is optional. For the other parameters, digits are
+parsed as decimal digits unless the ``"0"`` prefix for octal or the ``"0x"``
+prefix for hexadecimal are used.
+
+The following are the current set of command kinds:
+
+``init``
+ This command must be run before any ranges can be reserved. It accepts
+ ``start`` and ``count`` parameters, but default values will be supplied if the
+ plain text interface is being used and no parameters are given. When
+ initialization is complete, a notification will be sent. Initialization only
+ needs to happen once per start of the server.
+
+``reserve``
+ This command requests the server to reserve a range of multicast MAC addresses
+ from the range specified by the ``init`` command, which must have been
+ previously executed. It accepts an optional ``start`` value, which will cause
+ it to use that address as the initial request base, and a mandatory ``count``
+ parameter for the number of contiguous addresses to reserve. If ``start`` is
+ not supplied, a random one will be chosen. When the server receives a valid
+ request for reservation, it immediately sends a notification to indicate it is
+ querying. That notification and all further notifications about the status of
+ the request will include the reservation ``id``, which can be used in other
+ commands to identify it.
+
+``release``
+ This command requests that the server release the reservation, or to stop
+ attempting to acquire it if it has not yet completed the reservation process.
+ The only parameter is ``id``, which is the identifier given in response to a
+ ``reserve`` command. A notification will be sent by the server when the
+ release is completed.
+
+``status``
+ This command asks the server to supply the ``start`` and ``count`` values
+ associated with a particular reservation. The only parameter is ``id``, which
+ is the identifier given in response to a ``reserve`` command. A notification
+ with the requested information will be sent by the server if the ``id`` value
+ corresponds to an active reservation being managed by the server.
+
+``exit``
+ This command asks the server to shut itself down and exit. It takes no
+ parameters. Note that this stops the entire server, not just the current
+ connection to the server.
+
+Notifications
++++++++++++++
+
+Notifications are sent asynchronously by the server to clients to inform them
+about relevant changes to the server's state. The ``kind`` field of the
+``Maap_Notify`` structure identifies the kind of notification, the ``result``
+field contains a general status code, and the ``id``, ``start``, and ``count``
+fields contain extra notification-specific data.
+
+The following are the notification fields:
+
+``kind``
+ This field determines the kind of notification; the different kinds are listed
+ below.
+
+``id``
+ This field contains a signed 32-bit integer; if positive, it represents the
+ identifer of a reservation range. There are no current uses for negative
+ values in the protocol.
+
+``start``
+ This field holds an unsigned 64-bit integer, which should contain a MAC
+ address converted to a native integer with the first-to-transmit bytes of the
+ address in the most significant bits of the 48-bit integer and then
+ zero-extended to 64-bits; e.g. the default MAAP range uses a ``start``
+ parameter of ``0x000091E0F0000000ULL`` for the MAC address
+ ``91:E0:F0:00:00:00``. This way of interpreting an address as an integer
+ corresponds to the ordering rule that SRP uses to determine contiguous ranges.
+
+``count``
+ This field holds an unsigned 32-bit integer, which represents the number of
+ addresses in a range. The default MAAP range uses ``0x0000FE00UL`` as the
+ count, which means that the range extends from ``91:E0:F0:00:00:00`` to
+ ``91:E0:F0:00:FD:FF``.
+
+``result``
+ This field contains a general result code, which may either indicate no error
+ occurred or specify which kind of error occurred. The different result codes
+ are listed below after the kinds of notifications.
+
+The following are the kinds of notifications:
+
+``initialized``
+ This kind of notification is sent in response to receiving an initialization
+ request from a client. The ``start`` and ``count`` fields will contain the
+ range which the MAAP server has been initialized to use for reservations. The
+ ``result`` field will indicate whether the server had been previously
+ initialized before the latest request or not.
+
+``acquiring``
+ This kind of notification is sent immediately in response to a ``reserve``
+ command. If ``result`` does not indicate an error, then ``start`` and
+ ``count`` will indicate the address range that the server is currently
+ attempting to reserve. These should *not* be used for streams yet, as a
+ conflict may yet be detected that could force a different range selection.
+ Most importantly, the ``id`` field will contain the identifier that must be
+ used by the client to refer to this reservation in ``release`` or ``status``
+ commands.
+
+``acquired``
+ This kind of notification is sent to indicate either successful or
+ unsuccessful completion of a particular ``reserve`` command that has gone
+ through the ``acquiring`` phase. If there is no error indicated in ``result``,
+ then ``start`` and ``count`` contain the reserved address range that can now
+ be used for streams. The ``id`` field will contain the identifier that must be
+ used by the client to refer to this reservation in ``release`` or ``status``
+ commands.
+
+``released``
+ This kind of notification indicates that the reservation identified in a
+ ``release`` command has now been released. The ``start`` and ``count`` fields
+ contain the address range that the reservation previously held; they must no
+ longer be used for streams. The ``id`` field holds the identifer that was
+ associated with this reservation; it is no longer valid as an identifier.
+
+``status``
+ This kind of notification describes the reservation identified in a ``status``
+ command without changing it. The ``id`` field holds the identifier that was
+ given to the ``status`` command. The ``start`` and ``count`` fields describe
+ the range of addresses held by the reservation.
+
+``yielded``
+ This kind of notification is not sent in response to a command, but when the
+ network protocol forced the server to yield a previously-acquired address
+ range. The ``id`` field has the same value as when the server sent the
+ ``acquiring`` and ``acquired`` notifications for the range, and the actual
+ range values are held in ``start`` and ``count``. Any usage of the addresses
+ in the yielded range must be immediately stopped. Unless the ``status`` code
+ indicates an error, the server will attempt to reserve a new range with the
+ same size. This new range (if successfully acquired) will use the same ``id``
+ field value.
+
+The following are the result codes:
-$ sudo ./maap_daemon -i eth0
+``none``
+ This value indicates that there were no errors associated with this
+ notification.
-SENT MAAP_PROBE
+``requires initialization``
+ This value indicates that the server has not yet been initialized.
-SENT MAAP_PROBE
+``already initialized``
+ This value indicates that the server was already initialized when the latest
+ ``init`` command was received.
-SENT MAAP_PROBE
+``reserve not available``
+ This value indicates that no block of addresses of the requested size was
+ available. A smaller request may be necessary.
-SENT MAAP_ANNOUNCE
+``release invalid id``
+ This value indicates that a ``release`` command was given with an invalid
+ ``id`` field.
-ANNOUNCED ADDRESS:
-0x91 0xe0 0xf0 0 0x95 0x18
+``out of memory``
+ This value indicates that the request could not be completed because the
+ server is out of memory.
-STATE change to DEFEND:
-
-SENT MAAP_ANNOUNCE
-SENT MAAP_ANNOUNCE
-SENT MAAP_ANNOUNCE
+``internal``
+ This value indicates that an unspecified internal server error occurred.
-Here in the case the allocated address which starts from 0x91 0xe0 0xf0 0 0x95 0x18
-This mac-addr is assigned to Dest-Mac for packets transfer.
-ADDR[0] = 0x91
-ADDR[1] = 0xe0
-ADDR[2] = 0xf0
-ADDR[3] = 0
-ADDR[4] = 0x95
-ADDR[5] = 0x18
diff --git a/daemons/maap/common/intervals.c b/daemons/maap/common/intervals.c
new file mode 100644
index 00000000..3efd6870
--- /dev/null
+++ b/daemons/maap/common/intervals.c
@@ -0,0 +1,220 @@
+/*************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************/
+
+#include <stdlib.h>
+#include "intervals.h"
+
+static int check_overlap(Interval *a, Interval *b) {
+ return (a->low <= b->high && b->low <= a->high);
+}
+
+Interval *alloc_interval(uint32_t start, uint32_t count) {
+ Interval *i;
+ i = calloc(1, sizeof (Interval));
+ if (i) {
+ i->low = start;
+ i->high = start + count - 1;
+ }
+ return i;
+}
+
+void free_interval(Interval *node) {
+ free(node);
+}
+
+int insert_interval(Interval **root, Interval *node) {
+ Interval *current;
+
+ if (*root == NULL) {
+ *root = node;
+ return INTERVAL_SUCCESS;
+ }
+ current = *root;
+ while (1) {
+ if (check_overlap(current, node)) {
+ return INTERVAL_OVERLAP;
+ }
+ if (node->low < current->low) {
+ if (current->left_child == NULL) {
+ current->left_child = node;
+ node->parent = current;
+ break;
+ } else {
+ current = current->left_child;
+ }
+ } else {
+ if (current->right_child == NULL) {
+ current->right_child = node;
+ node->parent = current;
+ break;
+ } else {
+ current = current->right_child;
+ }
+ }
+ }
+
+ return INTERVAL_SUCCESS;
+}
+
+Interval *remove_interval(Interval **root, Interval *node) {
+ Interval *snip, *child;
+
+ /* If the node to remove does not have two children, we will snip it,
+ otherwise we will swap it with its successor and snip that one */
+ if (!node->left_child || !node->right_child) {
+ snip = node;
+ } else {
+ snip = next_interval(node);
+ }
+
+ /* If the node to snip has a child, make its parent link point to the snipped
+ node's parent */
+ if (snip->left_child) {
+ child = snip->left_child;
+ } else {
+ child = snip->right_child;
+ }
+ if (child) {
+ child->parent = snip->parent;
+ }
+
+ /* If the snipped node has no parent, it is the root node and we use the
+ provided root pointer to point to the child. Otherwise, we find if the
+ snipped node was a left or right child and set the appropriate link in the
+ parent node */
+ if (!snip->parent) {
+ *root = child;
+ } else if (snip == snip->parent->left_child) {
+ snip->parent->left_child = child;
+ } else {
+ snip->parent->right_child = child;
+ }
+
+ /* Swap the contents of the node passed in to remove with the one chosen to be
+ snipped */
+ if (snip != node) {
+ void *old_data = node->data;
+ node->low = snip->low;
+ node->high = snip->high;
+ node->data = snip->data;
+ snip->data = old_data;
+ }
+
+ return snip;
+}
+
+Interval *minimum_interval(Interval *root) {
+ Interval *current = root;
+
+ while (1) {
+ if (current && current->left_child) {
+ current = current->left_child;
+ } else {
+ return current;
+ }
+ }
+}
+
+Interval *maximum_interval(Interval *root) {
+ Interval *current = root;
+
+ while (1) {
+ if (current && current->right_child) {
+ current = current->right_child;
+ } else {
+ return current;
+ }
+ }
+}
+
+Interval *next_interval(Interval *node) {
+ Interval *parent, *child;
+
+ if (node->right_child) {
+ return minimum_interval(node->right_child);
+ }
+
+ child = node;
+ parent = node->parent;
+ while (parent && child == parent->right_child) {
+ child = parent;
+ parent = parent->parent;
+ }
+ return parent;
+}
+
+Interval *prev_interval(Interval *node) {
+ Interval *parent, *child;
+
+ if (node->left_child) {
+ return maximum_interval(node->left_child);
+ }
+
+ child = node;
+ parent = node->parent;
+ while (parent && child == parent->left_child) {
+ child = parent;
+ parent = parent->parent;
+ }
+ return parent;
+}
+
+Interval *search_interval(Interval *root, uint32_t start, uint32_t count) {
+ Interval *current, *test;
+ Interval i;
+
+ i.low = start;
+ i.high = start + count - 1;
+ current = root;
+
+ while (current && !check_overlap(current, &i)) {
+ if (current->low > i.low) {
+ current = current->left_child;
+ } else {
+ current = current->right_child;
+ }
+ }
+
+ /* Make sure we really are returning the first (lowest) matching interval. */
+ if (current) {
+ for (test = prev_interval(current);
+ test != NULL && check_overlap(test, &i);
+ test = prev_interval(test))
+ {
+ /* We found a lower interval that also matches the search parameters. */
+ current = test;
+ }
+ }
+
+ return current;
+}
+
+void traverse_interval(Interval *root, Visitor action) {
+ if (root) {
+ traverse_interval(root->left_child, action);
+ action(root);
+ traverse_interval(root->right_child, action);
+ }
+}
diff --git a/daemons/maap/common/intervals.h b/daemons/maap/common/intervals.h
new file mode 100644
index 00000000..7bedac74
--- /dev/null
+++ b/daemons/maap/common/intervals.h
@@ -0,0 +1,207 @@
+/*************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************/
+
+/**
+ * @file
+ *
+ * @brief Augmented Binary Search Tree for Intervals
+ *
+ * This library will keep track of non-overlapping intervals in the uint32 range
+ *
+ * It supports insert, remove, minimum, maximum, next, previous, search, and
+ * traverse operations. All updates occur in-place.
+ *
+ * All memory allocation must be handled by the user through the alloc_interval
+ * and free_interval functions. These are not called by any library functions.
+ *
+ * To create an empty set of intervals, simply store an Interval pointer. The
+ * address of this pointer will be passed to the insert and remove operations,
+ * which will update the pointer if the root node of the tree changes.
+ */
+
+#ifndef INTERVALS_H
+#define INTERVALS_H
+
+#include <stdint.h>
+
+/* Return values for insert_interval */
+
+/**
+ * The interval was inserted
+ */
+#define INTERVAL_SUCCESS 0
+
+/**
+ * The interval overlapped and wasn't inserted
+ */
+#define INTERVAL_OVERLAP -1
+
+/**
+ * A range of integers with an upper and lower bound.
+ */
+typedef struct interval_node Interval;
+
+/**
+ * Signature for function pointer parameter to traverse_interval()
+ */
+typedef void (*Visitor)(Interval *);
+
+/**
+ * Structure for each node of the interval tree
+ */
+struct interval_node {
+ uint32_t low; /**< Low value of this interval */
+ uint32_t high; /**< High value of this interval */
+ void *data; /**< Pointer to the data associated with this interval */
+ Interval *parent; /**< Pointer to the parent of the current tree, or NULL if this is the root node */
+ Interval *left_child; /**< Pointer to a subtree with smaller intervals, or NULL if none */
+ Interval *right_child; /**< Pointer to a subtree with larger intervals, or NULL if none */
+};
+
+/**
+ * Determine if the interval overlaps with the supplied integers
+ *
+ * @param inter Interval to test
+ * @param start The first integer to test
+ * @param count The number of integers to test
+ *
+ * @return TRUE if the interval overlaps the supplied integers, FALSE otherwise
+ */
+#define interval_check_overlap(inter, start, count) \
+ (((inter)->low <= (start) + (count) - 1) && ((start) <= (inter)->high))
+
+
+/**
+ * Allocates, initializes, and returns a pointer to an Interval.
+ *
+ * @param start The first integer in the interval
+ *
+ * @param count The number of integers in the interval
+ *
+ * @return An initialized Interval, or NULL if the allocator fails.
+ */
+Interval *alloc_interval(uint32_t start, uint32_t count);
+
+/**
+ * Deallocates an Interval.
+ *
+ * @note Be sure to call this after removing an interval from a set
+ *
+ * @param node The Interval to deallocate.
+ */
+void free_interval(Interval *node);
+
+/**
+ * Insert an Interval into the set of tracked Intervals.
+ *
+ * @param root The address of the Interval pointer that is the root of the set
+ *
+ * @param node The Interval to attempt to insert in the set
+ *
+ * @return INTERVAL_SUCCESS if the node inserted to the set without overlap,
+ * INTERVAL_OVERLAP if the node was not inserted due to overlap with an existing
+ * Interval.
+ */
+int insert_interval(Interval **root, Interval *node);
+
+/**
+ * Remove an Interval from the set of tracked Intervals.
+ *
+ * @note Because the actual node removed from the tree might not be the same
+ * as the one passed in, the return value MUST be stored and used to free the
+ * Interval that was removed from the set.
+ *
+ * @param root The address of the pointer to the root of the set of Intervals
+ *
+ * @param node The address of the Interval to remove from the set
+ *
+ * @return The address of the Interval storage that should be freed
+ */
+Interval *remove_interval(Interval **root, Interval *node);
+
+/**
+ * Find the minimum Interval from a set of Intervals.
+ *
+ * @param root The address of the root of the set of Intervals
+ *
+ * @return The address of the Interval with the smallest 'low' value in the set,
+ * or NULL if the set is empty.
+ */
+Interval *minimum_interval(Interval *root);
+
+/**
+ * Find the maximum Interval from a set of Intervals.
+ *
+ * @param root The address of the root of the set of Intervals
+ *
+ * @return The address of the Interval with the largest 'low' value in the set,
+ * or NULL if the set is empty.
+ */
+Interval *maximum_interval(Interval *root);
+
+/**
+ * Get the next Interval in the set assuming an ordering based on the 'low' value.
+ *
+ * @param node The Interval to find the successor of.
+ *
+ * @return The successor of the passed-in Interval, or NULL if there is none.
+ */
+Interval *next_interval(Interval *node);
+
+/**
+ * Get the previous Interval in the set assuming an ordering based on the 'low'
+ * value.
+ *
+ * @param node The Interval to find the predecessor of.
+ *
+ * @return The predecessor of the passed-in Interval, or NULL if there is none.
+ */
+Interval *prev_interval(Interval *node);
+
+/**
+ * Find the first Interval in a set that overlaps with the given interval.
+ *
+ * @param root The root Interval of the set to search.
+ *
+ * @param start The first integer in the interval to search for.
+ *
+ * @param count The number of integers in the interval to search for.
+ *
+ * @return The first overlapping Interval, or NULL if there is none.
+ */
+Interval *search_interval(Interval *root, uint32_t start, uint32_t count);
+
+/**
+ * Traverse the Interval set, performing an action on each Interval.
+ *
+ * @note Intervals will be visited in increasing order of their 'low' values.
+ *
+ * @param root The root Interval of the set to traverse.
+ *
+ * @param action The action to invoke on each Interval.
+ */
+void traverse_interval(Interval *root, Visitor action);
+
+#endif
diff --git a/daemons/maap/common/maap.c b/daemons/maap/common/maap.c
new file mode 100644
index 00000000..304ee343
--- /dev/null
+++ b/daemons/maap/common/maap.c
@@ -0,0 +1,1091 @@
+/*************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************/
+
+#include "maap.h"
+#include "maap_packet.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <time.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#ifdef _WIN32
+ /* Windows-specific header values */
+#define random() rand()
+#define srandom(s) srand(s)
+#else
+ /* Linux-specific header files */
+#include <linux/if_ether.h>
+#endif
+
+#define MAAP_LOG_COMPONENT "Main"
+#include "maap_log.h"
+
+ /* Uncomment the DEBUG_TIMER_MSG define to display timer debug messages. */
+#define DEBUG_TIMER_MSG
+
+ /* Uncomment the DEBUG_NEGOTIATE_MSG define to display negotiation debug messages. */
+#define DEBUG_NEGOTIATE_MSG
+
+
+static int get_count(Maap_Client *mc, Range *range) {
+ (void)mc;
+ return range->interval->high - range->interval->low + 1;
+ }
+
+static unsigned long long int get_start_address(Maap_Client *mc, Range *range) {
+ return mc->address_base + range->interval->low;
+}
+
+static unsigned long long int get_end_address(Maap_Client *mc, Range *range) {
+ return mc->address_base + range->interval->high;
+}
+
+static int send_packet(Maap_Client *mc, MAAP_Packet *p) {
+ uint8_t *pbuf = NULL;
+ int ret = 0;
+ (void)mc;
+
+ pbuf = Net_getPacketBuffer(mc->net);
+
+ pack_maap(p, pbuf);
+
+ ret = Net_queuePacket(mc->net, pbuf);
+ return ret;
+}
+
+static int send_probe(Maap_Client *mc, Range *range) {
+ MAAP_Packet p;
+
+ init_packet(&p, mc->dest_mac, mc->src_mac);
+
+ p.message_type = MAAP_PROBE;
+ p.requested_start_address = get_start_address(mc, range);
+ p.requested_count = get_count(mc, range);
+
+#ifdef DEBUG_NEGOTIATE_MSG
+ if (MAAP_LOG_LEVEL_DEBUG <= MAAP_LOG_LEVEL) {
+ Time t;
+ Time_setFromMonotonicTimer(&t);
+ MAAP_LOGF_DEBUG("Sending probe at %s", Time_dump(&t));
+ }
+#endif
+
+ return send_packet(mc, &p);
+}
+
+static int send_announce(Maap_Client *mc, Range *range) {
+ MAAP_Packet p;
+
+ init_packet(&p, mc->dest_mac, mc->src_mac);
+
+ p.message_type = MAAP_ANNOUNCE;
+ p.requested_start_address = get_start_address(mc, range);
+ p.requested_count = get_count(mc, range);
+
+#ifdef DEBUG_NEGOTIATE_MSG
+ if (MAAP_LOG_LEVEL_DEBUG <= MAAP_LOG_LEVEL) {
+ Time t;
+ Time_setFromMonotonicTimer(&t);
+ MAAP_LOGF_DEBUG("Sending announce at %s", Time_dump(&t));
+ }
+#endif
+
+ return send_packet(mc, &p);
+}
+
+static int send_defend(Maap_Client *mc, Range *range, uint64_t start,
+ uint16_t count, uint64_t destination) {
+ MAAP_Packet p;
+ uint64_t conflict_start, conflict_end;
+
+ init_packet(&p, mc->dest_mac, mc->src_mac);
+
+ /* Determine the range of addresses where the conflict occurred
+ * (the union of the requested and allocated ranges). */
+ conflict_start = get_start_address(mc, range);
+ if (conflict_start < start) { conflict_start = start; }
+ conflict_end = get_end_address(mc, range);
+ if (conflict_end > start + count - 1) { conflict_end = start + count - 1; }
+
+ p.DA = destination;
+ p.message_type = MAAP_DEFEND;
+ p.requested_start_address = start;
+ p.requested_count = count;
+ p.conflict_start_address = conflict_start;
+ p.conflict_count = (uint16_t)(conflict_end - conflict_start + 1);
+
+#ifdef DEBUG_NEGOTIATE_MSG
+ if (MAAP_LOG_LEVEL_DEBUG <= MAAP_LOG_LEVEL) {
+ Time t;
+ Time_setFromMonotonicTimer(&t);
+ MAAP_LOGF_DEBUG("Sending defend at %s", Time_dump(&t));
+ }
+#endif
+
+ return send_packet(mc, &p);
+}
+
+static int inform_initialized(Maap_Client *mc, const void *sender, Maap_Notify_Error result) {
+ Maap_Notify note;
+
+ note.kind = MAAP_NOTIFY_INITIALIZED;
+ note.id = -1; /* Not used */
+ note.start = mc->address_base;
+ note.count = mc->range_len;
+ note.result = result;
+
+ add_notify(mc, sender, &note);
+ return 0;
+}
+
+static int inform_acquiring(Maap_Client *mc, Range *range) {
+ Maap_Notify note;
+
+ note.kind = MAAP_NOTIFY_ACQUIRING;
+ note.id = range->id;
+ note.start = get_start_address(mc, range);
+ note.count = get_count(mc, range);
+ note.result = MAAP_NOTIFY_ERROR_NONE;
+
+ add_notify(mc, range->sender, &note);
+ return 0;
+}
+
+static int inform_acquired(Maap_Client *mc, Range *range, Maap_Notify_Error result) {
+ Maap_Notify note;
+
+ note.kind = MAAP_NOTIFY_ACQUIRED;
+ note.id = range->id;
+ note.start = get_start_address(mc, range);
+ note.count = get_count(mc, range);
+ note.result = result;
+
+ add_notify(mc, range->sender, &note);
+ return 0;
+}
+
+static int inform_not_acquired(Maap_Client *mc, const void *sender, int id, int range_size, Maap_Notify_Error result) {
+ Maap_Notify note;
+
+ note.kind = MAAP_NOTIFY_ACQUIRED;
+ note.id = id;
+ note.start = 0;
+ note.count = range_size;
+ note.result = result;
+
+ add_notify(mc, sender, &note);
+ return 0;
+}
+
+static int inform_released(Maap_Client *mc, const void *sender, int id, Range *range, Maap_Notify_Error result) {
+ Maap_Notify note;
+
+ note.kind = MAAP_NOTIFY_RELEASED;
+ note.id = id;
+ note.start = (range ? get_start_address(mc, range) : 0);
+ note.count = (range ? get_count(mc, range) : 0);
+ note.result = result;
+
+ add_notify(mc, sender, &note);
+ return 0;
+}
+
+static int inform_status(Maap_Client *mc, const void *sender, int id, Range *range, Maap_Notify_Error result) {
+ Maap_Notify note;
+
+ note.kind = MAAP_NOTIFY_STATUS;
+ note.id = id;
+ note.start = (range ? get_start_address(mc, range) : 0);
+ note.count = (range ? get_count(mc, range) : 0);
+ note.result = result;
+
+ add_notify(mc, sender, &note);
+ return 0;
+}
+
+static int inform_yielded(Maap_Client *mc, const void *sender, int id, Range *range, Maap_Notify_Error result) {
+ Maap_Notify note;
+
+ note.kind = MAAP_NOTIFY_YIELDED;
+ note.id = id;
+ note.start = (range ? get_start_address(mc, range) : 0);
+ note.count = (range ? get_count(mc, range) : 0 );
+ note.result = result;
+
+ add_notify(mc, sender, &note);
+ return 0;
+}
+
+static void start_timer(Maap_Client *mc) {
+
+ if (mc->timer_queue) {
+ Time_setTimer(mc->timer, &mc->timer_queue->next_act_time);
+ }
+}
+
+static void remove_range_interval(Interval **root, Interval *node) {
+ Range *old_range = node->data;
+ Interval *free_inter, *test_inter;
+
+ /* Remove and free the interval from the set of intervals.
+ * Note that the interval freed may not be the same one supplied. */
+ assert(!old_range || old_range->interval == node);
+ free_inter = remove_interval(root, node);
+ assert(free_inter->data == old_range);
+ free_interval(free_inter);
+
+ /* Make sure the remaining ranges point to the intervals that hold them.
+ * This is necessary as the Range object may have moved to a different node. */
+ for (test_inter = minimum_interval(*root); test_inter != NULL; test_inter = next_interval(test_inter)) {
+ Range *range = test_inter->data;
+ assert(range);
+ assert(range != old_range);
+ if (range->interval != test_inter) {
+ range->interval = test_inter;
+ }
+ }
+}
+
+
+void add_notify(Maap_Client *mc, const void *sender, const Maap_Notify *mn) {
+ Maap_Notify_List *tmp, *li = calloc(1, sizeof (Maap_Notify_List));
+ memcpy(&li->notify, mn, sizeof (Maap_Notify));
+ li->sender = sender;
+
+ if (mc->notifies == NULL) {
+ mc->notifies = li;
+ } else {
+ tmp = mc->notifies;
+ while (tmp->next) {
+ tmp = tmp->next;
+ }
+ tmp->next = li;
+ }
+}
+
+int get_notify(Maap_Client *mc, const void **sender, Maap_Notify *mn) {
+ Maap_Notify_List *tmp;
+
+ if (mc->notifies) {
+ tmp = mc->notifies;
+ if (mn) { memcpy(mn, &(tmp->notify), sizeof (Maap_Notify)); }
+ if (sender) { *sender = tmp->sender; }
+ mc->notifies = tmp->next;
+ free(tmp);
+ return 1;
+ }
+ return 0;
+}
+
+void print_notify(Maap_Notify *mn, print_notify_callback_t notify_callback, void *callback_data)
+{
+ char szOutput[300];
+
+ assert(mn);
+
+ switch (mn->result)
+ {
+ case MAAP_NOTIFY_ERROR_NONE:
+ /* No error. Don't display anything. */
+ break;
+ case MAAP_NOTIFY_ERROR_REQUIRES_INITIALIZATION:
+ notify_callback(callback_data, MAAP_LOG_LEVEL_ERROR,
+ "MAAP is not initialized, so the command cannot be performed.");
+ break;
+ case MAAP_NOTIFY_ERROR_ALREADY_INITIALIZED:
+ notify_callback(callback_data, MAAP_LOG_LEVEL_ERROR,
+ "MAAP is already initialized, so the values cannot be changed.");
+ break;
+ case MAAP_NOTIFY_ERROR_RESERVE_NOT_AVAILABLE:
+ notify_callback(callback_data, MAAP_LOG_LEVEL_ERROR,
+ "The MAAP reservation is not available, or yield cannot allocate a replacement block. "
+ "Try again with a smaller address block size.");
+ break;
+ case MAAP_NOTIFY_ERROR_RELEASE_INVALID_ID:
+ notify_callback(callback_data, MAAP_LOG_LEVEL_ERROR,
+ "The MAAP reservation ID is not valid, so cannot be released or report its status.");
+ break;
+ case MAAP_NOTIFY_ERROR_OUT_OF_MEMORY:
+ notify_callback(callback_data, MAAP_LOG_LEVEL_ERROR,
+ "The MAAP application is out of memory.");
+ break;
+ case MAAP_NOTIFY_ERROR_INTERNAL:
+ notify_callback(callback_data, MAAP_LOG_LEVEL_ERROR,
+ "The MAAP application experienced an internal error.");
+ break;
+ default:
+ sprintf(szOutput, "The MAAP application returned an unknown error %d.", mn->result);
+ notify_callback(callback_data, MAAP_LOG_LEVEL_ERROR, szOutput);
+ break;
+ }
+
+ switch (mn->kind)
+ {
+ case MAAP_NOTIFY_INITIALIZED:
+ if (mn->result == MAAP_NOTIFY_ERROR_NONE) {
+ sprintf(szOutput, "MAAP initialized: 0x%012llx-0x%012llx (Size: %d)",
+ (unsigned long long) mn->start,
+ (unsigned long long) mn->start + mn->count - 1,
+ (unsigned int) mn->count);
+ notify_callback(callback_data, MAAP_LOG_LEVEL_INFO, szOutput);
+ } else {
+ sprintf(szOutput, "MAAP previously initialized to 0x%012llx-0x%012llx (Size: %d)",
+ (unsigned long long) mn->start,
+ (unsigned long long) mn->start + mn->count - 1,
+ (unsigned int) mn->count);
+ notify_callback(callback_data, MAAP_LOG_LEVEL_ERROR, szOutput);
+ }
+ break;
+ case MAAP_NOTIFY_ACQUIRING:
+ if (mn->result == MAAP_NOTIFY_ERROR_NONE) {
+ sprintf(szOutput, "Address range %d querying: 0x%012llx-0x%012llx (Size %d)",
+ mn->id,
+ (unsigned long long) mn->start,
+ (unsigned long long) mn->start + mn->count - 1,
+ mn->count);
+ notify_callback(callback_data, MAAP_LOG_LEVEL_INFO, szOutput);
+ } else {
+ sprintf(szOutput, "Unknown address range %d acquisition error", mn->id);
+ notify_callback(callback_data, MAAP_LOG_LEVEL_ERROR, szOutput);
+ }
+ break;
+ case MAAP_NOTIFY_ACQUIRED:
+ if (mn->result == MAAP_NOTIFY_ERROR_NONE) {
+ sprintf(szOutput, "Address range %d acquired: 0x%012llx-0x%012llx (Size %d)",
+ mn->id,
+ (unsigned long long) mn->start,
+ (unsigned long long) mn->start + mn->count - 1,
+ mn->count);
+ notify_callback(callback_data, MAAP_LOG_LEVEL_INFO, szOutput);
+ } else if (mn->id != -1) {
+ sprintf(szOutput, "Address range %d of size %d not acquired",
+ mn->id, mn->count);
+ notify_callback(callback_data, MAAP_LOG_LEVEL_ERROR, szOutput);
+ } else {
+ sprintf(szOutput, "Address range of size %d not acquired",
+ mn->count);
+ notify_callback(callback_data, MAAP_LOG_LEVEL_ERROR, szOutput);
+ }
+ break;
+ case MAAP_NOTIFY_RELEASED:
+ if (mn->result == MAAP_NOTIFY_ERROR_NONE) {
+ sprintf(szOutput, "Address range %d released: 0x%012llx-0x%012llx (Size %d)",
+ mn->id,
+ (unsigned long long) mn->start,
+ (unsigned long long) mn->start + mn->count - 1,
+ mn->count);
+ notify_callback(callback_data, MAAP_LOG_LEVEL_INFO, szOutput);
+ } else {
+ sprintf(szOutput, "Address range %d not released",
+ mn->id);
+ notify_callback(callback_data, MAAP_LOG_LEVEL_ERROR, szOutput);
+ }
+ break;
+ case MAAP_NOTIFY_STATUS:
+ if (mn->result == MAAP_NOTIFY_ERROR_NONE) {
+ sprintf(szOutput, "ID %d is address range 0x%012llx-0x%012llx (Size %d)",
+ mn->id,
+ (unsigned long long) mn->start,
+ (unsigned long long) mn->start + mn->count - 1,
+ mn->count);
+ notify_callback(callback_data, MAAP_LOG_LEVEL_INFO, szOutput);
+ } else {
+ sprintf(szOutput, "ID %d is not valid",
+ mn->id);
+ notify_callback(callback_data, MAAP_LOG_LEVEL_ERROR, szOutput);
+ }
+ break;
+ case MAAP_NOTIFY_YIELDED:
+ if (mn->result != MAAP_NOTIFY_ERROR_REQUIRES_INITIALIZATION && mn->result != MAAP_NOTIFY_ERROR_RELEASE_INVALID_ID) {
+ sprintf(szOutput, "Address range %d yielded: 0x%012llx-0x%012llx (Size %d)",
+ mn->id,
+ (unsigned long long) mn->start,
+ (unsigned long long) mn->start + mn->count - 1,
+ mn->count);
+ notify_callback(callback_data, MAAP_LOG_LEVEL_WARNING, szOutput);
+ if (mn->result != MAAP_NOTIFY_ERROR_NONE) {
+ notify_callback(callback_data, MAAP_LOG_LEVEL_ERROR,
+ "A new address range will not be allocated");
+ }
+ } else {
+ sprintf(szOutput, "ID %d is not valid",
+ mn->id);
+ notify_callback(callback_data, MAAP_LOG_LEVEL_ERROR, szOutput);
+ }
+ break;
+ default:
+ sprintf(szOutput, "Notification type %d not recognized", mn->kind);
+ notify_callback(callback_data, MAAP_LOG_LEVEL_ERROR, szOutput);
+ break;
+ }
+}
+
+
+int maap_init_client(Maap_Client *mc, const void *sender, uint64_t range_address_base, uint32_t range_len) {
+
+ if (mc->initialized) {
+ /* If the desired values are the same as the initialized values, pretend the command succeeded.
+ * Otherwise, let the sender know the range that was already specified and cannot change. */
+ int matches = (range_address_base == mc->address_base && range_len == mc->range_len);
+ inform_initialized(mc, sender, (matches ? MAAP_NOTIFY_ERROR_NONE : MAAP_NOTIFY_ERROR_ALREADY_INITIALIZED));
+
+ return (matches ? 0 : -1);
+ }
+
+ mc->timer = Time_newTimer();
+ if (!mc->timer) {
+ MAAP_LOG_ERROR("Failed to create Timer");
+ return -1;
+ }
+
+ mc->net = Net_newNet();
+ if (!mc->net) {
+ MAAP_LOG_ERROR("Failed to create Net");
+ Time_delTimer(mc->timer);
+ return -1;
+ }
+
+ mc->address_base = range_address_base;
+ mc->range_len = range_len;
+ mc->ranges = NULL;
+ mc->timer_queue = NULL;
+ mc->maxid = 0;
+ mc->notifies = NULL;
+
+ mc->initialized = 1;
+
+ /* Let the sender know the range is now specified. */
+ inform_initialized(mc, sender, MAAP_NOTIFY_ERROR_NONE);
+
+ return 0;
+}
+
+void maap_deinit_client(Maap_Client *mc) {
+ if (mc->initialized) {
+ while (mc->timer_queue) {
+ Range * pDel = mc->timer_queue;
+ mc->timer_queue = mc->timer_queue->next_timer;
+ if (pDel->state == MAAP_STATE_RELEASED) { free(pDel); }
+ }
+
+ while (mc->ranges) {
+ Range *range = mc->ranges->data;
+ remove_range_interval(&mc->ranges, mc->ranges);
+ if (range) { free(range); }
+ }
+
+ if (mc->timer) {
+ Time_delTimer(mc->timer);
+ mc->timer = NULL;
+ }
+
+ if (mc->net) {
+ Net_delNet(mc->net);
+ mc->net = NULL;
+ }
+
+ while (get_notify(mc, NULL, NULL)) { /* Do nothing with the result */ }
+
+ mc->initialized = 0;
+ }
+}
+
+int rand_ms(int variation) {
+ /* Return a value between 1 and variation-1, inclusive.
+ * This is to adhere to IEEE 1722-2016 B.3.4.1 and B.3.4.2. */
+ return random() % (variation - 1) + 1;
+}
+
+int schedule_timer(Maap_Client *mc, Range *range) {
+ Range *rp, *prev_rp;
+ unsigned long long int ns;
+ Time ts;
+
+ assert(mc);
+ assert(range);
+
+#ifdef DEBUG_TIMER_MSG
+ if (MAAP_LOG_LEVEL_DEBUG <= MAAP_LOG_LEVEL) {
+ Time_setFromMonotonicTimer(&ts);
+ MAAP_LOGF_DEBUG("schedule_timer called at: %s", Time_dump(&ts));
+ }
+#endif
+
+ if (range->state == MAAP_STATE_PROBING) {
+ ns = MAAP_PROBE_INTERVAL_BASE + rand_ms(MAAP_PROBE_INTERVAL_VARIATION);
+ ns = ns * 1000000;
+#ifdef DEBUG_TIMER_MSG
+ MAAP_LOGF_DEBUG("Scheduling probe timer for %llu ns from now", ns);
+#endif
+ Time_setFromNanos(&ts, ns);
+ Time_setFromMonotonicTimer(&range->next_act_time);
+ Time_add(&range->next_act_time, &ts);
+#ifdef DEBUG_TIMER_MSG
+ MAAP_LOGF_DEBUG("Expiration time is: %s", Time_dump(&range->next_act_time));
+#endif
+ } else if (range->state == MAAP_STATE_DEFENDING) {
+ ns = MAAP_ANNOUNCE_INTERVAL_BASE + rand_ms(MAAP_ANNOUNCE_INTERVAL_VARIATION);
+ ns = ns * 1000000;
+#ifdef DEBUG_TIMER_MSG
+ MAAP_LOGF_DEBUG("Scheduling defend timer for %llu ns from now", ns);
+#endif
+ Time_setFromNanos(&ts, (uint64_t)ns);
+ Time_setFromMonotonicTimer(&range->next_act_time);
+ Time_add(&range->next_act_time, &ts);
+#ifdef DEBUG_TIMER_MSG
+ MAAP_LOGF_DEBUG("Expiration time is: %s", Time_dump(&range->next_act_time));
+#endif
+ }
+
+ /* Remove the range from the timer queue, if it is already in it. */
+ if (mc->timer_queue == range) {
+ /* Range was at the front of the queue. */
+ mc->timer_queue = range->next_timer;
+ } else if (mc->timer_queue) {
+ /* Search the rest of the queue. */
+ prev_rp = mc->timer_queue;
+ rp = prev_rp->next_timer;
+ while (rp && rp != range) {
+ prev_rp = rp;
+ rp = rp->next_timer;
+ }
+ if (rp) {
+ /* Range was found. Remove it. */
+ prev_rp->next_timer = rp->next_timer;
+ rp->next_timer = NULL;
+ }
+ }
+
+ /* Add the range to the timer queue. */
+ if (mc->timer_queue == NULL ||
+ Time_cmp(&range->next_act_time, &mc->timer_queue->next_act_time) < 0) {
+ range->next_timer = mc->timer_queue;
+ mc->timer_queue = range;
+ } else {
+ rp = mc->timer_queue;
+ while (rp->next_timer &&
+ Time_cmp(&rp->next_timer->next_act_time, &range->next_act_time) <= 0)
+ {
+ rp = rp->next_timer;
+ }
+ range->next_timer = rp->next_timer;
+ rp->next_timer = range;
+ }
+
+#ifdef DEBUG_TIMER_MSG
+ /* Perform a sanity test on the timer queue. */
+ {
+ Range *test = mc->timer_queue;
+ int i;
+ for (i = 0; test && i < 100000; ++i) {
+ assert(test->next_timer != test);
+ assert(test->next_timer == NULL || Time_cmp(&test->next_act_time, &test->next_timer->next_act_time) <= 0);
+ test = test->next_timer;
+ }
+ if (test) {
+ MAAP_LOG_ERROR("Timer infinite loop detected!");
+ assert(0);
+ }
+ }
+#endif
+
+ return 0;
+}
+
+static int assign_interval(Maap_Client *mc, Range *range, uint64_t attempt_base, uint16_t len) {
+ Interval *iv;
+ int i, rv = INTERVAL_OVERLAP;
+ uint32_t range_max;
+
+ if (len > mc->range_len) { return -1; }
+ range_max = mc->range_len - 1;
+
+ /* If we were supplied with a base address to attempt, try that first. */
+ if (attempt_base >= mc->address_base &&
+ attempt_base + len - 1 <= mc->address_base + mc->range_len - 1)
+ {
+ iv = alloc_interval((uint32_t) (attempt_base - mc->address_base), len);
+ assert(iv->high <= range_max);
+ rv = insert_interval(&mc->ranges, iv);
+ if (rv == INTERVAL_OVERLAP) {
+ free_interval(iv);
+ }
+ }
+
+ /** @todo Use the saved MAAP_ANNOUNCE message ranges to search for addresses likely to be available.
+ * Old announced ranges (e.g. older than 1.75 minutes) can be deleted if there are no ranges available. */
+
+ for (i = 0; i < 1000 && rv == INTERVAL_OVERLAP; ++i) {
+ iv = alloc_interval(random() % (mc->range_len + 1 - len), len);
+ assert(iv->high <= range_max);
+ rv = insert_interval(&mc->ranges, iv);
+ if (rv == INTERVAL_OVERLAP) {
+ free_interval(iv);
+ }
+ }
+ if (i >= 1000) {
+ /* There don't appear to be any options! */
+ return -1;
+ }
+
+ iv->data = range;
+ range->interval = iv;
+
+ return 0;
+}
+
+int maap_reserve_range(Maap_Client *mc, const void *sender, uint64_t attempt_base, uint32_t length) {
+ int id;
+ Range *range;
+
+ if (!mc->initialized) {
+ MAAP_LOG_DEBUG("Reserve not allowed, as MAAP not initialized");
+ inform_not_acquired(mc, sender, -1, length, MAAP_NOTIFY_ERROR_REQUIRES_INITIALIZATION);
+ return -1;
+ }
+
+ if (length > 0xFFFF || length > mc->range_len) {
+ /* Range size cannot be more than 16 bits in size, due to the MAAP packet format */
+ inform_not_acquired(mc, sender, -1, length, MAAP_NOTIFY_ERROR_RESERVE_NOT_AVAILABLE);
+ return -1;
+ }
+
+ range = malloc(sizeof(Range));
+ if (range == NULL) {
+ inform_not_acquired(mc, sender, -1, length, MAAP_NOTIFY_ERROR_OUT_OF_MEMORY);
+ return -1;
+ }
+
+ id = ++(mc->maxid);
+ range->id = id;
+ range->state = MAAP_STATE_PROBING;
+ range->counter = MAAP_PROBE_RETRANSMITS;
+ range->overlapping = 0;
+ Time_setFromMonotonicTimer(&range->next_act_time);
+ range->interval = NULL;
+ range->sender = sender;
+ range->next_timer = NULL;
+
+ if (assign_interval(mc, range, attempt_base, length) < 0)
+ {
+ /* Cannot find any available intervals of the requested size. */
+ inform_not_acquired(mc, sender, -1, length, MAAP_NOTIFY_ERROR_RESERVE_NOT_AVAILABLE);
+ free(range);
+ return -1;
+ }
+
+#ifdef DEBUG_NEGOTIATE_MSG
+ MAAP_LOGF_DEBUG("Requested address range, id %d", id);
+ MAAP_LOGF_DEBUG("Selected address range 0x%012llx-0x%012llx", get_start_address(mc, range), get_end_address(mc, range));
+#endif
+ inform_acquiring(mc, range);
+
+ schedule_timer(mc, range);
+ start_timer(mc);
+ send_probe(mc, range);
+
+ return id;
+}
+
+int maap_release_range(Maap_Client *mc, const void *sender, int id) {
+ Interval *iv;
+ Range *range;
+
+ if (!mc->initialized) {
+ MAAP_LOG_DEBUG("Release not allowed, as MAAP not initialized");
+ inform_released(mc, sender, id, NULL, MAAP_NOTIFY_ERROR_REQUIRES_INITIALIZATION);
+ return -1;
+ }
+
+ range = mc->timer_queue;
+ while (range) {
+ if (range->id == id && range->state != MAAP_STATE_RELEASED) {
+ inform_released(mc, sender, id, range, MAAP_NOTIFY_ERROR_NONE);
+ if (sender != range->sender)
+ {
+ /* Also inform the sender that originally reserved this range. */
+ inform_released(mc, range->sender, id, range, MAAP_NOTIFY_ERROR_NONE);
+ }
+
+ iv = range->interval;
+ remove_range_interval(&mc->ranges, iv);
+ /* memory for range will be freed the next time its timer elapses */
+ range->state = MAAP_STATE_RELEASED;
+
+ return 0;
+ }
+ range = range->next_timer;
+ }
+
+ MAAP_LOGF_DEBUG("Range id %d does not exist to release", id);
+ inform_released(mc, sender, id, NULL, MAAP_NOTIFY_ERROR_RELEASE_INVALID_ID);
+ return -1;
+}
+
+void maap_range_status(Maap_Client *mc, const void *sender, int id)
+{
+ Range *range;
+
+ if (!mc->initialized) {
+ MAAP_LOG_DEBUG("Status not allowed, as MAAP not initialized");
+ inform_status(mc, sender, id, NULL, MAAP_NOTIFY_ERROR_REQUIRES_INITIALIZATION);
+ return;
+ }
+
+ range = mc->timer_queue;
+ while (range) {
+ if (range->id == id && range->state == MAAP_STATE_DEFENDING) {
+ inform_status(mc, sender, id, range, MAAP_NOTIFY_ERROR_NONE);
+ return;
+ }
+ range = range->next_timer;
+ }
+
+ MAAP_LOGF_DEBUG("Range id %d does not exist", id);
+ inform_status(mc, sender, id, NULL, MAAP_NOTIFY_ERROR_RELEASE_INVALID_ID);
+}
+
+int maap_yield_range(Maap_Client *mc, const void *sender, int id) {
+ Range *range;
+ MAAP_Packet announce_packet;
+ uint8_t announce_buffer[MAAP_NET_BUFFER_SIZE];
+
+ if (!mc->initialized) {
+ MAAP_LOG_DEBUG("Yield not allowed, as MAAP not initialized");
+ inform_yielded(mc, sender, id, NULL, MAAP_NOTIFY_ERROR_REQUIRES_INITIALIZATION);
+ return -1;
+ }
+
+ range = mc->timer_queue;
+ while (range) {
+ if (range->id == id && range->state == MAAP_STATE_DEFENDING) {
+ // Create a conflicting packet for this range.
+ // Use a source address which will always be less than our address, so we should always yield.
+ init_packet(&announce_packet, 0x010000000000ull, 0x010000000000ull);
+ announce_packet.message_type = MAAP_ANNOUNCE;
+ announce_packet.requested_start_address = get_start_address(mc, range);
+ announce_packet.requested_count = get_count(mc, range);
+ pack_maap(&announce_packet, announce_buffer);
+ maap_handle_packet(mc, announce_buffer, MAAP_NET_BUFFER_SIZE);
+
+ return 0;
+ }
+ range = range->next_timer;
+ }
+
+ MAAP_LOGF_DEBUG("Range id %d does not exist", id);
+ inform_yielded(mc, sender, id, NULL, MAAP_NOTIFY_ERROR_RELEASE_INVALID_ID);
+ return -1;
+}
+
+int maap_handle_packet(Maap_Client *mc, const uint8_t *stream, int len) {
+ MAAP_Packet p;
+ Interval *iv;
+ uint32_t start;
+ Range *range;
+ int rv, num_overlaps;
+ unsigned long long int own_base, own_max, incoming_base, incoming_max;
+
+ if (len < MAAP_PKT_SIZE) {
+ MAAP_LOGF_ERROR("Truncated MAAP packet of length %d received, discarding", len);
+ return -1;
+ }
+ rv = unpack_maap(&p, stream);
+ if (rv != 0) {
+ MAAP_LOG_ERROR("Error unpacking the MAAP packet");
+ return -1;
+ }
+
+ if (p.Ethertype != MAAP_TYPE ||
+ p.subtype != MAAP_SUBTYPE ||
+ p.control_data_length != 16 )
+ {
+ /* This is not a MAAP packet. Ignore it. */
+#ifdef DEBUG_NEGOTIATE_MSG
+ MAAP_LOGF_DEBUG("Ignoring non-MAAP packet of length %d", len);
+#endif
+ return -1;
+ }
+
+ if (p.version != 0) {
+ MAAP_LOGF_ERROR("AVTP version %u not supported", p.version);
+ return -1;
+ }
+
+ if (p.message_type < MAAP_PROBE || p.message_type > MAAP_ANNOUNCE) {
+ MAAP_LOGF_ERROR("MAAP packet message type %u not recognized", p.message_type);
+ return -1;
+ }
+
+ own_base = mc->address_base;
+ own_max = mc->address_base + mc->range_len - 1;
+ incoming_base = p.requested_start_address;
+ incoming_max = p.requested_start_address + p.requested_count - 1;
+
+#ifdef DEBUG_NEGOTIATE_MSG
+ if (p.message_type == MAAP_PROBE) {
+ MAAP_LOGF_DEBUG("Received PROBE for range 0x%012llx-0x%012llx (Size %u)", incoming_base, incoming_max, p.requested_count);
+ }
+ if (p.message_type == MAAP_DEFEND) {
+ MAAP_LOGF_DEBUG("Received DEFEND for range 0x%012llx-0x%012llx (Size %u),",
+ incoming_base, incoming_max, p.requested_count);
+ MAAP_LOGF_DEBUG("conflicting with range 0x%012llx-0x%012llx (Size %u)",
+ (unsigned long long) p.conflict_start_address,
+ (unsigned long long) p.conflict_start_address + p.conflict_count - 1,
+ p.conflict_count);
+ }
+ if (p.message_type == MAAP_ANNOUNCE) {
+ MAAP_LOGF_DEBUG("Received ANNOUNCE for range 0x%012llx-0x%012llx (Size %u)", incoming_base, incoming_max, p.requested_count);
+ }
+#endif
+
+ if (incoming_max < own_base || own_max < incoming_base) {
+#ifdef DEBUG_NEGOTIATE_MSG
+ MAAP_LOG_DEBUG("Packet refers to a range outside of our concern:");
+ MAAP_LOGF_DEBUG(" 0x%012llx < 0x%012llx || 0x%012llx < 0x%012llx", incoming_max, own_base, own_max, incoming_base);
+#endif
+ return 0;
+ }
+
+ /** @todo If this is a MAAP_ANNOUNCE message, save the announced range and time received for later reference. */
+
+ /* Flag all the range items that overlap with the incoming packet. */
+ num_overlaps = 0;
+ start = (uint32_t) (p.requested_start_address - mc->address_base);
+ for (iv = search_interval(mc->ranges, start, p.requested_count); iv != NULL && interval_check_overlap(iv, start, p.requested_count); iv = next_interval(iv)) {
+ range = iv->data;
+ range->overlapping = 1;
+ num_overlaps++;
+ }
+
+ while (num_overlaps-- > 0) {
+ /* Find the first item that is still flagged. */
+ for (iv = search_interval(mc->ranges, start, p.requested_count); iv != NULL; iv = next_interval(iv)) {
+ range = iv->data;
+ if (range->overlapping) { break; }
+ }
+ if (!iv) {
+ /* We reached the end of the list. */
+ assert(0); /* We should never get here! */
+ break;
+ }
+ range->overlapping = 0;
+
+ if (range->state == MAAP_STATE_PROBING) {
+
+ if (p.message_type == MAAP_PROBE && compare_mac_addresses(mc->src_mac, p.SA)) {
+ /* We won with the lower MAC Address. Do nothing. */
+#ifdef DEBUG_NEGOTIATE_MSG
+ MAAP_LOG_DEBUG("Ignoring conflicting probe request");
+#endif
+ } else {
+ /* Find an alternate interval, remove old interval,
+ and restart probe counter */
+ int range_size = iv->high - iv->low + 1;
+ iv->data = NULL; /* Range is moving to a new interval */
+ if (assign_interval(mc, range, 0, range_size) < 0) {
+ /* No interval is available, so stop probing and report an error. */
+ MAAP_LOG_WARNING("Unable to find an available address block to probe");
+ inform_not_acquired(mc, range->sender, range->id, range_size, MAAP_NOTIFY_ERROR_RESERVE_NOT_AVAILABLE);
+ remove_range_interval(&mc->ranges, iv);
+ /* memory will be freed the next time its timer elapses */
+ range->state = MAAP_STATE_RELEASED;
+ } else {
+#ifdef DEBUG_NEGOTIATE_MSG
+ MAAP_LOGF_DEBUG("Selected new address range 0x%012llx-0x%012llx",
+ get_start_address(mc, range), get_end_address(mc, range));
+#endif
+ inform_acquiring(mc, range);
+
+ remove_range_interval(&mc->ranges, iv);
+ range->counter = MAAP_PROBE_RETRANSMITS;
+
+ schedule_timer(mc, range);
+ send_probe(mc, range);
+ }
+ }
+
+ } else if (range->state == MAAP_STATE_DEFENDING) {
+
+ MAAP_LOGF_INFO("Conflict detected with our range (id %d)!", range->id);
+#ifdef DEBUG_NEGOTIATE_MSG
+ MAAP_LOGF_DEBUG(" Request of 0x%012llx-0x%012llx conflicts with our range of 0x%012llx-0x%012llx",
+ incoming_base, incoming_max,
+ get_start_address(mc, range), get_end_address(mc, range));
+#endif
+
+ if (p.message_type == MAAP_PROBE) {
+ MAAP_LOG_INFO("DEFEND!");
+ send_defend(mc, range, p.requested_start_address, p.requested_count, p.SA);
+ } else if (compare_mac_addresses(mc->src_mac, p.SA)) {
+ /* We won with the lower MAC Address. Do nothing. */
+ MAAP_LOG_INFO("IGNORE");
+ } else {
+ Range *new_range;
+ int range_size = iv->high - iv->low + 1;
+
+ MAAP_LOG_INFO("YIELD");
+
+ /* Start a new reservation request for the owner of the yielded reservation.
+ * Use the same ID as the yielded range, so the owner can easily track it.
+ *
+ * Note: Because our previous range is still in our range list,
+ * the new range selected will not overlap it.
+ */
+ new_range = malloc(sizeof(Range));
+ if (new_range == NULL) {
+ inform_yielded(mc, range->sender, range->id, range, MAAP_NOTIFY_ERROR_OUT_OF_MEMORY);
+ } else {
+ new_range->id = range->id;
+ new_range->state = MAAP_STATE_PROBING;
+ new_range->counter = MAAP_PROBE_RETRANSMITS;
+ new_range->overlapping = 0;
+ Time_setFromMonotonicTimer(&new_range->next_act_time);
+ new_range->interval = NULL;
+ new_range->sender = range->sender;
+ new_range->next_timer = NULL;
+ if (assign_interval(mc, new_range, 0, range_size) < 0)
+ {
+ /* Cannot find any available intervals of the requested size. */
+ inform_yielded(mc, range->sender, range->id, range, MAAP_NOTIFY_ERROR_RESERVE_NOT_AVAILABLE);
+ free(new_range);
+ } else {
+#ifdef DEBUG_NEGOTIATE_MSG
+ MAAP_LOGF_DEBUG("Requested replacement address range, id %d", new_range->id);
+ MAAP_LOGF_DEBUG("Selected replacement address range 0x%012llx-0x%012llx", get_start_address(mc, new_range), get_end_address(mc, new_range));
+#endif
+
+ /* Send a probe for the replacement address range to try. */
+ schedule_timer(mc, new_range);
+ send_probe(mc, new_range);
+
+ inform_yielded(mc, range->sender, range->id, range, MAAP_NOTIFY_ERROR_NONE);
+ inform_acquiring(mc, new_range);
+ }
+ }
+
+ /* We are done with the old range. */
+ remove_range_interval(&mc->ranges, iv);
+ /* memory will be freed the next time its timer elapses */
+ range->state = MAAP_STATE_RELEASED;
+ }
+
+ }
+ }
+
+ start_timer(mc);
+
+ return 0;
+}
+
+int handle_probe_timer(Maap_Client *mc, Range *range) {
+ if (range->counter == 0) {
+ inform_acquired(mc, range, MAAP_NOTIFY_ERROR_NONE);
+ range->state = MAAP_STATE_DEFENDING;
+ schedule_timer(mc, range);
+ send_announce(mc, range);
+ } else {
+ range->counter--;
+ schedule_timer(mc, range);
+ send_probe(mc, range);
+ }
+
+ return 0;
+}
+
+int handle_defend_timer(Maap_Client *mc, Range *range) {
+ schedule_timer(mc, range);
+ send_announce(mc, range);
+
+ return 0;
+}
+
+int maap_handle_timer(Maap_Client *mc) {
+ Time currenttime;
+ Range *range;
+
+ /* Get the current time. */
+ Time_setFromMonotonicTimer(&currenttime);
+#ifdef DEBUG_TIMER_MSG
+ MAAP_LOGF_DEBUG("maap_handle_timer called at: %s", Time_dump(&currenttime));
+#endif
+
+ while ((range = mc->timer_queue) && Time_passed(&currenttime, &range->next_act_time)) {
+#ifdef DEBUG_TIMER_MSG
+ MAAP_LOGF_DEBUG("Due timer: %s", Time_dump(&range->next_act_time));
+#endif
+ mc->timer_queue = range->next_timer;
+ range->next_timer = NULL;
+
+ if (range->state == MAAP_STATE_PROBING) {
+#ifdef DEBUG_TIMER_MSG
+ MAAP_LOG_DEBUG("Handling probe timer");
+#endif
+ handle_probe_timer(mc, range);
+ } else if (range->state == MAAP_STATE_DEFENDING) {
+#ifdef DEBUG_TIMER_MSG
+ MAAP_LOG_DEBUG("Handling defend timer");
+#endif
+ handle_defend_timer(mc, range);
+ } else if (range->state == MAAP_STATE_RELEASED) {
+#ifdef DEBUG_TIMER_MSG
+ MAAP_LOG_DEBUG("Freeing released timer");
+#endif
+ free(range);
+ }
+
+ }
+
+ start_timer(mc);
+
+ return 0;
+}
+
+int64_t maap_get_delay_to_next_timer(Maap_Client *mc)
+{
+ long long int timeRemaining;
+
+ if (!(mc->timer) || !(mc->timer_queue))
+ {
+ /* There are no timers waiting, so wait for an hour.
+ * (No particular reason; it just sounded reasonable.) */
+ timeRemaining = 60LL * 60LL * 1000000000LL;
+ }
+ else
+ {
+ /* Get the time remaining for the next timer. */
+ timeRemaining = Time_remaining(mc->timer);
+ }
+#ifdef DEBUG_TIMER_MSG
+ MAAP_LOG_DEBUG(""); /* Blank line */
+ MAAP_LOGF_DEBUG("Time_remaining: %lld ns", timeRemaining);
+ MAAP_LOG_DEBUG(""); /* Blank line */
+#endif
+ return timeRemaining;
+}
diff --git a/daemons/maap/common/maap.h b/daemons/maap/common/maap.h
new file mode 100644
index 00000000..13b4660c
--- /dev/null
+++ b/daemons/maap/common/maap.h
@@ -0,0 +1,253 @@
+/*************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************/
+
+/**
+ * @file
+ *
+ * @brief Main MAAP supporting functions
+ *
+ * Includes functions to perform the MAAP negotiation, and defines useful for MAAP support.
+ */
+
+#ifndef MAAP_H
+#define MAAP_H
+
+#include <stdint.h>
+#include <stdio.h>
+#include <time.h>
+#include "intervals.h"
+#include "maap_iface.h"
+#include "maap_timer.h"
+#include "maap_net.h"
+
+#define MAAP_PROBE_RETRANSMITS 3 /**< Number of allowed probes - This value is defined in IEEE 1722-2016 Table B.8 */
+
+/* Times are in milliseconds */
+#define MAAP_PROBE_INTERVAL_BASE 500 /**< Probe interval minimum time in milliseconds - This value is defined in IEEE 1722-2016 Table B.8 */
+#define MAAP_PROBE_INTERVAL_VARIATION 100 /**< Probe interval additional time in milliseconds - This value is defined in IEEE 1722-2016 Table B.8 */
+#define MAAP_ANNOUNCE_INTERVAL_BASE 30000 /**< Announce interval minimum time in milliseconds - This value is defined in IEEE 1722-2016 Table B.8 */
+#define MAAP_ANNOUNCE_INTERVAL_VARIATION 2000 /**< Announce interval additional time in milliseconds - This value is defined in IEEE 1722-2016 Table B.8 */
+
+#define MAAP_DEST_MAC {0x91, 0xE0, 0xF0, 0x00, 0xFF, 0x00} /**< MAAP multicast Address - Defined in IEEE 1722-2016 Table B.10 */
+
+#define MAAP_DYNAMIC_POOL_BASE 0x91E0F0000000LL /**< MAAP dynamic allocation pool base address - Defined in IEEE 1722-2016 Table B.9 */
+#define MAAP_DYNAMIC_POOL_SIZE 0xFE00 /**< MAAP dynamic allocation pool size - Defined in IEEE 1722-2016 Table B.9 */
+
+#define MAAP_TYPE 0x22F0 /**< AVTP Ethertype - Defined in IEEE 1722-2016 Table 5 */
+#define MAAP_SUBTYPE 0xFE /**< AVTP MAAP subtype - Defined in IEEE 1722-2016 Table 6 */
+#define MAAP_PKT_SIZE 42 /**< Number of bytes for a raw MAAP Ethernet packet */
+
+ /** MAAP Range States */
+typedef enum {
+ MAAP_STATE_INVALID = 0,
+ MAAP_STATE_PROBING, /**< Probing to determine if the address interval is available */
+ MAAP_STATE_DEFENDING, /**< The address interval has been reserved, and defend if conflicts detected */
+ MAAP_STATE_RELEASED, /**< The address interval has been released, and is waiting to be freed */
+ } Maap_State;
+
+
+/** Wrapper for struct maap_notify */
+typedef struct maap_notify_list Maap_Notify_List;
+
+/** Structure for each queued notification */
+struct maap_notify_list {
+ Maap_Notify notify; /**< Notification information to send */
+ const void *sender; /**< Sender information pointer for the entity that requested the original command */
+ Maap_Notify_List *next; /**< Next notification in the queue */
+};
+
+
+/** Wrapper for struct range */
+typedef struct range Range;
+
+/** Structure for each range in use */
+struct range {
+ int id; /**< Unique identifier for this range */
+ Maap_State state; /**< State of this range */
+ int counter; /**< Counter used to limit the number of probes for this range */
+ int overlapping; /**< Temporary flag used to keep track of ranges that require overlap processing */
+ Time next_act_time; /**< Next time to perform an action for this range */
+ Interval *interval; /**< Interval information for the range */
+ const void *sender; /**< Sender information pointer for the entity that requested the range */
+ Range *next_timer; /**< Next range in the list */
+};
+
+
+/** MAAP Initialization Information */
+typedef struct {
+ uint64_t dest_mac; /**< Multicast address for MAAP packets */
+ uint64_t src_mac; /**< Local adapter interface MAC Address */
+ uint64_t address_base; /**< Starting address of the recognized range of addresses (typically #MAAP_DYNAMIC_POOL_BASE) */
+ uint32_t range_len; /**< Number of recognized addresses (typically #MAAP_DYNAMIC_POOL_SIZE) */
+ Interval *ranges; /**< Pointer to the root of the #Interval tree, which contains all the Range structures */
+ Range *timer_queue; /**< Pointer to a linked list of ranges that need timer support,
+ * with the first timer to expire being first in the list */
+ Timer *timer; /**< Pointer to the platform-specific timing support (initialized by calling #Time_newTimer) */
+ Net *net; /**< Pointer to the platform-specific networking support (initialized by calling #Net_newNet) */
+ int maxid; /**< Identifier value of the latest reservation */
+ Maap_Notify_List *notifies; /**< Pointer to a linked list of queued notification */
+ int initialized; /**< 1 if the structure has been initialized, 0 otherwise */
+} Maap_Client;
+
+
+/**
+ * Initialize the MAAP support, in response to a MAAP_CMD_INIT command.
+ *
+ * @param mc Pointer to the Maap_Client structure to use
+ * @param sender Sender information pointer used to track the entity requesting the command
+ * @param range_address_base Starting address of the recognized range of addresses (typically #MAAP_DYNAMIC_POOL_BASE)
+ * @param range_len Number of recognized addresses (typically #MAAP_DYNAMIC_POOL_SIZE)
+ *
+ * @return 0 if the initialization was successful, -1 otherwise.
+ */
+int maap_init_client(Maap_Client *mc, const void *sender, uint64_t range_address_base, uint32_t range_len);
+
+/**
+ * Deinitialize the MAAP support.
+ *
+ * @param mc Pointer to the Maap_Client structure to use
+ */
+void maap_deinit_client(Maap_Client *mc);
+
+
+/**
+ * Reserve a block of addresses, in support of a MAAP_CMD_RESERVE command.
+ *
+ * @note This call starts the reservation process.
+ * One or more MAAP_NOTIFY_ACQUIRING notifications may be sent during the process.
+ * A MAAP_NOTIFY_ACQUIRED notification will be sent when the process is complete
+ * (either succeeded or failed).
+ *
+ * @param mc Pointer to the Maap_Client structure to use
+ * @param sender Sender information pointer used to track the entity requesting the command
+ * @param attempt_base The base address to be attempted first, or 0 if no preference.
+ * If the preferred address is not available, another random address will be attempted instead.
+ * @param length Number of addresses in the block to reserve (1 to 65535)
+ *
+ * @return The identifier value if the request was started successfully, -1 otherwise.
+ */
+int maap_reserve_range(Maap_Client *mc, const void *sender, uint64_t attempt_base, uint32_t length);
+
+/**
+ * Release a reserved block of addresses, in support of a MAAP_CMD_RELEASE command.
+ *
+ * @note This call starts the release process.
+ * A MAAP_NOTIFY_RELEASED notification will be sent when the process is complete.
+ *
+ * @param mc Pointer to the Maap_Client structure to use
+ * @param sender Sender information pointer used to track the entity requesting the command
+ * @param id Identifier for the address block to release
+ *
+ * @return 0 if the release was started successfully, -1 otherwise.
+ */
+int maap_release_range(Maap_Client *mc, const void *sender, int id);
+
+/**
+ * Get the start and length of a block of addresses, in support of a MAAP_CMD_STATUS command.
+ *
+ * @note This call starts the status process.
+ * A MAAP_NOTIFY_STATUS notification will be sent when the process is complete.
+ *
+ * @param mc Pointer to the Maap_Client structure to use
+ * @param sender Sender information pointer used to track the entity requesting the command
+ * @param id Identifier for the address block to get the status of
+ */
+void maap_range_status(Maap_Client *mc, const void *sender, int id);
+
+/**
+ * Yield a reserved block of addresses, in support of a MAAP_CMD_YIELD command.
+ *
+ * @note This call starts the yield process, which is only useful for testing.
+ * A MAAP_NOTIFY_YIELDED notification will be sent when the process is complete.
+ *
+ * @param mc Pointer to the Maap_Client structure to use
+ * @param sender Sender information pointer used to track the entity requesting the command
+ * @param id Identifier for the address block to yield
+ *
+ * @return 0 if the yield was started successfully, -1 otherwise.
+ */
+int maap_yield_range(Maap_Client *mc, const void *sender, int id);
+
+
+/**
+ * Processing for a received (incoming) networking packet
+ *
+ * @param mc Pointer to the Maap_Client structure to use
+ * @param stream Binary data for the raw incoming packet
+ * @param len Length (in bytes) for the raw incoming packet
+ *
+ * @return 0 if the packet is a MAAP packet, -1 otherwise.
+ */
+int maap_handle_packet(Maap_Client *mc, const uint8_t *stream, int len);
+
+/**
+ * Determine if the next timer has expired, and perform any relevant actions if it has.
+ *
+ * @param mc Pointer to the Maap_Client structure to use
+ *
+ * @return 0 if successful, -1 otherwise.
+ */
+int maap_handle_timer(Maap_Client *mc);
+
+/**
+ * Get the number of nanoseconds until the next timer event.
+ *
+ * @param mc Pointer to the Maap_Client structure to use
+ *
+ * @return Number of nanoseconds until the next timer expires, or a very large value if there are no timers waiting.
+ */
+int64_t maap_get_delay_to_next_timer(Maap_Client *mc);
+
+
+/**
+ * Add a notification to the end of the notifications queue.
+ *
+ * @param mc Pointer to the Maap_Client structure to use
+ * @param sender Sender information pointer used to track the entity requesting the command
+ * @param mn Maap_Notify structure with the notification information to use
+ */
+void add_notify(Maap_Client *mc, const void *sender, const Maap_Notify *mn);
+
+/**
+ * Get the next notification from the notifications queue.
+ *
+ * @param mc Pointer to the Maap_Client structure to use
+ * @param sender Pointer to empty sender information pointer to receive the entity requesting the command
+ * @param mn Empty Maap_Notify structure to fill with the notification information
+ *
+ * @return 1 if a notification was returned, 0 if there are no more queued notifications.
+ */
+int get_notify(Maap_Client *mc, const void **sender, Maap_Notify *mn);
+
+/**
+ * Output the text equivalent of the notification information to the callback function.
+ *
+ * @param mn Pointer to the notification information structure.
+ * @param notify_callback Function of type #print_notify_callback_t that will handle printable results.
+ * @param callback_data Data to return with the callback.
+ */
+void print_notify(Maap_Notify *mn, print_notify_callback_t notify_callback, void *callback_data);
+
+#endif
diff --git a/daemons/maap/common/maap_iface.h b/daemons/maap/common/maap_iface.h
new file mode 100644
index 00000000..55dcb8d3
--- /dev/null
+++ b/daemons/maap/common/maap_iface.h
@@ -0,0 +1,108 @@
+/*************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************/
+
+/**
+ * @file
+ *
+ * @brief Interface for inter-process commands and notifications
+ *
+ * The commands and notifications are used to allow a client to tell the daemon
+ * which command to perform, and provide notifications when the status relevant
+ * to a client has changed. The commands and notifications are asynchronous.
+ */
+
+#ifndef MAAP_IFACE_H
+#define MAAP_IFACE_H
+
+#include <stdint.h>
+
+/** MAAP Commands */
+typedef enum {
+ MAAP_CMD_INVALID = 0,
+ MAAP_CMD_INIT, /**< Initialize the daemon to support a range of values */
+ MAAP_CMD_RESERVE, /**< Preserve a block of addresses within the initialized range */
+ MAAP_CMD_RELEASE, /**< Release a previously-reserved block of addresses */
+ MAAP_CMD_STATUS, /**< Return the block of reserved addresses associated with the supplied ID */
+ MAAP_CMD_YIELD, /**< Yield a previously-reserved block of addresses. This is only useful for testing. */
+ MAAP_CMD_EXIT, /**< Have the daemon exit */
+ } Maap_Cmd_Tag;
+
+/** MAAP Command Request Format
+ *
+ * This is the format of the command request the daemon expects to receive from the client.
+ * Not all values are used for all commands.
+ */
+typedef struct {
+ Maap_Cmd_Tag kind; /**< Type of command to perform */
+ int32_t id; /**< ID to use for #MAAP_CMD_RELEASE, #MAAP_CMD_STATUS, or #MAAP_CMD_YIELD */
+ uint64_t start; /**< Address range start for #MAAP_CMD_INIT */
+ uint32_t count; /**< Address range size for #MAAP_CMD_INIT, or address block size for #MAAP_CMD_RESERVE */
+} Maap_Cmd;
+
+
+/** MAAP Notifications */
+typedef enum {
+ MAAP_NOTIFY_INVALID = 0,
+ MAAP_NOTIFY_INITIALIZED, /**< Notification sent in response to a #MAAP_CMD_INIT command */
+ MAAP_NOTIFY_ACQUIRING, /**< Notification sent in response to a #MAAP_CMD_RESERVE command indicating that the reservation is in progress */
+ MAAP_NOTIFY_ACQUIRED, /**< Notification sent in response to a #MAAP_CMD_RESERVE command indicating that the reservation is complete (either succeeded or failed) */
+ MAAP_NOTIFY_RELEASED, /**< Notification sent in response to a #MAAP_CMD_RELEASE command */
+ MAAP_NOTIFY_STATUS, /**< Notification sent in response to a #MAAP_CMD_STATUS command */
+ MAAP_NOTIFY_YIELDED, /**< Notification that an address block was yielded to another device on the network */
+} Maap_Notify_Tag;
+
+/** MAAP Notification Errors */
+typedef enum {
+ MAAP_NOTIFY_ERROR_NONE = 0, /**< Command was successful */
+ MAAP_NOTIFY_ERROR_REQUIRES_INITIALIZATION, /**< MAAP is not initialized, so the command cannot be performed */
+ MAAP_NOTIFY_ERROR_ALREADY_INITIALIZED, /**< MAAP is already initialized, so the values cannot be changed */
+ MAAP_NOTIFY_ERROR_RESERVE_NOT_AVAILABLE, /**< The MAAP reservation is not available, or yield cannot allocate a replacement block.
+ * Try again with a smaller address block size. */
+ MAAP_NOTIFY_ERROR_RELEASE_INVALID_ID, /**< The MAAP reservation ID is not valid, so cannot be released or report its status */
+ MAAP_NOTIFY_ERROR_OUT_OF_MEMORY, /**< The MAAP application is out of memory */
+ MAAP_NOTIFY_ERROR_INTERNAL, /**< The MAAP application experienced an internal error */
+} Maap_Notify_Error;
+
+/** MAAP Notification Response Format
+ *
+ * This is the format of the notification response the client expects to receive from the daemon.
+ * Not all values are used for all notifications.
+ */
+typedef struct {
+ Maap_Notify_Tag kind; /**< Type of notification being returned */
+ int32_t id; /**< ID assigned for #MAAP_NOTIFY_ACQUIRING and #MAAP_NOTIFY_ACQUIRED, or used for #MAAP_NOTIFY_RELEASED,
+ * #MAAP_NOTIFY_STATUS, or #MAAP_NOTIFY_YIELDED */
+ uint64_t start; /**< Address range start for #MAAP_NOTIFY_INITIALIZED, or address block start for #MAAP_NOTIFY_ACQUIRING,
+ * #MAAP_NOTIFY_ACQUIRED, #MAAP_NOTIFY_RELEASED, #MAAP_NOTIFY_STATUS, or #MAAP_NOTIFY_YIELDED */
+ uint32_t count; /**< Address range size for #MAAP_NOTIFY_INITIALIZED, or address block size for #MAAP_NOTIFY_ACQUIRING,
+ * #MAAP_NOTIFY_ACQUIRED, #MAAP_NOTIFY_RELEASED, #MAAP_NOTIFY_STATUS, or #MAAP_NOTIFY_YIELDED */
+ Maap_Notify_Error result; /**< #MAAP_NOTIFY_ERROR_NONE if the command succeeded, or another value if an error occurred */
+} Maap_Notify;
+
+
+/** Callback function used by #print_notify and #print_cmd_usage */
+typedef void (*print_notify_callback_t)(void *callback_data, int logLevel, const char *notifyText);
+
+#endif
diff --git a/daemons/maap/common/maap_log.h b/daemons/maap/common/maap_log.h
new file mode 100644
index 00000000..eb9ca01f
--- /dev/null
+++ b/daemons/maap/common/maap_log.h
@@ -0,0 +1,253 @@
+/*************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************/
+
+/*
+* MODULE SUMMARY : A simple logging facility for use during
+* development.
+*/
+
+#ifndef MAAP_LOG_H
+#define MAAP_LOG_H 1
+
+// ********
+// Merge Issue
+// TODO: Restructure to remove #ifdef code.
+// ********
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+// Uncomment MAAP_LOG_ON to enable logging.
+#define MAAP_LOG_ON 1
+
+// Uncomment MAAP_LOG_ON_OVERRIDE to override all MAAP_LOG_ON usage in the app to ensure all logs are off.
+//#define MAAP_LOG_ON_OVERRIDE 1
+
+#ifdef MAAP_LOG_ON_OVERRIDE
+#ifdef MAAP_LOG_ON
+#undef MAAP_LOG_ON
+#endif
+#endif
+
+#define MAAP_LOG_LEVEL_NONE 0
+#define MAAP_LOG_LEVEL_ERROR 1
+#define MAAP_LOG_LEVEL_WARNING 2
+#define MAAP_LOG_LEVEL_INFO 3
+#define MAAP_LOG_LEVEL_STATUS 4
+#define MAAP_LOG_LEVEL_DEBUG 5
+#define MAAP_LOG_LEVEL_VERBOSE 6
+
+// Special case development logging levels for use with MAAP_LOGF_DEV and MAAP_LOG_DEV
+#define MAAP_LOG_LEVEL_DEV_ON MAAP_LOG_LEVEL_NONE
+#define MAAP_LOG_LEVEL_DEV_OFF MAAP_LOG_LEVEL_VERBOSE + 1
+
+// Default log level, can override in source files
+#ifndef MAAP_LOG_LEVEL
+//#define MAAP_LOG_LEVEL MAAP_LOG_LEVEL_ERROR
+//#define MAAP_LOG_LEVEL MAAP_LOG_LEVEL_INFO
+#define MAAP_LOG_LEVEL MAAP_LOG_LEVEL_STATUS
+//#define MAAP_LOG_LEVEL MAAP_LOG_LEVEL_DEBUG
+//#define MAAP_LOG_LEVEL MAAP_LOG_LEVEL_VERBOSE
+#endif
+
+#ifndef MAAP_LOG_COMPANY
+#define MAAP_LOG_COMPANY "MAAP"
+#endif
+
+#ifndef MAAP_LOG_COMPONENT
+#define MAAP_LOG_COMPONENT "MAAP"
+#endif
+
+// Log format options and sizes. Uncomment to include the formatted info.
+#define LOG_MSG_LEN 1024
+
+// The length of the full message
+#define LOG_FULL_MSG_LEN 1024
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+static const int MAAP_LOG_TIME_INFO = FALSE;
+#define LOG_TIME_LEN 9
+//#define LOG_TIME_LEN 1
+
+static const int MAAP_LOG_TIMESTAMP_INFO = TRUE;
+#define LOG_TIMESTAMP_LEN 32
+//#define LOG_TIMESTAMP_LEN 1
+
+static const int MAAP_LOG_FILE_INFO = FALSE;
+//#define LOG_FILE_LEN 256
+#define LOG_FILE_LEN 1
+
+static const int MAAP_LOG_PROC_INFO = FALSE;
+//#define LOG_PROC_LEN 64
+#define LOG_PROC_LEN 1
+
+static const int MAAP_LOG_THREAD_INFO = FALSE;
+//#define LOG_THREAD_LEN 64
+#define LOG_THREAD_LEN 1
+
+#define LOG_RT_MSG_LEN 256
+//#define LOG_RT_MSG_LEN 1
+
+#define MAAP_LOG_OUTPUT_FD stderr
+//#define MAAP_LOG_OUTPUT_FD stdout
+
+#define MAAP_LOG_STDOUT_CONSOLE_WIDTH 80
+
+static const int MAAP_LOG_EXTRA_NEWLINE = TRUE;
+
+// When MAAP_LOG_FROM_THREAD the message output will be output from a separate thread/task
+// Primary intended use is for debugging.
+// It is expected that MAAP_LOG_PULL_MODE will not be used at the same time as this option.
+static const int MAAP_LOG_FROM_THREAD = TRUE;
+
+// When MAAP_LOG_PULL_MODE the messages will be queued and can be pulled using the
+// maapLogGetMsg() call. This could be from an logger interface module or host application.
+// It is expected that MAAP_LOG_FROM_THREAD will not be used at the same time as this option.
+static const int MAAP_LOG_PULL_MODE = FALSE;
+
+// When using the MAAP_LOG_FROM_THREAD option. These defines control the behavior of the msg queue
+#define LOG_QUEUE_MSG_LEN 256
+#define LOG_QUEUE_MSG_SIZE (LOG_QUEUE_MSG_LEN + 1)
+#define LOG_QUEUE_MSG_CNT 82
+#define LOG_QUEUE_SLEEP_MSEC 100
+
+// RT (RealTime logging) related defines
+#define LOG_RT_QUEUE_CNT 128
+#define LOG_RT_BEGIN TRUE
+#define LOG_RT_ITEM TRUE
+#define LOG_RT_END TRUE
+typedef enum {
+ LOG_RT_DATATYPE_NONE,
+ LOG_RT_DATATYPE_CONST_STR,
+ LOG_RT_DATATYPE_NOW_TS,
+ LOG_RT_DATATYPE_U16,
+ LOG_RT_DATATYPE_S16,
+ LOG_RT_DATATYPE_U32,
+ LOG_RT_DATATYPE_S32,
+ LOG_RT_DATATYPE_U64,
+ LOG_RT_DATATYPE_S64,
+ LOG_RT_DATATYPE_FLOAT
+} log_rt_datatype_t;
+
+
+#define LOG_VARX(x, y) x ## y
+#define LOG_VAR(x, y) LOG_VARX(x, y)
+
+// Log a message once. Technically once every 4.2 billion attempts. Usage: IF_LOG_ONCE() MAAP_LOG_INFO(...)
+#define IF_LOG_ONCE() static uint32_t LOG_VAR(logOnce,__LINE__) = 0; if (!LOG_VAR(logOnce,__LINE__)++)
+
+// Log a message at an interval. Usage: IF_LOG_INTERVAL(100) MAAP_LOG_INFO(...)
+#define IF_LOG_INTERVAL(x) static uint32_t LOG_VAR(logOnce,__LINE__) = 0; if (!(LOG_VAR(logOnce,__LINE__)++ % (x)))
+
+
+#define ETH_FORMAT "%02x:%02x:%02x:%02x:%02x:%02x"
+#define ETH_OCTETS(a) (a)[0],(a)[1],(a)[2],(a)[3],(a)[4],(a)[5]
+
+
+void maapLogInit(void);
+
+void maapLogExit(void);
+
+void maapLogFn(
+ int level,
+ const char *tag,
+ const char *company,
+ const char *component,
+ const char *path,
+ int line,
+ const char *fmt,
+ ...);
+
+void maapLogRT(int level, int bBegin, int bItem, int bEnd, char *pFormat, log_rt_datatype_t dataType, void *pVar);
+
+void maapLogBuffer(
+ int level,
+ const uint8_t *pData,
+ int dataLen,
+ int lineLen,
+ const char *company,
+ const char *component,
+ const char *path,
+ int line);
+
+
+#ifdef MAAP_LOG_ON
+#define MAAP_LOGF_DEV(LEVEL, FMT, ...) do { if (LEVEL <= MAAP_LOG_LEVEL) maapLogFn(0, "DEV", MAAP_LOG_COMPANY, MAAP_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__); } while(0)
+#define MAAP_LOGF_ERROR(FMT, ...) do { if (MAAP_LOG_LEVEL_ERROR <= MAAP_LOG_LEVEL) maapLogFn(0, "ERROR", MAAP_LOG_COMPANY, MAAP_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__); } while(0)
+#define MAAP_LOGF_WARNING(FMT, ...) do { if (MAAP_LOG_LEVEL_WARNING <= MAAP_LOG_LEVEL) maapLogFn(0, "WARNING", MAAP_LOG_COMPANY, MAAP_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__); } while(0)
+#define MAAP_LOGF_INFO(FMT, ...) do { if (MAAP_LOG_LEVEL_INFO <= MAAP_LOG_LEVEL) maapLogFn(0, "INFO", MAAP_LOG_COMPANY, MAAP_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__); } while(0)
+#define MAAP_LOGF_STATUS(FMT, ...) do { if (MAAP_LOG_LEVEL_STATUS <= MAAP_LOG_LEVEL) maapLogFn(0, "STATUS", MAAP_LOG_COMPANY, MAAP_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__); } while(0)
+#define MAAP_LOGF_DEBUG(FMT, ...) do { if (MAAP_LOG_LEVEL_DEBUG <= MAAP_LOG_LEVEL) maapLogFn(0, "DEBUG", MAAP_LOG_COMPANY, MAAP_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__); } while(0)
+#define MAAP_LOGF_VERBOSE(FMT, ...) do { if (MAAP_LOG_LEVEL_VERBOSE <= MAAP_LOG_LEVEL) maapLogFn(0, "VERBOSE", MAAP_LOG_COMPANY, MAAP_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__); } while(0)
+#define MAAP_LOG_DEV(LEVEL, MSG) do { if (LEVEL <= MAAP_LOG_LEVEL) maapLogFn(0, "DEV", MAAP_LOG_COMPANY, MAAP_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG); } while(0)
+#define MAAP_LOG_ERROR(MSG) do { if (MAAP_LOG_LEVEL_ERROR <= MAAP_LOG_LEVEL) maapLogFn(0, "ERROR", MAAP_LOG_COMPANY, MAAP_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG); } while(0)
+#define MAAP_LOG_WARNING(MSG) do { if (MAAP_LOG_LEVEL_WARNING <= MAAP_LOG_LEVEL) maapLogFn(0, "WARNING", MAAP_LOG_COMPANY, MAAP_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG); } while(0)
+#define MAAP_LOG_INFO(MSG) do { if (MAAP_LOG_LEVEL_INFO <= MAAP_LOG_LEVEL) maapLogFn(0, "INFO", MAAP_LOG_COMPANY, MAAP_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG); } while(0)
+#define MAAP_LOG_STATUS(MSG) do { if (MAAP_LOG_LEVEL_STATUS <= MAAP_LOG_LEVEL) maapLogFn(0, "STATUS", MAAP_LOG_COMPANY, MAAP_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG); } while(0)
+#define MAAP_LOG_DEBUG(MSG) do { if (MAAP_LOG_LEVEL_DEBUG <= MAAP_LOG_LEVEL) maapLogFn(0, "DEBUG", MAAP_LOG_COMPANY, MAAP_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG); } while(0)
+#define MAAP_LOG_VERBOSE(MSG) do { if (MAAP_LOG_LEVEL_VERBOSE <= MAAP_LOG_LEVEL) maapLogFn(0, "VERBOSE", MAAP_LOG_COMPANY, MAAP_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG); } while(0)
+#define MAAP_LOGRT_ERROR(BEGIN, ITEM, END, FMT, TYPE, VAL) maapLogRT(MAAP_LOG_LEVEL_ERROR, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define MAAP_LOGRT_WARNING(BEGIN, ITEM, END, FMT, TYPE, VAL) maapLogRT(MAAP_LOG_LEVEL_WARNING, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define MAAP_LOGRT_INFO(BEGIN, ITEM, END, FMT, TYPE, VAL) maapLogRT(MAAP_LOG_LEVEL_INFO, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define MAAP_LOGRT_STATUS(BEGIN, ITEM, END, FMT, TYPE, VAL) maapLogRT(MAAP_LOG_LEVEL_STATUS, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define MAAP_LOGRT_DEBUG(BEGIN, ITEM, END, FMT, TYPE, VAL) maapLogRT(MAAP_LOG_LEVEL_DEBUG, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define MAAP_LOGRT_VERBOSE(BEGIN, ITEM, END, FMT, TYPE, VAL) maapLogRT(MAAP_LOG_LEVEL_VERBOSE, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define MAAP_LOG_BUFFER(LEVEL, DATA, DATALEN, LINELINE) do { if (LEVEL <= MAAP_LOG_LEVEL) maapLogBuffer(0, DATA, DATALEN, LINELINE, MAAP_LOG_COMPANY, MAAP_LOG_COMPONENT, __FILE__, __LINE__); } while(0)
+#else
+#define MAAP_LOGF_DEV(LEVEL, FMT, ...)
+#define MAAP_LOGF_ERROR(FMT, ...)
+#define MAAP_LOGF_WARNING(FMT, ...)
+#define MAAP_LOGF_INFO(FMT, ...)
+#define MAAP_LOGF_STATUS(FMT, ...)
+#define MAAP_LOGF_DEBUG(FMT, ...)
+#define MAAP_LOGF_VERBOSE(FMT, ...)
+#define MAAP_LOG_DEV(LEVEL, FMT, ...)
+#define MAAP_LOG_ERROR(MSG)
+#define MAAP_LOG_WARNING(MSG)
+#define MAAP_LOG_INFO(MSG)
+#define MAAP_LOG_STATUS(MSG)
+#define MAAP_LOG_DEBUG(MSG)
+#define MAAP_LOG_VERBOSE(MSG)
+#define MAAP_LOGRT_ERROR(BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define MAAP_LOGRT_WARNING(BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define MAAP_LOGRT_INFO(BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define MAAP_LOGRT_STATUS(BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define MAAP_LOGRT_DEBUG(BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define MAAP_LOGRT_VERBOSE(BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define MAAP_LOG_BUFFER(LEVEL, DATA, DATALEN, LINELINE)
+#endif // MAAP_LOG_ON
+
+// Get a queued log message. Intended to be used with the MAAP_LOG_PULL_MODE option.
+// Message will not be null terminated.
+uint32_t maapLogGetMsg(uint8_t *pBuf, uint32_t bufSize);
+
+#endif // MAAP_LOG_H
diff --git a/daemons/maap/common/maap_log_queue.c b/daemons/maap/common/maap_log_queue.c
new file mode 100644
index 00000000..ef6f3289
--- /dev/null
+++ b/daemons/maap/common/maap_log_queue.c
@@ -0,0 +1,207 @@
+/*************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(_WIN32) && (_MSC_VER < 1800)
+/* Visual Studio 2012 and earlier */
+typedef unsigned __int8 uint8_t;
+typedef unsigned __int32 uint32_t;
+#else
+#include <inttypes.h>
+#endif
+
+#include "maap_log_queue.h"
+
+#define MAAP_LOG_COMPONENT "Queue"
+#include "maap_log.h"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+struct maap_log_queue_elem {
+ int setFlg;
+ void *data;
+};
+
+struct maap_log_queue {
+ // Size of each element
+ uint32_t elemSize;
+
+ // Number of queue element slots
+ uint32_t queueSize;
+
+ // Next element to be filled
+ uint32_t head;
+
+ // Next element to be pulled
+ uint32_t tail;
+
+ maap_log_queue_elem_t elemArray;
+};
+
+maap_log_queue_t maapLogQueueNewQueue(uint32_t elemSize, uint32_t queueSize)
+{
+ maap_log_queue_t retQueue;
+
+ if (elemSize < 1 || queueSize < 1)
+ return NULL;
+
+ retQueue = calloc(1, sizeof(struct maap_log_queue));
+ if (retQueue) {
+ retQueue->elemArray = calloc(queueSize, sizeof(struct maap_log_queue_elem));
+ if (retQueue->elemArray) {
+ uint32_t i1;
+ for (i1 = 0; i1 < queueSize; i1++) {
+ retQueue->elemArray[i1].data = calloc(1, elemSize);
+ if (!retQueue->elemArray[i1].data) {
+ maapLogQueueDeleteQueue(retQueue);
+ return NULL;
+ }
+ }
+ }
+ else {
+ maapLogQueueDeleteQueue(retQueue);
+ return NULL;
+ }
+
+ retQueue->elemSize = elemSize;
+ retQueue->queueSize = queueSize;
+ retQueue->head = 0;
+ retQueue->tail = 0;
+ }
+
+ return retQueue;
+}
+
+void maapLogQueueDeleteQueue(maap_log_queue_t queue)
+{
+ if (queue) {
+ uint32_t i1;
+ for (i1 = 0; i1 < queue->queueSize; i1++) {
+ free(queue->elemArray[i1].data);
+ queue->elemArray[i1].data = NULL;
+ }
+ free(queue->elemArray);
+ queue->elemArray = NULL;
+ free(queue);
+ }
+}
+
+uint32_t maapLogQueueGetQueueSize(maap_log_queue_t queue)
+{
+ if (queue) {
+ return queue->queueSize;
+ }
+ return 0;
+}
+
+uint32_t maapLogQueueGetElemCount(maap_log_queue_t queue)
+{
+ uint32_t cnt = 0;
+ if (queue) {
+ if (queue->head > queue->tail) {
+ cnt += queue->head - queue->tail - 1;
+ }
+ else if (queue->head < queue->tail) {
+ cnt += queue->head + ((queue->queueSize - 1) - queue->tail);
+ }
+
+ if (queue->elemArray[queue->tail].setFlg) {
+ cnt++;
+ }
+ }
+ return cnt;
+}
+
+uint32_t maapLogQueueGetElemSize(maap_log_queue_t queue)
+{
+ if (queue) {
+ return queue->elemSize;
+ }
+ return 0;
+}
+
+void *maapLogQueueData(maap_log_queue_elem_t elem)
+{
+ if (elem) {
+ return elem->data;
+ }
+ return NULL;
+}
+
+maap_log_queue_elem_t maapLogQueueHeadLock(maap_log_queue_t queue)
+{
+ if (queue) {
+ if (!queue->elemArray[queue->head].setFlg) {
+ return &queue->elemArray[queue->head];
+ }
+ }
+ return NULL;
+}
+
+void maapLogQueueHeadUnlock(maap_log_queue_t queue)
+{
+}
+
+void maapLogQueueHeadPush(maap_log_queue_t queue)
+{
+ if (queue) {
+ queue->elemArray[queue->head++].setFlg = TRUE;
+ if (queue->head >= queue->queueSize) {
+ queue->head = 0;
+ }
+ }
+}
+
+maap_log_queue_elem_t maapLogQueueTailLock(maap_log_queue_t queue)
+{
+ if (queue) {
+ if (queue->elemArray[queue->tail].setFlg) {
+ return &queue->elemArray[queue->tail];
+ }
+ }
+ return NULL;
+}
+
+void maapLogQueueTailUnlock(maap_log_queue_t queue)
+{
+}
+
+void maapLogQueueTailPull(maap_log_queue_t queue)
+{
+ if (queue) {
+ queue->elemArray[queue->tail++].setFlg = FALSE;
+ if (queue->tail >= queue->queueSize) {
+ queue->tail = 0;
+ }
+ }
+}
diff --git a/daemons/maap/common/maap_log_queue.h b/daemons/maap/common/maap_log_queue.h
new file mode 100644
index 00000000..b875443e
--- /dev/null
+++ b/daemons/maap/common/maap_log_queue.h
@@ -0,0 +1,78 @@
+/*************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************/
+
+/*
+* MODULE SUMMARY : Interface for a basic dynamic array abstraction.
+*
+* - Fixed size queue.
+* - Only head and tail access possible.
+* - Head and Tail locking.
+* - If there is a single task accessing head and a single task accessing tail no synchronization is needed.
+* - If synchronization is needed the Pull and Push functions should be protected before calling.
+*/
+
+#ifndef MAAP_LOG_QUEUE_H
+#define MAAP_LOG_QUEUE_H 1
+
+typedef struct maap_log_queue_elem * maap_log_queue_elem_t;
+typedef struct maap_log_queue * maap_log_queue_t;
+
+// Create an queue. Returns NULL on failure.
+maap_log_queue_t maapLogQueueNewQueue(uint32_t elemSize, uint32_t queueSize);
+
+// Delete an array.
+void maapLogQueueDeleteQueue(maap_log_queue_t queue);
+
+// Get number of queue slots
+uint32_t maapLogQueueGetQueueSize(maap_log_queue_t queue);
+
+// Get number of element
+uint32_t maapLogQueueGetElemCount(maap_log_queue_t queue);
+
+// Get element size
+uint32_t maapLogQueueGetElemSize(maap_log_queue_t queue);
+
+// Get data of the element. Returns NULL on failure.
+void *maapLogQueueData(maap_log_queue_elem_t elem);
+
+// Lock the head element.
+maap_log_queue_elem_t maapLogQueueHeadLock(maap_log_queue_t queue);
+
+// Unlock the head element.
+void maapLogQueueHeadUnlock(maap_log_queue_t queue);
+
+// Push the head element making it available for tail access.
+void maapLogQueueHeadPush(maap_log_queue_t queue);
+
+// Lock the tail element.
+maap_log_queue_elem_t maapLogQueueTailLock(maap_log_queue_t queue);
+
+// Unlock the tail element.
+void maapLogQueueTailUnlock(maap_log_queue_t queue);
+
+// Pull (remove) the tail element
+void maapLogQueueTailPull(maap_log_queue_t queue);
+
+#endif // MAAP_LOG_QUEUE_H
diff --git a/daemons/maap/common/maap_net.c b/daemons/maap/common/maap_net.c
new file mode 100644
index 00000000..90e90e6f
--- /dev/null
+++ b/daemons/maap/common/maap_net.c
@@ -0,0 +1,258 @@
+/*************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <assert.h>
+
+#include "maap_net.h"
+
+#define MAAP_LOG_COMPONENT "Net"
+#include "maap_log.h"
+
+/* Number of preallocated buffers to use. */
+#define NUM_BUFFERS 4
+
+/* Uncomment the DEBUG_NET_MSG define to display debug messages. */
+#define DEBUG_NET_MSG
+
+
+typedef enum {
+ BUFFER_FREE = 0,
+ BUFFER_SUPPLIED,
+ BUFFER_QUEUED,
+ BUFFER_SENDING,
+ } Buffer_State;
+
+struct maap_buffer {
+ char buffer[MAAP_NET_BUFFER_SIZE];
+ Buffer_State state;
+ struct maap_buffer *pNext; /* Pointer to next item when used in a linked list */
+};
+
+struct maap_net {
+ struct maap_buffer net_buffer[NUM_BUFFERS];
+ struct maap_buffer *pFirst; /* Linked list of additional buffers, in case more than NUM_BUFFERS supplied. */
+};
+
+Net *Net_newNet(void)
+{
+ Net *pNew;
+
+ pNew = malloc(sizeof(Net));
+ if (!pNew) { return NULL; }
+ memset(pNew, 0, sizeof(Net));
+ return pNew;
+}
+
+void Net_delNet(Net *net)
+{
+ struct maap_buffer *pDel;
+
+ assert(net);
+ while (net->pFirst) {
+ pDel = net->pFirst;
+ net->pFirst = pDel->pNext;
+ free(pDel);
+ }
+ free(net);
+}
+
+void *Net_getPacketBuffer(Net *net)
+{
+ struct maap_buffer *pNew, *pLast;
+ int buffer_index;
+
+ assert(net);
+
+ /* See if one of the preallocated buffers is available. */
+ for (buffer_index = 0; buffer_index < NUM_BUFFERS; ++buffer_index)
+ {
+ if (net->net_buffer[buffer_index].state == BUFFER_FREE)
+ {
+ net->net_buffer[buffer_index].state = BUFFER_SUPPLIED;
+#ifdef DEBUG_NET_MSG
+ MAAP_LOGF_DEBUG("Allocated buffer %d", buffer_index);
+#endif
+ return (void *)(net->net_buffer[buffer_index].buffer);
+ }
+ }
+
+ /* We need to create an overflow buffer. */
+ pNew = malloc(sizeof(struct maap_buffer));
+ if (pNew) {
+ memset(pNew, 0, sizeof(struct maap_buffer));
+ if (net->pFirst == NULL) {
+ net->pFirst = pNew;
+ } else {
+ pLast = net->pFirst;
+ while (pLast->pNext) { pLast = pLast->pNext; }
+ pLast->pNext = pNew;
+ }
+
+ pNew->state = BUFFER_SUPPLIED;
+#ifdef DEBUG_NET_MSG
+ MAAP_LOGF_DEBUG("Allocated buffer 0x%llx", (long long int)(uintptr_t) pNew);
+#endif
+ return (void *)(pNew->buffer);
+ }
+
+ assert(0);
+ return NULL;
+}
+
+int Net_queuePacket(Net *net, void *buffer)
+{
+ struct maap_buffer *pTest;
+ int buffer_index;
+
+ assert(net);
+
+ /* See if the supplied buffer is one of the preallocated buffers. */
+ for (buffer_index = 0; buffer_index < NUM_BUFFERS; ++buffer_index)
+ {
+ if (net->net_buffer[buffer_index].buffer == buffer)
+ {
+ /* We found the buffer provided. */
+ assert(net->net_buffer[buffer_index].state == BUFFER_SUPPLIED);
+ net->net_buffer[buffer_index].state = BUFFER_QUEUED;
+#ifdef DEBUG_NET_MSG
+ MAAP_LOGF_DEBUG("Queuing buffer %d", buffer_index);
+#endif
+ return 0;
+ }
+ }
+
+ /* See if the supplied buffer is one of the allocated buffers. */
+ for (pTest = net->pFirst; pTest != NULL; pTest = pTest->pNext)
+ {
+ if (pTest->buffer == buffer)
+ {
+ /* We found the the buffer provided. */
+ assert(pTest->state == BUFFER_SUPPLIED);
+ pTest->state = BUFFER_QUEUED;
+#ifdef DEBUG_NET_MSG
+ MAAP_LOGF_DEBUG("Queuing buffer 0x%llx", (long long int)(uintptr_t) pTest);
+#endif
+ return 0;
+ }
+ }
+
+ assert(0);
+ return -1;
+}
+
+void *Net_getNextQueuedPacket(Net *net)
+{
+ struct maap_buffer *pTest;
+ int buffer_index;
+
+ assert(net);
+
+ /* See if one of the preallocated buffers is available. */
+ for (buffer_index = 0; buffer_index < NUM_BUFFERS; ++buffer_index)
+ {
+ if (net->net_buffer[buffer_index].state == BUFFER_QUEUED)
+ {
+ net->net_buffer[buffer_index].state = BUFFER_SENDING;
+#ifdef DEBUG_NET_MSG
+ MAAP_LOGF_DEBUG("Buffer %d pulled from queue", buffer_index);
+ MAAP_LOG_DEBUG(""); /* Blank line */
+#endif
+ return (void *)(net->net_buffer[buffer_index].buffer);
+ }
+ }
+
+ /* See if one of the allocated buffers is available. */
+ for (pTest = net->pFirst; pTest != NULL; pTest = pTest->pNext)
+ {
+ if (pTest->state == BUFFER_QUEUED)
+ {
+ pTest->state = BUFFER_SENDING;
+#ifdef DEBUG_NET_MSG
+ MAAP_LOGF_DEBUG("Buffer 0x%llx pulled from queue", (long long int)(uintptr_t) pTest);
+ MAAP_LOG_DEBUG(""); /* Blank line */
+#endif
+ return (void *)(pTest->buffer);
+ }
+ }
+
+ /* No packets are currently in the queue. */
+ return NULL;
+}
+
+int Net_freeQueuedPacket(Net *net, void *buffer)
+{
+ struct maap_buffer *pTest, *pPrevious;
+ int buffer_index;
+
+ assert(net);
+
+ /* See if the supplied buffer is one of the preallocated buffers. */
+ for (buffer_index = 0; buffer_index < NUM_BUFFERS; ++buffer_index)
+ {
+ if (net->net_buffer[buffer_index].buffer == buffer)
+ {
+ /* We found the buffer provided. */
+ assert(net->net_buffer[buffer_index].state == BUFFER_SENDING);
+ net->net_buffer[buffer_index].state = BUFFER_FREE;
+#ifdef DEBUG_NET_MSG
+ MAAP_LOGF_DEBUG("Freed buffer %d", buffer_index);
+#endif
+ return 0;
+ }
+ }
+
+ /* See if the supplied buffer is one of the allocated buffers. */
+ for (pPrevious = NULL, pTest = net->pFirst; pTest != NULL; pPrevious = pTest, pTest = pTest->pNext)
+ {
+ if (pTest->buffer == buffer)
+ {
+ /* We found the the buffer provided. */
+ assert(pTest->state == BUFFER_SENDING);
+ pTest->state = BUFFER_FREE;
+#ifdef DEBUG_NET_MSG
+ MAAP_LOGF_DEBUG("Freed buffer 0x%llx", (long long int)(uintptr_t) pTest);
+#endif
+
+ /* Free the buffer. */
+ if (pPrevious) {
+ /* Remove this item from the middle (or end) of the queue. */
+ pPrevious->pNext = pTest->pNext;
+ } else {
+ /* Remove this item from the start of the queue. */
+ net->pFirst = pTest->pNext;
+ }
+ free(pTest);
+
+ return 0;
+ }
+ }
+
+ assert(0);
+ return -1;
+}
diff --git a/daemons/maap/common/maap_net.h b/daemons/maap/common/maap_net.h
new file mode 100644
index 00000000..b0236462
--- /dev/null
+++ b/daemons/maap/common/maap_net.h
@@ -0,0 +1,99 @@
+/*************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************/
+
+/**
+ * @file
+ *
+ * @brief Support for platform-specific networking operations
+ *
+ * These functions support the transmission of raw networking packets.
+ * The functions are generic, and allow for a platform-specific network implementation.
+ *
+ * The buffers are expected to be raw Ethernet packets. In other words,
+ * the first 12 bytes should be the destination and source MAC Addresses.
+ */
+
+#ifndef MAAP_NET_H
+#define MAAP_NET_H
+
+/** Size in bytes of the raw network packets to handle. */
+#define MAAP_NET_BUFFER_SIZE 64
+
+/** Structure to hold the networking information. @b struct @b maap_net will be defined in the platform-specific implementation file. */
+typedef struct maap_net Net;
+
+/**
+ * Create a new #Net pointer to use for packet transmission support.
+ *
+ * @return A #Net pointer, or NULL if an error occurred.
+ */
+Net *Net_newNet(void);
+
+/**
+ * Delete a #Net pointer when done with the packet transmission.
+ *
+ * @param net The pointer to free
+ */
+void Net_delNet(Net *net);
+
+/**
+ * Get a buffer to fill with the packet contents.
+ *
+ * @param net The #Net pointer from #Net_newNet to use
+ *
+ * @return The buffer to fill. The buffer will be #MAAP_NET_BUFFER_SIZE bytes in size.
+ */
+void *Net_getPacketBuffer(Net *net);
+
+/**
+ * Queue a packet buffer for transmission.
+ *
+ * @param net The #Net pointer from #Net_newNet to use
+ * @param buffer The buffer from #Net_getPacketBuffer that was filled
+ *
+ * @return 0 if the buffer was queued, or -1 if an error occurred.
+ */
+int Net_queuePacket(Net *net, void *buffer);
+
+/**
+ * Get the next packet from the queue.
+ *
+ * @param net The #Net pointer from #Net_newNet to use
+ *
+ * @return The buffer with the network data to transmit, or NULL if an error occurred.
+ */
+void *Net_getNextQueuedPacket(Net *net);
+
+/**
+ * Free a packet after it has been transmitted.
+ *
+ * @param net The #Net pointer from #Net_newNet to use
+ * @param buffer The buffer from #Net_getNextQueuedPacket that was filled
+ *
+ * @return 0 if the buffer was freed, or -1 if an error occurred.
+ */
+int Net_freeQueuedPacket(Net *net, void *buffer);
+
+#endif
diff --git a/daemons/maap/common/maap_packet.c b/daemons/maap/common/maap_packet.c
new file mode 100644
index 00000000..55a30110
--- /dev/null
+++ b/daemons/maap/common/maap_packet.c
@@ -0,0 +1,205 @@
+/*************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************/
+
+#include <assert.h>
+#include <string.h>
+#ifdef _WIN32
+#include "Winsock2.h"
+#endif
+#include "maap.h"
+#include "maap_packet.h"
+
+#define MAAP_LOG_COMPONENT "Packet"
+#include "maap_log.h"
+
+int unpack_maap(MAAP_Packet *packet, const uint8_t *stream) {
+ uint64_t tmp64;
+ uint16_t tmp16;
+ uint8_t tmp8;
+
+ assert(packet);
+ assert(stream);
+
+ memcpy(&tmp64, stream, 6);
+ packet->DA = BE64TOH(tmp64) >> 16;
+ stream += 6;
+
+ memcpy(&tmp64, stream, 6);
+ packet->SA = BE64TOH(tmp64) >> 16;
+ stream += 6;
+
+ memcpy(&tmp16, stream, 2);
+ packet->Ethertype = BE16TOH(tmp16);
+ stream += 2;
+
+ tmp8 = *stream;
+ packet->subtype = tmp8;
+ stream++;
+
+ tmp8 = *stream;
+ packet->SV = (tmp8 & 0x80) >> 7;
+ packet->version = (tmp8 & 0x70) >> 4;
+ packet->message_type = tmp8 & 0x0f;
+ stream++;
+
+ memcpy(&tmp8, stream, 1);
+ packet->maap_version = (tmp8 & 0xf8) >> 3;
+
+ memcpy(&tmp16, stream, 2);
+ packet->control_data_length = BE16TOH(tmp16) & 0x07ff;
+ stream += 2;
+
+ memcpy(&tmp64, stream, 8);
+ packet->stream_id = BE64TOH(tmp64);
+ stream += 8;
+
+ memcpy(&tmp64, stream, 6);
+ packet->requested_start_address = BE64TOH(tmp64) >> 16;
+ stream += 6;
+
+ memcpy(&tmp16, stream, 2);
+ packet->requested_count = BE16TOH(tmp16);
+ stream += 2;
+
+ memcpy(&tmp64, stream, 6);
+ packet->conflict_start_address = BE64TOH(tmp64) >> 16;
+ stream += 6;
+
+ memcpy(&tmp16, stream, 2);
+ packet->conflict_count = BE16TOH(tmp16);
+
+ return 0;
+ }
+
+int pack_maap(const MAAP_Packet *packet, uint8_t *stream) {
+ uint64_t tmp64;
+ uint16_t tmp16;
+ uint8_t tmp8;
+
+ assert(packet);
+ assert(stream);
+
+ tmp64 = HTOBE64(packet->DA << 16);
+ memcpy(stream, &tmp64, 6);
+ stream += 6;
+
+ tmp64 = HTOBE64(packet->SA << 16);
+ memcpy(stream, &tmp64, 6);
+ stream += 6;
+
+ tmp16 = HTOBE16(packet->Ethertype);
+ memcpy(stream, &tmp16, 2);
+ stream += 2;
+
+ tmp8 = (uint8_t) packet->subtype;
+ *stream = tmp8;
+ stream++;
+
+ tmp8 = (packet->SV << 7) | ((packet->version & 0x07) << 4) |
+ (packet->message_type & 0x0f);
+ *stream = tmp8;
+ stream++;
+
+ tmp16 = HTOBE16(((packet->maap_version & 0x001f) << 11) |
+ (packet->control_data_length & 0x07ff));
+ memcpy(stream, &tmp16, 2);
+ stream += 2;
+
+ tmp64 = HTOBE64(packet->stream_id);
+ memcpy(stream, &tmp64, 8);
+ stream += 8;
+
+ tmp64 = HTOBE64(packet->requested_start_address << 16);
+ memcpy(stream, &tmp64, 6);
+ stream += 6;
+
+ tmp16 = HTOBE16(packet->requested_count);
+ memcpy(stream, &tmp16, 2);
+ stream += 2;
+
+ tmp64 = HTOBE64(packet->conflict_start_address << 16);
+ memcpy(stream, &tmp64, 6);
+ stream += 6;
+
+ tmp16 = HTOBE16(packet->conflict_count);
+ memcpy(stream, &tmp16, 2);
+
+ return 0;
+}
+
+void init_packet(MAAP_Packet *packet, uint64_t dest_mac, uint64_t src_mac) {
+ assert(packet);
+ assert(dest_mac != 0);
+ assert(src_mac != 0);
+
+ packet->DA = dest_mac;
+ packet->SA = src_mac;
+ packet->Ethertype = MAAP_TYPE;
+ packet->subtype = MAAP_SUBTYPE;
+ packet->SV = 0; /* SV is 0 - Defined in IEEE 1722-2016 Table F.23 */
+ packet->version = 0; /* AVTP version is 0 - Defined in IEEE 1722-2016 4.4.3.4 */
+ packet->message_type = 0;
+ packet->maap_version = 1; /* MAAP version is 1 - Defined in IEEE 1722-2016 B.2.3.1 */
+ packet->control_data_length = 16; /* Control data length is 16 - Defined in IEEE 1722-2016 B.2.1 */
+ packet->stream_id = 0; /* MAAP stream_id is 0 - Defined in IEEE 1722-2016 B.2.4 */
+ packet->requested_start_address = 0;
+ packet->requested_count = 0;
+ packet->conflict_start_address = 0;
+ packet->conflict_count = 0;
+}
+
+uint64_t convert_mac_address(const uint8_t macaddr[])
+{
+ uint64_t retVal;
+
+ assert(macaddr);
+ retVal = BE64TOH(*(uint64_t *)macaddr) >> 16;
+ return retVal;
+}
+
+int compare_mac_addresses(uint64_t local_mac, uint64_t remote_mac)
+{
+ int i;
+ uint8_t local_byte, remote_byte;
+
+ for (i = 0; i < 6; ++i)
+ {
+ /* Test the next least-significant byte. */
+ local_byte = (uint8_t)(local_mac & 0xFF);
+ remote_byte = (uint8_t)(remote_mac & 0xFF);
+
+ /* See if we have a difference. */
+ if (local_byte < remote_byte) return 1;
+ if (local_byte > remote_byte) return 0;
+
+ /* Try the next lowest-byte in the next iteration. */
+ local_mac = local_mac >> 8;
+ remote_mac = remote_mac >> 8;
+ }
+
+ /* Assume that our own packet was somehow reflected back at us.
+ * Return 1 to ignore this packet. */
+ return 1;
+}
diff --git a/daemons/maap/common/maap_packet.h b/daemons/maap/common/maap_packet.h
new file mode 100644
index 00000000..b1d9095d
--- /dev/null
+++ b/daemons/maap/common/maap_packet.h
@@ -0,0 +1,117 @@
+/*************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************/
+
+/**
+ * @file
+ *
+ * @brief Support for packing and unpacking MAAP packets
+ *
+ * These functions convert a binary stream of bytes into a #MAAP_Packet structure, or vice versa.
+ */
+
+#ifndef MAAP_PACKET_H
+#define MAAP_PACKET_H
+
+#include <stdint.h>
+
+#include "platform.h"
+
+#define MAAP_PROBE 1 /**< MAAP Probe MAC address(es) PDU - Defined in IEEE 1722-2016 Table B.1 */
+#define MAAP_DEFEND 2 /**< MAAP Defend address(es) response PDU - Defined in IEEE 1722-2016 Table B.1 */
+#define MAAP_ANNOUNCE 3 /**< MAAP Announce MAC address(es) acquired PDU - Defined in IEEE 1722-2016 Table B.1 */
+
+/** MAAP Packet contents - Defined in IEEE 1722-2016 Figure B.1 */
+typedef struct {
+ uint64_t DA; /**< Destination Address */
+ uint64_t SA; /**< Source Address */
+ uint16_t Ethertype; /**< AVTB Ethertype (i.e. @p MAAP_TYPE) */
+ uint16_t subtype; /**< AVTP Subtype (i.e. @p MAAP_SUBTYPE) */
+ uint8_t SV; /**< 1 if stream_id is valid, 0 otherwise. Always 0 for MAAP. */
+ uint8_t version; /**< AVTP Version. Always 0 for MAAP */
+ uint8_t message_type; /**< MAAP message type (MAAP_PROBE, MAAP_DEFEND, or MAAP_ANNOUNCE) */
+ uint8_t maap_version; /**< MAAP Version. Currently 1 for MAAP. */
+ uint16_t control_data_length; /**< Control Data Length in Bytes. Always 16 for MAAP. */
+ uint64_t stream_id; /**< MAAP stream_id. Always 0 for MAAP. */
+ uint64_t requested_start_address; /**< Starting address for a MAAP_PROBE or MAAP_ANNOUNCE.
+ * For a MAAP_DEFEND, the same address as the MAAP_PROBE or MAAP_ANNOUNCE that initiated the defend. */
+ uint16_t requested_count; /**< Number of addresses for a MAAP_PROBE or MAAP_ANNOUNCE.
+ * For a MAAP_DEFEND, the same number of addresses as the MAAP_PROBE or MAAP_ANNOUNCE that initiated the defend. */
+ uint64_t conflict_start_address; /**< For a MAAP_DEFEND, the starting address of the block that conflicts with the MAAP_PROBE or MAAP_ANNOUNCE. */
+ uint16_t conflict_count; /**< For a MAAP_DEFEND, the number of addresses in the block that conflicts with the MAAP_PROBE or MAAP_ANNOUNCE. */
+} MAAP_Packet;
+
+/**
+ * Initialize a #MAAP_Packet structure to prepare for sending a MAAP packet.
+ *
+ * @param packet Pointer to an empty #MAAP_Packet structure to fill
+ * @param dest_mac Destination MAC Address for the packet
+ * @param src_mac Source MAC Address for the packet
+ */
+void init_packet(MAAP_Packet *packet, uint64_t dest_mac, uint64_t src_mac);
+
+/**
+ * Convert (pack) a #MAAP_Packet structure into a binary stream of bytes.
+ *
+ * @param packet #MAAP_Packet structure to convert
+ * @param stream Pointer to the buffer to fill with the binary stream
+ *
+ * @return 0 if successful, -1 if an error occurred.
+ */
+int pack_maap(const MAAP_Packet *packet, uint8_t *stream);
+
+/**
+ * Convert (unpack) a binary stream of bytes into a #MAAP_Packet structure
+ *
+ * @param packet #MAAP_Packet structure to fill with the packet contents
+ * @param stream Pointer to the buffer containing the binary stream
+ *
+ * @return 0 if successful, -1 if an error occurred.
+ */
+int unpack_maap(MAAP_Packet *packet, const uint8_t *stream);
+
+/**
+ * Convert a byte-order MAC Address into a 64-bit number.
+ *
+ * The 64-bit number format is used to fill #MAAP_Packet#DA and #MAAP_Packet#SA in the #MAAP_Packet structure.
+ *
+ * @param macaddr Pointer to the byte-order MAC Address to convert
+ *
+ * @return A 64-bit number equivalent to the supplied MAC Address
+ */
+uint64_t convert_mac_address(const uint8_t macaddr[]);
+
+/**
+ * Compare two MAC addresses, starting with the least-significant bytes, to determine if the local address is numerically lower.
+ *
+ * @note This is equivalent to the compare_MAC function in IEEE 1722-2016 B3.6.4
+ *
+ * @param local_mac The MAC Address for the local network interface of the computer running this application
+ * @param remote_mac The source MAC Address in a MAAP packet that was received
+ *
+ * @return 1 if the local_mac is less than then remote_mac, 0 otherwise
+ */
+int compare_mac_addresses(uint64_t local_mac, uint64_t remote_mac);
+
+#endif
diff --git a/daemons/maap/common/maap_parse.c b/daemons/maap/common/maap_parse.c
new file mode 100644
index 00000000..1c51c3ba
--- /dev/null
+++ b/daemons/maap/common/maap_parse.c
@@ -0,0 +1,222 @@
+/*************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(_WIN32) && (_MSC_VER < 1800)
+/* Visual Studio 2012 and earlier */
+#define strtoull(x,y,z) _strtoui64(x,y,z)
+#endif
+
+#include "maap.h"
+#include "maap_parse.h"
+
+#define MAAP_LOG_COMPONENT "Parse"
+#include "maap_log.h"
+
+/* Uncomment the DEBUG_CMD_MSG define to display command debug messages. */
+#define DEBUG_CMD_MSG
+
+
+int parse_text_cmd(char *buf, Maap_Cmd *cmd) {
+ char *argv[5];
+ int argc = 0;
+ char *p;
+ int set_cmd = 0;
+
+ p = strtok(buf, " \r\n");
+ while ((p != NULL) && (argc < sizeof(argv) / sizeof(*argv))) {
+ argv[argc++] = p;
+ p = strtok(NULL, " \r\n");
+ }
+
+ if (argc >= 1 && argc <= 3)
+ {
+ /* Give all parameters default values. */
+ cmd->kind = MAAP_CMD_INVALID;
+ cmd->id = -1; /* N/A */
+ cmd->start = 0; /* N/A */
+ cmd->count = 0; /* N/A */
+
+ if (strncmp(argv[0], "init", 4) == 0) {
+ if (argc == 1) {
+ cmd->kind = MAAP_CMD_INIT;
+ cmd->start = MAAP_DYNAMIC_POOL_BASE;
+ cmd->count = MAAP_DYNAMIC_POOL_SIZE;
+ set_cmd = 1;
+ } else if (argc == 3) {
+ cmd->kind = MAAP_CMD_INIT;
+ cmd->start = strtoull(argv[1], NULL, 16);
+ cmd->count = strtoul(argv[2], NULL, 0);
+ set_cmd = 1;
+ }
+ } else if (strncmp(argv[0], "reserve", 7) == 0) {
+ if (argc == 2) {
+ cmd->kind = MAAP_CMD_RESERVE;
+ cmd->count = strtoul(argv[1], NULL, 0);
+ set_cmd = 1;
+ } else if (argc == 3) {
+ cmd->kind = MAAP_CMD_RESERVE;
+ cmd->start = strtoull(argv[1], NULL, 16);
+ cmd->count = strtoul(argv[2], NULL, 0);
+ set_cmd = 1;
+ }
+ } else if (strncmp(argv[0], "release", 7) == 0 && argc == 2) {
+ cmd->kind = MAAP_CMD_RELEASE;
+ cmd->id = (int)strtoul(argv[1], NULL, 0);
+ set_cmd = 1;
+ } else if (strncmp(argv[0], "status", 7) == 0 && argc == 2) {
+ cmd->kind = MAAP_CMD_STATUS;
+ cmd->id = (int)strtoul(argv[1], NULL, 0);
+ set_cmd = 1;
+ } else if (strncmp(argv[0], "yield", 7) == 0 && argc == 2) {
+ cmd->kind = MAAP_CMD_YIELD;
+ cmd->id = (int)strtoul(argv[1], NULL, 0);
+ set_cmd = 1;
+ } else if (strncmp(argv[0], "exit", 4) == 0 && argc == 1) {
+ cmd->kind = MAAP_CMD_EXIT;
+ set_cmd = 1;
+ }
+ }
+
+ return set_cmd;
+ }
+
+int parse_write(Maap_Client *mc, const void *sender, char *buf, int *input_is_text) {
+ Maap_Cmd *bufcmd, cmd;
+ int rv = 0;
+ int retVal = 0;
+
+ bufcmd = (Maap_Cmd *)buf;
+
+ switch (bufcmd->kind) {
+ case MAAP_CMD_INIT:
+ case MAAP_CMD_RESERVE:
+ case MAAP_CMD_RELEASE:
+ case MAAP_CMD_STATUS:
+ case MAAP_CMD_YIELD:
+ case MAAP_CMD_EXIT:
+ if (input_is_text) { *input_is_text = 0; }
+ memcpy(&cmd, bufcmd, sizeof (Maap_Cmd));
+ rv = 1;
+ break;
+ default:
+ if (input_is_text) { *input_is_text = 1; }
+ memset(&cmd, 0, sizeof (Maap_Cmd));
+ rv = parse_text_cmd(buf, &cmd);
+ if (!rv) {
+ /* Unrecognized command. */
+ retVal = -1;
+ }
+ break;
+ }
+
+ if (rv) {
+ switch(cmd.kind) {
+ case MAAP_CMD_INIT:
+#ifdef DEBUG_CMD_MSG
+ MAAP_LOGF_DEBUG("Got cmd MAAP_CMD_INIT, range_base: 0x%016llx, range_size: 0x%04x",
+ (unsigned long long)cmd.start, cmd.count);
+#endif
+ rv = maap_init_client(mc, sender, cmd.start, cmd.count);
+ break;
+ case MAAP_CMD_RESERVE:
+#ifdef DEBUG_CMD_MSG
+ if (cmd.start != 0) {
+ MAAP_LOGF_DEBUG("Got cmd MAAP_CMD_RESERVE, start: 0x%016llx, length: %u",
+ (unsigned long long)cmd.start, (unsigned) cmd.count);
+ } else {
+ MAAP_LOGF_DEBUG("Got cmd MAAP_CMD_RESERVE, length: %u", (unsigned) cmd.count);
+ }
+#endif
+ rv = maap_reserve_range(mc, sender, cmd.start, cmd.count);
+ break;
+ case MAAP_CMD_RELEASE:
+#ifdef DEBUG_CMD_MSG
+ MAAP_LOGF_DEBUG("Got cmd MAAP_CMD_RELEASE, id: %d", (int) cmd.id);
+#endif
+ rv = maap_release_range(mc, sender, cmd.id);
+ break;
+ case MAAP_CMD_STATUS:
+#ifdef DEBUG_CMD_MSG
+ MAAP_LOGF_DEBUG("Got cmd MAAP_CMD_STATUS, id: %d", (int) cmd.id);
+#endif
+ maap_range_status(mc, sender, cmd.id);
+ break;
+ case MAAP_CMD_YIELD:
+#ifdef DEBUG_CMD_MSG
+ MAAP_LOGF_DEBUG("Got cmd MAAP_CMD_YIELD, id: %d", (int) cmd.id);
+#endif
+ rv = maap_yield_range(mc, sender, cmd.id);
+ break;
+ case MAAP_CMD_EXIT:
+#ifdef DEBUG_CMD_MSG
+ MAAP_LOG_DEBUG("Got cmd MAAP_CMD_EXIT");
+#endif
+ retVal = 1; /* Indicate that we should exit. */
+ break;
+ default:
+ MAAP_LOG_ERROR("Unrecognized input to parse_write");
+ retVal = -1;
+ break;
+ }
+ }
+
+ return retVal;
+}
+
+void parse_usage(print_notify_callback_t print_callback, void *callback_data)
+{
+ char szOutput[100];
+ print_callback(callback_data, MAAP_LOG_LEVEL_INFO,
+ "Input usage:");
+ print_callback(callback_data, MAAP_LOG_LEVEL_INFO,
+ " init [<range_base> <range_size>] - Initialize the MAAP daemon to recognize");
+ print_callback(callback_data, MAAP_LOG_LEVEL_INFO,
+ " the specified range of addresses. If not specified, it uses");
+ sprintf(szOutput,
+ " range_base=0x%llx, range_size=0x%04x.", MAAP_DYNAMIC_POOL_BASE, MAAP_DYNAMIC_POOL_SIZE);
+ print_callback(callback_data, MAAP_LOG_LEVEL_INFO, szOutput);
+ print_callback(callback_data, MAAP_LOG_LEVEL_INFO,
+ " reserve [<addr_base>] <addr_size> - Reserve a range of addresses of size");
+ print_callback(callback_data, MAAP_LOG_LEVEL_INFO,
+ " <addr_size> in the initialized range. If <addr_base> is specified,");
+ print_callback(callback_data, MAAP_LOG_LEVEL_INFO,
+ " that address base will be attempted first.");
+ print_callback(callback_data, MAAP_LOG_LEVEL_INFO,
+ " release <id> - Release the range of addresses with identifier ID");
+ print_callback(callback_data, MAAP_LOG_LEVEL_INFO,
+ " status <id> - Get the range of addresses associated with identifier ID");
+ print_callback(callback_data, MAAP_LOG_LEVEL_INFO,
+ " yield <id> - Yield the range of addresses associated with identifier ID.");
+ print_callback(callback_data, MAAP_LOG_LEVEL_INFO,
+ " This is only useful for testing.");
+ print_callback(callback_data, MAAP_LOG_LEVEL_INFO,
+ " exit - Shutdown the MAAP daemon");
+ print_callback(callback_data, MAAP_LOG_LEVEL_INFO,
+ " "); // Blank line
+}
diff --git a/daemons/maap/common/maap_parse.h b/daemons/maap/common/maap_parse.h
new file mode 100644
index 00000000..c079e696
--- /dev/null
+++ b/daemons/maap/common/maap_parse.h
@@ -0,0 +1,70 @@
+/*************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************/
+
+/**
+ * @file
+ *
+ * @brief Support for parsing and handling commands
+ *
+ * These functions convert a text string into a Maap_Cmd structure,
+ * and perform the supplied commands.
+ */
+
+#ifndef MAAP_PARSE_H_
+#define MAAP_PARSE_H_
+
+#include "maap_iface.h"
+
+/**
+ * Parse the incoming text data for a command.
+ *
+ * @param buf Binary or text data to parse
+ * @param cmd Pointer to the Maap_Cmd to fill with the binary equivalent of the command
+ *
+ * @return 1 if a valid command was received, 0 otherwise.
+ */
+int parse_text_cmd(char *buf, Maap_Cmd *cmd);
+
+/**
+ * Parse the incoming binary or text data, and perform the specified command, if any.
+ *
+ * @param mc Pointer to the Maap_Client structure to use
+ * @param sender Sender information pointer used to track the entity requesting the command
+ * @param buf Binary or text data to parse
+ * @param input_is_text Optional pointer for variable set to 1 if the input is text, 0 if the input is binary.
+ *
+ * @return 1 if the exit command was received, -1 for an unrecognized command, or 0 otherwise.
+ */
+int parse_write(Maap_Client *mc, const void *sender, char *buf, int *input_is_text);
+
+/**
+ * Prints the usage expected for parsing.
+ *
+ * @param print_callback Function of type #print_notify_callback_t that will handle printable results.
+ * @param callback_data Data to return with the callback.
+ */
+void parse_usage(print_notify_callback_t print_callback, void *callback_data);
+
+#endif /* MAAP_PARSE_H_ */
diff --git a/daemons/maap/common/maap_protocol.c b/daemons/maap/common/maap_protocol.c
deleted file mode 100644
index eb09b72e..00000000
--- a/daemons/maap/common/maap_protocol.c
+++ /dev/null
@@ -1,334 +0,0 @@
-/*************************************************************************
- Copyright (c) 2015 VAYAVYA LABS PVT LTD - http://vayavyalabs.com/
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- 1. Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- 3. Neither the name of the Vayavya labs nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
-
-****************************************************************************/
-
-/* MAC Address Acquisition Protocol- dynamically allocate multicast MAC address */
-#include "maap_protocol.h"
-
-extern uint8_t *maap_shm_mem;
-
-/* generate pseudo random mac_address in the MAAP range */
-void generate_address(maap_info_t *maap_info)
-{
- uint16_t val;
- uint8_t maap_address_llimit[6] = {0x91,0xE0,0xF0,0x00,0x00,0x00};
-
- memcpy(maap_info->requested_mac_add, maap_address_llimit, MAC_ADDR_LEN);
- val = rand_range(0x0000, 0xFDFF);
- maap_info->requested_mac_add[4] = (val & 0xff00) >> 8;
- maap_info->requested_mac_add[5] = val & 0x00ff;
-}
-
-int state_transit(maap_info_t *maap_info)
-{
- state_t current_state = maap_info->state;
- maap_pdu_t *maap_pdu = &maap_info->ethpkt.data;
- ethpkt_t *pkt_tx = &maap_info->ethpkt;
- ethpkt_t *pkt_rx = &maap_info->ethpkt_rx;
- msg_type_t msg_type = 0;
- uint8_t *s = NULL;
- int i= 0;
- int num_bytes = 0;
- int maap_probe_count;
-
- switch (current_state) {
- case INITIAL:
- DBG("state: INITIAL\n");
- generate_address(maap_info);
- maap_probe_count = MAAP_PROBE_RETRANSMITS;
- maap_info->state = PROBE;
- break;
-
- case PROBE:
- DBG("state: PROBE\n");
- prepare_ethpkt(maap_info, MAAP_PROBE);
-
- while (maap_probe_count) {
- /* send MAAP_PROBE */
- send_packet(pkt_tx);
- printf("\nSENT MAAP_PROBE \n");
-
- delay(0, PROBE_TIMER_MS);
-
- memset(pkt_rx, 0x00, ETH_PKT_LEN);
- /* Listen for MAAP_DEFEND */
- num_bytes = recv_packet(pkt_rx, NON_BLOCK);
- if (num_bytes > 0) {
- msg_type = pkt_rx->data.message_type;
- DBG("msg_type %x \n",msg_type);
-
- if (msg_type == MAAP_DEFEND ||
- msg_type == MAAP_ANNOUNCE ||
- msg_type == MAAP_PROBE) {
- if (compare_mac(pkt_rx->data.requested_start_address,
- maap_pdu->requested_start_address)) {
- DBG("\nReceived\
- MAAP_DEFEND frame from \
- Mac Address: ");
- DBG_ADDR(pkt_rx->header.h_source);
- DBG("\nRequested\
- Address of recv frame: ");
- DBG_ADDR(pkt_rx->data.requested_start_address);
- DBG("\nRequested Address: ");
- DBG_ADDR(maap_pdu->requested_start_address);
-
- maap_info->state = INITIAL;
- return 1;
- }
- } else {
- printf("\n Invalid MAAP packet\n");
- }
- } else {
- maap_probe_count -=1;
- }
- }
-
- maap_info->acquired_mac_count =
- maap_info->requested_mac_count;
- memcpy(maap_info->acquired_mac_add,
- maap_info->requested_mac_add, MAC_ADDR_LEN);
-
- prepare_ethpkt(maap_info, MAAP_ANNOUNCE);
- send_packet(pkt_tx);
-
- create_thread(maap_info, send_announce);
-
- printf("\nSENT MAAP_ANNOUNCE \n\nANNOUNCED ADDRESS:\n");
- DBG_ADDR(maap_info->acquired_mac_add);
-
- s = maap_shm_mem;
- /* writing allocated mac-address to shared memory */
- for (i = 0; i < MAC_ADDR_LEN ; i++) {
- *s++ = maap_info->acquired_mac_add[i];
- }
-
- maap_info->state = DEFEND;
- printf("\n\nSTATE change to DEFEND:\n");
- break;
-
- case DEFEND:
- memset(pkt_rx, 0x00, ETH_PKT_LEN);
- /* Listen MAAP_PROBE */
- num_bytes = recv_packet(pkt_rx, BLOCK);
-
- if (num_bytes > 0) {
- msg_type = pkt_rx->data.message_type;
- if (compare_mac(pkt_rx->data.requested_start_address,
- maap_info->acquired_mac_add)) {
- if (msg_type == MAAP_PROBE) {
- memcpy(maap_info->conflict_mac_add,
- pkt_rx->data.requested_start_address,
- MAC_ADDR_LEN);
- maap_info->conflict_mac_count =
- pkt_rx->data.requested_count;
-
- DBG("\n Received frame\
- MAAP_PROBE \n Source address of\
- the received frame:");
- DBG_ADDR(pkt_rx->header.h_source);
- DBG("\n Requested start address\
- of received frame :");
- DBG_ADDR(pkt_rx->data.requested_start_address);
- DBG("\n Announced Address :");
- DBG_ADDR(maap_info->acquired_mac_add);
-
- Lock();
- prepare_ethpkt(maap_info,
- MAAP_DEFEND);
- send_packet(pkt_tx);
- UnLock();
- DBG(" SENT DEFEND \n");
- } else if (msg_type == MAAP_ANNOUNCE ||
- msg_type == MAAP_DEFEND) {
- DBG("\n Received \
- msg_type-MAAP_ANNOUNCE \
- Source Address: ");
- DBG_ADDR(pkt_rx->header.h_source);
- DBG("\n Destination Address: ");
- DBG_ADDR(pkt_rx->header.h_dest);
-
- destroy_thread();
- maap_info->state = INITIAL;
- DBG("\nstate change to INITIAL");
- }
- }
- }
- break;
-
- default:
- printf("Error: Undefined State\n");
- break;
- }
-
- return 0;
-}
-
-
-void Init(maap_info_t *maap_info, uint8_t src_mac_adr[6])
-{
- maap_pdu_t *maap_pkt = &maap_info->ethpkt.data;
- uint8_t dest_mac[6];
- int i;
-
- DBG("Init\n");
- maap_info->state = INITIAL;
- maap_pkt->subtype = MAAP_SUBTYPE;
- maap_pkt->cd = 0x1;
- maap_pkt->message_type = 0x0;
- maap_pkt->version = 0x0;
- maap_pkt->sv = 0x0;
- maap_pkt->maap_version_data_length = hton_s(MAAP_VER_DATA_LEN);
- maap_pkt->stream_id = 0x00;
- AGN_ADR(maap_pkt->requested_start_address, 0x00);
- AGN_ADR(maap_pkt->conflict_start_address, 0x00);
- maap_pkt->requested_count = 0x00;
- maap_pkt->conflict_count = 0x00;
-
- get_multicast_mac_adr(dest_mac);
- memcpy(maap_info->src_mac, src_mac_adr, MAC_ADDR_LEN);
-
- memcpy(maap_info->ethpkt.header.h_dest, dest_mac, MAC_ADDR_LEN);
- memcpy(maap_info->ethpkt.header.h_source, src_mac_adr, MAC_ADDR_LEN);
- maap_info->ethpkt.header.eth_type = hton_s(ETH_TYPE);
-
- maap_info->requested_mac_count = hton_s(0x0001);
-}
-
-void prepare_ethpkt(maap_info_t *maap_info, msg_type_t msg_type)
-{
- ethpkt_t *pkt_tx = &maap_info->ethpkt;
- ethpkt_t *pkt_rx = &maap_info->ethpkt_rx;
- maap_pdu_t *maap_pkt = &maap_info->ethpkt.data;
- uint8_t src_mac[6];
- uint8_t dest_mac[6];
- int i;
-
- maap_pkt->message_type = msg_type;
- memcpy(src_mac, maap_info->src_mac, MAC_ADDR_LEN);
- get_multicast_mac_adr(dest_mac);
-
- switch(msg_type)
- {
- case MAAP_PROBE:
- memcpy(maap_pkt->requested_start_address,
- maap_info->requested_mac_add, MAC_ADDR_LEN);
- AGN_ADR(maap_pkt->conflict_start_address, 0x00);
- maap_pkt->requested_count =
- maap_info->requested_mac_count;
- maap_pkt->conflict_count = 0x00;
- memcpy(pkt_tx->header.h_dest, dest_mac, MAC_ADDR_LEN);
- memcpy(pkt_tx->header.h_source, src_mac, MAC_ADDR_LEN);
- break;
-
- case MAAP_DEFEND:
- memcpy(maap_pkt->requested_start_address,
- maap_info->requested_mac_add, MAC_ADDR_LEN);
- memcpy(maap_pkt->conflict_start_address,
- maap_info->conflict_mac_add, MAC_ADDR_LEN);
- maap_pkt->requested_count =
- maap_info->requested_mac_count;
- maap_pkt->conflict_count =
- maap_info->conflict_mac_count;
- /*
- * DEST_MAC set to source mac address received in
- * MAAP_PROBE
- */
- memcpy(pkt_tx->header.h_dest, pkt_rx->header.h_source,
- MAC_ADDR_LEN);
- memcpy(pkt_tx->header.h_source, src_mac, MAC_ADDR_LEN);
- break;
-
- case MAAP_ANNOUNCE:
- memcpy(maap_pkt->requested_start_address,
- maap_info->acquired_mac_add, MAC_ADDR_LEN);
- AGN_ADR(maap_pkt->conflict_start_address, 0x00);
- maap_pkt->requested_count =
- maap_info->acquired_mac_count;
- maap_pkt->conflict_count = 0x00;
- memcpy(pkt_tx->header.h_dest, dest_mac, MAC_ADDR_LEN);
- memcpy(pkt_tx->header.h_source, src_mac, MAC_ADDR_LEN);
- break;
-
- default:
- printf("Error: Message type not set\n");
- break;
- }
-}
-
-/*
- * compare MAC address from received MAAP PDU and receiving station MAC address
- * return TRUE if they are same(different from what given in the protocol which is
- * to return TRUE if MAC address of receiving station is lower than received MAAP PDU)
- */
-int compare_mac(uint8_t rcv_add[6], uint8_t req_addr[6])
-{
- int i, flag = 0;
-
- for (i=0; i<6; i++) {
- if (rcv_add[i] == req_addr[i])
- {
- flag = 1;
- } else {
- flag = 0;
- break;
- }
- }
- return flag;
-}
-
-void *send_announce(void *maap_Info)
-{
- maap_info_t *maap_info;
- maap_info = (maap_info_t *)maap_Info;
-
- ethpkt_t *pkt_tx = &maap_info->ethpkt;
-
- while(1)
- {
- delay(ANNOUNCE_TIMER_S, 0);
- Lock();
- prepare_ethpkt(maap_info, MAAP_ANNOUNCE);
- send_packet(pkt_tx);
- UnLock();
- printf("\nSENT MAAP_ANNOUNCE");
- }
-}
-
-/* Multicast MAAP MAC address */
-void get_multicast_mac_adr(uint8_t *dest_mac)
-{
- dest_mac[0] = 0x91;
- dest_mac[1] = 0xE0;
- dest_mac[2] = 0xF0;
- dest_mac[3] = 0x00;
- dest_mac[4] = 0xFF;
- dest_mac[5] = 0x00;
-}
diff --git a/daemons/maap/common/maap_protocol.h b/daemons/maap/common/maap_protocol.h
deleted file mode 100644
index c75f6646..00000000
--- a/daemons/maap/common/maap_protocol.h
+++ /dev/null
@@ -1,175 +0,0 @@
-/*************************************************************************
- Copyright (c) 2015 VAYAVYA LABS PVT LTD - http://vayavyalabs.com/
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- 1. Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- 3. Neither the name of the Vayavya labs nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
-
-****************************************************************************/
-
-#ifndef __MAAP__PROTOCOL__
-
-#define __MAAP__PROTOCOL__
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <inttypes.h>
-
-#define MAAP_PROBE_RETRANSMITS 3
-#define MAAP_PROBE_INTERVAL_BASE_MS 500
-#define MAAP_PROBE_INTERVAL_VARIATION_MS 100
-#define MAAP_ANNOUNCE_INTERVAL_BASE_S 30
-#define MAAP_ANNOUNCE_INTERVAL_VARIATION_S 2
-
-#define PROBE_TIMER_MS rand_frange(MAAP_PROBE_INTERVAL_BASE_MS,\
- MAAP_PROBE_INTERVAL_BASE_MS + MAAP_PROBE_INTERVAL_VARIATION_MS)
-#define ANNOUNCE_TIMER_S rand_frange(MAAP_ANNOUNCE_INTERVAL_BASE_S,\
- MAAP_ANNOUNCE_INTERVAL_BASE_S + MAAP_ANNOUNCE_INTERVAL_VARIATION_S)
-
-#define MAAP_SUBTYPE 0x7E
-#define MAAP_VER_DATA_LEN (((0x01 & 0x1F) << 11) | (0x010 & 0x7FF))
-#define ETH_TYPE 0x22F0
-#define ETH_PKT_LEN sizeof(ethpkt_t)
-#define MAC_ADDR_LEN 6
-#define BLOCK 0
-#define NON_BLOCK 1
-
-#define AGN_ADR(ADDR, val) for(i=0; i<MAC_ADDR_LEN; i++) {ADDR[i] = val;}
-
-/* states */
-typedef enum maap_state {
- INITIAL = 0,
- PROBE,
- DEFEND,
-} state_t;
-
-/* message types */
-typedef enum msg_type {
- MAAP_PROBE = 1,
- MAAP_DEFEND,
- MAAP_ANNOUNCE
-} msg_type_t;
-
-/* Ethernet header */
-typedef struct ethhedr {
- uint8_t h_dest[6];
- uint8_t h_source[6];
- uint16_t eth_type;
-} ethhedr_t;
-
-/* MAAP PDU */
-typedef struct __attribute__ ((packed)) {
- uint64_t subtype:7;
- uint64_t cd:1;
- uint64_t message_type:4;
- uint64_t version:3;
- uint64_t sv:1;
- uint64_t maap_version_data_length:16;
- uint64_t stream_id;
- uint8_t requested_start_address[6];
- uint16_t requested_count;
- uint8_t conflict_start_address[6];
- uint16_t conflict_count;
-} maap_pdu_t;
-
-/* structure to store packet header and data */
-typedef struct ethpacket {
- ethhedr_t header;
- maap_pdu_t data;
-} ethpkt_t;
-
-/* MAAP Info private data structure */
-typedef struct maap_info {
- ethpkt_t ethpkt;
- ethpkt_t ethpkt_rx;
- state_t state;
- uint8_t src_mac[6];
- uint8_t requested_mac_add[6];
- uint16_t requested_mac_count;
- uint8_t acquired_mac_add[6];
- uint16_t acquired_mac_count;
- uint8_t conflict_mac_add[6];
- uint16_t conflict_mac_count;
-} maap_info_t;
-
-/*
- * Function to initialize the pdu, header info and private data structure
- * maap_info
- */
-void Init(maap_info_t *, uint8_t *);
-
-/* Function to prepare ethernet packet */
-void prepare_ethpkt(maap_info_t *, msg_type_t);
-
-/* State transition */
-int state_transit(maap_info_t *);
-
-/* Get a random value within the range (min, max) */
-int rand_range(int , int);
-double rand_frange(double , double);
-
-/* Generate a random address from the MAAP Dynamic allocation range */
-void generate_address(maap_info_t *);
-
-/* Compare the Mac address and return 1 if address are same else return 0 */
-int compare_mac(uint8_t *, uint8_t *);
-
-/* Send MAAP_ANNOUNCE periodically with a delay of ANNOUNCE_TIMER */
-void *send_announce(void *);
-
-/* Get Multicast MAAP MAC Address */
-void get_multicast_mac_adr(uint8_t *);
-
-/* Create thread and Destroy thread */
-void create_thread(maap_info_t *, void *);
-void destroy_thread();
-
-/* Send and receive of ethernet packet */
-void send_packet(ethpkt_t *);
-int recv_packet(ethpkt_t *, int);
-
-/* Delay based on the timer type passed */
-void delay(int , int );
-
-/* Lock and release */
-void Lock();
-void UnLock();
-uint16_t hton_s(uint16_t );
-
-//#define DEBUG
-#ifdef DEBUG
-#define DBG(x...) fprintf(stderr, x)
-#define DBG_ADDR(ADDR) for(i=0; i<MAC_ADDR_LEN; i++) { fprintf(stderr, "%#x " \
- ,ADDR[i]); }
-#else
-#define DBG(x...) do {} while(0)
-#define DBG_ADDR(ADDR) for(i=0; i<MAC_ADDR_LEN; i++) { fprintf(stderr, "%#x " \
- ,ADDR[i]); }
-//#define DBG_ADDR(ADDR) do {} while(0)
-#endif
-
-#endif
diff --git a/daemons/maap/common/maap_timer.h b/daemons/maap/common/maap_timer.h
new file mode 100644
index 00000000..abe2e9f2
--- /dev/null
+++ b/daemons/maap/common/maap_timer.h
@@ -0,0 +1,146 @@
+/*************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************/
+
+/**
+ * @file
+ *
+ * @brief Support for platform-specific timer operations
+ *
+ * These functions support the platform-specific timers allowing for measuring time elapsed and remaining.
+ */
+
+#ifndef MAAP_TIMER_H
+#define MAAP_TIMER_H
+
+#include <stdint.h>
+
+#include "platform.h"
+
+/** Structure to hold the timer information. @b struct @b maap_timer will be defined in the platform-specific implementation file. */
+typedef struct maap_timer Timer;
+
+/** Time type to use. @p OS_TIME_TYPE is defined in platform.h */
+typedef OS_TIME_TYPE Time;
+
+/**
+ * Create a new #Timer pointer to use when measuring time elapsed and remaining.
+ *
+ * @return A #Timer pointer, or NULL if an error occurred.
+ */
+Timer *Time_newTimer();
+
+/**
+ * Delete a #Timer pointer when done with the timer support.
+ *
+ * @param timer The pointer to free
+ */
+void Time_delTimer(Timer *timer);
+
+
+/**
+ * Set the timer to expire at the specified time.
+ *
+ * @param timer The timer to set
+ * @param t The system time when the timer should expire
+ */
+void Time_setTimer(Timer *timer, const Time *t);
+
+/**
+ * Returns the time remaining on the timer.
+ *
+ * @param timer The timer to test
+ *
+ * @return The number of nanoseconds remaining on the timer, 0 if the timer has expired, or -1 if an error occurred.
+ */
+int64_t Time_remaining(Timer *timer);
+
+
+/**
+ * Adds the second time to the first time.
+ *
+ * @param a Time that the second time is added to. This value is modified.
+ * @param b Time that is added to the first time. This value is not modified.
+ */
+void Time_add(Time *a, const Time *b);
+
+/**
+ * Returns the difference between the two times in nanoseconds.
+ *
+ * @param a Time "a" to compare.
+ * @param b Time "b" to compare.
+ *
+ * @return The "a" time in nanoseconds subtracted from the "b" time in nanoseconds.
+ * If "a" is greater than "b", the returned value will be negative.
+ */
+int64_t Time_diff(const Time *a, const Time *b);
+
+/**
+ * Compare two different time values.
+ *
+ * @param a First time to compare
+ * @param b Second time to compare
+ *
+ * @return -1 if the first time is less than the second time, 1 if the first time is greater than the second time, or 0 if they are equal.
+ */
+int Time_cmp(const Time *a, const Time *b);
+
+/**
+ * Determine if the target time has arrived.
+ *
+ * @param current Current time
+ * @param target Target time
+ *
+ * @return 1 if the current time is at least as great as the target time, 0 otherwise.
+ */
+int Time_passed(const Time *current, const Time *target);
+
+
+/**
+ * Set the Time structure to the number of nanoseconds value.
+ *
+ * @param t Pointer to the Time structure to set
+ * @param nsec Number of nanoseconds to convert into a time
+ */
+void Time_setFromNanos(Time *t, uint64_t nsec);
+
+/**
+ * Set the current time
+ *
+ * @param t Pointer to the Time structure to fill with the current time
+ */
+void Time_setFromMonotonicTimer(Time *t);
+
+/**
+ * Returns the string equivalent of the supplied time for debugging purposes.
+ * The string will remain valid until the next call to Time_dump().
+ * @note This function is not multithread safe.
+ *
+ * @param t Pointer to the time to convert.
+ *
+ * @return A string representing the supplied timer value.
+ */
+const char * Time_dump(const Time *t);
+
+#endif
diff --git a/daemons/maap/common/platform.h b/daemons/maap/common/platform.h
new file mode 100644
index 00000000..5b33385f
--- /dev/null
+++ b/daemons/maap/common/platform.h
@@ -0,0 +1,74 @@
+/*************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************/
+
+#ifndef MAAP_PLATFORM_H
+#define MAAP_PLATFORM_H
+
+#if defined(__linux__)
+
+#include <endian.h>
+#include <time.h>
+
+#define OS_TIME_TYPE struct timespec
+
+#elif defined(__APPLE__)
+
+#include <libkern/OSByteOrder.h>
+#include <sys/time.h>
+
+#define htobe16(x) OSSwapHostToBigInt16(x)
+#define be16toh(x) OSSwapBigToHostInt16(x)
+#define htobe64(x) OSSwapHostToBigInt64(x)
+#define be64toh(x) OSSwapBigToHostInt64(x)
+
+#define ETH_ALEN 6
+
+#define OS_TIME_TYPE struct timeval
+
+#elif defined(_WIN32)
+
+#include <Winsock2.h>
+
+#define htobe16(x) htons(x)
+#define be16toh(x) ntohs(x)
+#define htobe64(x) ((htonl(1) == 1) ? x : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
+#define be64toh(x) ((ntohl(1) == 1) ? x : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))
+
+#define OS_TIME_TYPE struct timeval
+
+#else
+
+#error Please create the platform support definitions for this platform
+
+#endif
+
+
+#define HTOBE16(x) htobe16(x)
+#define BE16TOH(x) be16toh(x)
+#define HTOBE64(x) htobe64(x)
+#define BE64TOH(x) be64toh(x)
+
+
+#endif
diff --git a/daemons/maap/doc/CMakeLists.txt b/daemons/maap/doc/CMakeLists.txt
new file mode 100644
index 00000000..c6fc3dcc
--- /dev/null
+++ b/daemons/maap/doc/CMakeLists.txt
@@ -0,0 +1,24 @@
+cmake_minimum_required(VERSION 2.8)
+
+# add a target to generate API documentation with Doxygen
+find_package(Doxygen)
+option(BUILD_DOCUMENTATION "Create and install the HTML based API documentation (requires Doxygen)" ${DOXYGEN_FOUND})
+
+if(BUILD_DOCUMENTATION)
+ if(NOT DOXYGEN_FOUND)
+ message(FATAL_ERROR "Doxygen is needed to build the documentation.")
+ endif()
+
+ set(doxyfile_in ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in)
+ set(doxyfile ${CMAKE_CURRENT_SOURCE_DIR}/build/Doxyfile)
+
+ configure_file(${doxyfile_in} ${doxyfile} @ONLY)
+
+ add_custom_target(doc
+ COMMAND ${DOXYGEN_EXECUTABLE} ${doxyfile}
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ COMMENT "Generating API documentation with Doxygen"
+ VERBATIM)
+
+ #install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION share/doc)
+endif()
diff --git a/daemons/maap/doc/Doxyfile.in b/daemons/maap/doc/Doxyfile.in
new file mode 100644
index 00000000..324fdc6c
--- /dev/null
+++ b/daemons/maap/doc/Doxyfile.in
@@ -0,0 +1,2431 @@
+# Doxyfile 1.8.11
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = "MAAP Documentation"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = ../doc/build
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = YES
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = NO
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = ../common \
+ ../linux/src \
+ ../test \
+ ../doc/mainpage.dox
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl,
+# *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js.
+
+FILE_PATTERNS = *.h \
+ *.hpp
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse-libclang=ON option for CMake.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = YES
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = NO
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
+
+HAVE_DOT = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = YES
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
+# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
+# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = YES
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/daemons/maap/doc/mainpage.dox b/daemons/maap/doc/mainpage.dox
new file mode 100644
index 00000000..dc073157
--- /dev/null
+++ b/daemons/maap/doc/mainpage.dox
@@ -0,0 +1,24 @@
+/**
+ * \mainpage MAAP Documentation
+ *
+ * Introduction
+ * ------------
+ * This is a MAAP implementation. Details will be provided soon.
+ *
+ * Linux Specific
+ * -------------
+ *
+ * Requirements for documentation on a ubuntu based system:
+ * - cmake: sudo apt-get install cmake
+ * - doxygen: sudo apt-get install doxygen
+ *
+ * To build, execute the linux/build makefile.
+ *
+ * To execute, run ./maap_daemon
+ *
+ * Windows Version
+ * ---------------
+ *
+ * Windows is not supported.
+*/
+
diff --git a/daemons/maap/linux/Makefile b/daemons/maap/linux/Makefile
deleted file mode 100644
index 520939cb..00000000
--- a/daemons/maap/linux/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-BUILD_DIR=.
-COMMON_DIR=../common
-INCFLAGS=$(COMMON_DIR)/maap_protocol.c
-CFLAGS=$(OPT) -Wall
-EXTRA_FLAGS=-I$(COMMON_DIR)
-FLAGS=-lpthread -lpcap
-CC?=gcc
-
-all: maap_daemon
-
-maap_daemon: maap_linux.c
- $(CC) -o $(BUILD_DIR)/maap_daemon $(INCFLAGS) maap_linux.c $(CFLAGS) $(FLAGS) $(EXTRA_FLAGS)
-
-clean:
- rm -rf $(BUILD_DIR)/maap_daemon
diff --git a/daemons/maap/linux/build/Makefile b/daemons/maap/linux/build/Makefile
new file mode 100644
index 00000000..f066defc
--- /dev/null
+++ b/daemons/maap/linux/build/Makefile
@@ -0,0 +1,47 @@
+COMMON_DIR=../../common
+LINUX_DIR=../src
+TEST_DIR=../../test
+
+OPT?=-O2
+CFLAGS=$(OPT) -Wall
+CPPFLAGS=-I$(COMMON_DIR)
+CC?=gcc
+
+VPATH=$(LINUX_DIR) $(COMMON_DIR) $(TEST_DIR)
+
+BINARIES=maap_daemon maap_test test_intervals
+
+.PHONY: all clean
+
+all: $(BINARIES)
+
+# Header dependencies
+
+intervals.o: intervals.h
+
+maap.o: maap.h intervals.h maap_iface.h maap_timer.h maap_net.h platform.h maap_packet.h maap_log.h
+maap_net.o: maap_net.h maap_log.h
+maap_packet.o: maap.h intervals.h maap_iface.h maap_timer.h maap_net.h platform.h maap_packet.h maap_log.h
+maap_parse.o: maap.h intervals.h maap_iface.h maap_timer.h maap_net.h platform.h maap_parse.h maap_log.h
+maap_log_queue.o: maap_log_queue.h maap_log.h
+
+maap_daemon.o: maap.h intervals.h maap_iface.h maap_timer.h maap_net.h platform.h maap_parse.h maap_packet.h
+maap_log_linux.o: maap_log_queue.h maap_helper_linux.h platform.h
+maap_timer_linux.o: maap_timer.h platform.h
+
+test_intervals.o: intervals.h
+
+# Binary targets
+
+maap_daemon: LDLIBS = -lrt -lpthread
+maap_daemon: maap_log_linux.o maap_timer_linux.o intervals.o maap.o maap_net.o maap_packet.o maap_parse.o maap_log_queue.o
+
+maap_test: LDLIBS = -lpcap
+
+test_intervals: intervals.o
+
+# Utility targets
+
+clean:
+ rm -f *.o
+ rm -f $(BINARIES)
diff --git a/daemons/maap/linux/maap_linux.c b/daemons/maap/linux/maap_linux.c
deleted file mode 100644
index a0e19969..00000000
--- a/daemons/maap/linux/maap_linux.c
+++ /dev/null
@@ -1,279 +0,0 @@
-/*************************************************************************
- Copyright (c) 2015 VAYAVYA LABS PVT LTD - http://vayavyalabs.com/
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- 1. Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- 3. Neither the name of the Vayavya labs nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
-
-****************************************************************************/
-
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/ipc.h>
-#include <sys/shm.h>
-
-#include <linux/if_ether.h>
-#include <linux/if_packet.h>
-#include <linux/if.h>
-
-#include <netinet/in.h>
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <pthread.h>
-#include <inttypes.h>
-#include <unistd.h>
-
-#include "maap_protocol.h"
-
-uint8_t *maap_shm_mem;
-struct sockaddr_ll saddrll;
-pthread_t thread;
-pthread_mutex_t lock;
-int socketfd;
-
-#define VERSION_STR "0.0"
-
-static const char *version_str =
- "maap_daemon v" VERSION_STR "\n" "Copyright (c) 2014, VAYAVYA LABS PVT LTD\n";
-
-void usage(void)
-{
- fprintf(stderr,
- "\n"
- "usage: maap_daemon [-d] -i interface-name"
- "\n"
- "options:\n"
- " -d run daemon in the background\n"
- " -i specify interface to monitor\n"
- "\n" "%s" "\n", version_str);
- exit(1);
-}
-
-int main(int argc, char *argv[])
-{
- char *iface = NULL;
- struct ifreq buffer;
- int ifindex;
- struct packet_mreq mreq;
- maap_info_t *maap_Info;
- uint32_t seed;
- uint8_t dest_mac[6];
- uint8_t src_mac[6];
- int daemonize = 0;
- int shmid;
- key_t key;
- int ret;
- int c;
-
- for (;;) {
- c = getopt(argc, argv, "hdi:");
-
- if (c < 0)
- break;
-
- switch (c) {
- case 'd':
- daemonize = 1;
- break;
- case 'i':
- if (iface) {
- printf
- ("only one interface per daemon is supported\n");
- usage();
- }
- iface = strdup(optarg);
- break;
- case 'h':
- default:
- usage();
- break;
- }
- }
- if (optind < argc)
- usage();
-
- if (iface == NULL)
- usage();
-
- if (daemonize) {
- ret = daemon(1, 0);
- if (ret) {
- printf("Error: Failed to daemonize\n");
- return -1;
- }
- }
-
- if ((socketfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_TYPE))) < 0 )
- {
- printf("Error: could not open socket %d\n",socketfd);
- return -1;
- }
-
- memset(&buffer, 0x00, sizeof(buffer));
- strncpy(buffer.ifr_name, (char *)iface, IFNAMSIZ);
- if (ioctl(socketfd, SIOCGIFINDEX, &buffer) < 0)
- {
- printf("Error: could not get interface index\n");
- close(socketfd);
- return -1;
- }
-
- key = 1234;
- if ((shmid = shmget(key, MAC_ADDR_LEN, IPC_CREAT | 0666)) < 0) {
- printf("Error : Failed to allocate the Shared Memory\n");
- close(socketfd);
- return -1;
- }
-
- if ((maap_shm_mem = shmat(shmid, NULL, 0)) == (uint8_t *) -1) {
- printf("Error : Failed to attach the created segment id by function \
- shmget()");
- close(socketfd);
- return -1;
- }
-
- ifindex = buffer.ifr_ifindex;
- if (ioctl(socketfd, SIOCGIFHWADDR, &buffer) < 0) {
- printf("Error: could not get interface address\n");
- close(socketfd);
- return -1;
- }
- memcpy(src_mac, buffer.ifr_hwaddr.sa_data, MAC_ADDR_LEN);
-
- get_multicast_mac_adr(dest_mac);
-
- memset((void*)&saddrll, 0, sizeof(saddrll));
- saddrll.sll_family = AF_PACKET;
- saddrll.sll_ifindex = ifindex;
- saddrll.sll_halen = MAC_ADDR_LEN;
- memcpy((void*)(saddrll.sll_addr), (void*)dest_mac, MAC_ADDR_LEN);
-
- if (bind(socketfd, (struct sockaddr*)&saddrll, sizeof(saddrll))) {
- printf("Error: could not bind datagram socket\n");
- return -1;
- }
-
- /* filter multicast address */
- memset(&mreq, 0, sizeof(mreq));
- mreq.mr_ifindex = ifindex;
- mreq.mr_type = PACKET_MR_MULTICAST;
- mreq.mr_alen = 6;
- memcpy(mreq.mr_address, dest_mac, mreq.mr_alen);
-
- if (setsockopt(socketfd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq,
- sizeof(mreq)) < 0) {
- printf("setsockopt PACKET_ADD_MEMBERSHIP failed\n");
- return -1;
- }
-
- pthread_mutex_init(&(lock), NULL);
- seed = src_mac[6] + time(NULL);
- srand(seed);
-
- maap_Info = (maap_info_t *)calloc(1,sizeof(maap_info_t));
-
- /* Initialize packet header and data */
- Init(maap_Info, src_mac);
-
- while (1) {
- state_transit(maap_Info);
- }
-
- close(socketfd);
-
- free(maap_Info);
-
- return 0;
-}
-
-void delay(int seconds, int millisecond)
-{
- sleep(seconds);
- usleep(millisecond * 1000);
-}
-
-void create_thread(maap_info_t *maap_info, void *announce)
-{
- pthread_create(&thread, NULL, announce, (void *)(maap_info));
-}
-
-void destroy_thread()
-{
- pthread_cancel(thread);
-}
-
-double rand_frange(double min_n, double max_n)
-{
- return (double)rand()/RAND_MAX * (max_n - min_n) + min_n;
-}
-
-int rand_range(int min_n, int max_n)
-{
- return rand() % (max_n - min_n + 1) + min_n;
-}
-
-void send_packet(ethpkt_t *pkt_tx)
-{
- int result;
- if ((result = (sendto(socketfd, pkt_tx, ETH_PKT_LEN, 0,
- (struct sockaddr*)&saddrll, sizeof(saddrll)) > 0)))
- DBG("send successful %d\n", result);
- else
- DBG("Error: sending of packet failed\n");
-}
-
-int recv_packet(ethpkt_t *pkt_rx, int flag)
-{
- int result;
- socklen_t fmlen = sizeof(saddrll);
-
- if (flag == NON_BLOCK)
- flag = MSG_DONTWAIT;
-
- result = recvfrom(socketfd, pkt_rx, ETH_PKT_LEN, flag,
- (struct sockaddr*)&saddrll, &fmlen);
- return result;
-}
-
-void Lock()
-{
- pthread_mutex_lock(&lock);
-}
-
-void UnLock()
-{
- pthread_mutex_unlock(&lock);
-}
-
-uint16_t hton_s(uint16_t val)
-{
- return htons(val);
-}
diff --git a/daemons/maap/linux/src/maap_daemon.c b/daemons/maap/linux/src/maap_daemon.c
new file mode 100644
index 00000000..8943ee73
--- /dev/null
+++ b/daemons/maap/linux/src/maap_daemon.c
@@ -0,0 +1,1020 @@
+/*************************************************************************
+ Copyright (c) 2015 VAYAVYA LABS PVT LTD - http://vayavyalabs.com/
+ Copyright (c) 2016-2017 Harman International Industries, Incorporated
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the Vayavya labs nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+****************************************************************************/
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <signal.h>
+#include <netdb.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+
+#include <linux/if_ether.h>
+#include <linux/if_packet.h>
+#include <linux/if.h>
+
+#include <netinet/in.h>
+
+#include <arpa/inet.h>
+
+#include "maap.h"
+#include "maap_packet.h"
+#include "maap_parse.h"
+
+#define MAAP_LOG_COMPONENT "Init"
+#include "maap_log.h"
+
+#define MAX_CLIENT_CONNECTIONS 32
+#define DEFAULT_PORT "15364"
+
+#define VERSION_STR "0.1"
+
+static int init_maap_networking(const char *iface, uint8_t src_mac[ETH_ALEN], uint8_t dest_mac[ETH_ALEN]);
+static int get_listener_socket(const char *listenport);
+static int act_as_client(const char *listenport);
+static int act_as_server(const char *listenport, char *iface, int daemonize);
+static int do_daemonize(void);
+
+static void log_print_notify_result(void *callback_data, int logLevel, const char *notifyText);
+static void display_print_notify_result(void *callback_data, int logLevel, const char *notifyText);
+static void send_print_notify_result(void *callback_data, int logLevel, const char *notifyText);
+
+
+static const char *version_str =
+ "maap_daemon v" VERSION_STR "\n"
+ "Copyright (c) 2014-2015, VAYAVYA LABS PVT LTD\n"
+ "Copyright (c) 2016-2017, Harman International Industries, Inc.\n";
+
+static void usage(void)
+{
+ fprintf(stderr,
+ "\n" "%s"
+ "\n"
+ "usage: maap_daemon [ -c | -i interface-name [-d log_file] ] [-p port_num]"
+ "\n"
+ "options:\n"
+ "\t-c Run as a client (sends commands to the daemon)\n"
+ "\t-i Run as a server monitoring the specified interface\n"
+ "\t-d Daemonize the server and log to log_file\n"
+ "\t-p Specify the control port to connect to (client) or\n"
+ "\t listen to (server). The default port is " DEFAULT_PORT ".\n"
+ "\n",
+ version_str);
+ exit(1);
+}
+
+/* get sockaddr, IPv4 or IPv6 */
+static void *get_in_addr(struct sockaddr *sa)
+{
+ if (sa->sa_family == AF_INET) {
+ return &(((struct sockaddr_in*)sa)->sin_addr);
+ }
+
+ return &(((struct sockaddr_in6*)sa)->sin6_addr);
+}
+
+
+int main(int argc, char *argv[])
+{
+ int c;
+ int as_client = 0, daemonize = 0;
+ char *iface = NULL;
+ char *listenport = NULL;
+ char *logfile = NULL;
+ int ret;
+
+
+ /*
+ * Parse the arguments
+ */
+
+ while ((c = getopt(argc, argv, "hcd:i:p:")) >= 0)
+ {
+ switch (c)
+ {
+ case 'c':
+ as_client = 1;
+ break;
+
+ case 'd':
+ if (daemonize)
+ {
+ fprintf(stderr, "Only one log file per server is supported\n");
+ free(logfile);
+ usage();
+ }
+ daemonize = 1;
+ logfile = strdup(optarg);
+ break;
+
+ case 'i':
+ if (iface)
+ {
+ fprintf(stderr, "Only one interface per server is supported\n");
+ free(iface);
+ usage();
+ }
+ iface = strdup(optarg);
+ break;
+
+ case 'p':
+ if (listenport)
+ {
+ fprintf(stderr, "Only one port per server is supported\n");
+ free(listenport);
+ usage();
+ }
+ listenport = strdup(optarg);
+ break;
+
+ case 'h':
+ default:
+ usage();
+ break;
+ }
+ }
+ if (optind < argc)
+ {
+ usage();
+ }
+
+ if (as_client && daemonize)
+ {
+ fprintf(stderr, "Cannot run as both a client and a daemon\n");
+ usage();
+ }
+
+ if (!as_client && iface == NULL)
+ {
+ fprintf(stderr, "A network interface is required as a daemon\n");
+ usage();
+ }
+ if (as_client && iface != NULL)
+ {
+ fprintf(stderr, "A network interface is not supported as a client\n");
+ usage();
+ }
+
+ if (daemonize) {
+ ret = do_daemonize();
+ if (ret) {
+ fprintf(stderr, "Error: Failed to daemonize\n");
+ return -1;
+ }
+ open("/dev/null", O_RDONLY);
+ open("/dev/null", O_WRONLY);
+ open(logfile, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+ }
+
+ if (listenport == NULL)
+ {
+ /* Use the default port. */
+ listenport = strdup(DEFAULT_PORT);
+ }
+
+ /*
+ * Initialize the logging support.
+ */
+
+ maapLogInit();
+
+
+ if (as_client)
+ {
+ /* Run as a client instead of a server. */
+ ret = act_as_client(listenport);
+ }
+ else
+ {
+ ret = act_as_server(listenport, iface, daemonize);
+ }
+
+ maapLogExit();
+
+ free(listenport);
+ return ret;
+}
+
+/* Local function to server side of network command & control. */
+static int act_as_server(const char *listenport, char *iface, int daemonize)
+{
+ Maap_Client mc;
+
+ int socketfd;
+ uint8_t dest_mac[ETH_ALEN] = MAAP_DEST_MAC;
+ uint8_t src_mac[ETH_ALEN];
+
+ int listener;
+
+ int clientfd[MAX_CLIENT_CONNECTIONS];
+ int client_wants_text[MAX_CLIENT_CONNECTIONS];
+ int i, nextclientindex;
+
+ fd_set master, read_fds;
+ int fdmax;
+
+ void *packet_data;
+ int64_t waittime;
+ struct timeval tv;
+ char recvbuffer[1600];
+ int recvbytes;
+ Maap_Cmd recvcmd;
+ Maap_Notify recvnotify;
+ uintptr_t notifysocket;
+ int exit_received = 0;
+
+ int ret;
+
+ /*
+ * Initialize the networking support.
+ */
+
+ socketfd = init_maap_networking(iface, src_mac, dest_mac);
+ if (socketfd == -1) {
+ maapLogExit();
+ return -1;
+ }
+
+ free(iface);
+ iface = NULL;
+
+ FD_ZERO(&read_fds);
+ FD_ZERO(&master);
+ if (!daemonize) {
+ FD_SET(STDIN_FILENO, &master);
+ }
+ FD_SET(socketfd, &master);
+ fdmax = socketfd;
+
+
+ /*
+ * Initialize the client connection listen socket.
+ */
+
+ listener = get_listener_socket(listenport);
+ if (listener == -1) {
+ close(socketfd);
+ maapLogExit();
+ return -1;
+ }
+
+ /* Add the listener to the master set */
+ FD_SET(listener, &master);
+
+ /* Keep track of the biggest file descriptor */
+ if (listener > fdmax) {
+ fdmax = listener;
+ }
+
+ for (i = 0; i < MAX_CLIENT_CONNECTIONS; ++i) {
+ clientfd[i] = -1;
+ client_wants_text[i] = 0;
+ }
+ nextclientindex = 0;
+
+
+ /*
+ * Initialize the Maap_Client data structure.
+ */
+
+ memset(&mc, 0, sizeof(mc));
+ mc.dest_mac = convert_mac_address(dest_mac);
+ mc.src_mac = convert_mac_address(src_mac);
+
+
+ /*
+ * Seed the random number generator.
+ * This seeding is defined in IEEE 1722-2016 B.3.6.1.
+ */
+
+ srand((unsigned int)mc.src_mac + (unsigned int)time(NULL));
+
+
+ /*
+ * Main event loop
+ */
+
+ MAAP_LOG_STATUS("Server started");
+ if (!daemonize) {
+ puts("Enter \"help\" for a list of valid commands.");
+ }
+
+ while (!exit_received)
+ {
+ /* Send any queued packets. */
+ while (mc.net != NULL && (packet_data = Net_getNextQueuedPacket(mc.net)) != NULL)
+ {
+ if (send(socketfd, packet_data, MAAP_NET_BUFFER_SIZE, 0) < 0)
+ {
+ /* Something went wrong. Abort! */
+ MAAP_LOGF_ERROR("Error %d writing to network socket (%s)", errno, strerror(errno));
+ Net_freeQueuedPacket(mc.net, packet_data);
+ break;
+ }
+ Net_freeQueuedPacket(mc.net, packet_data);
+ }
+
+ /* Process any notifications. */
+ while (get_notify(&mc, (void *)&notifysocket, &recvnotify) > 0)
+ {
+ if ((int) notifysocket == -1) {
+ /* Just display the information for the user. */
+ print_notify(&recvnotify, display_print_notify_result, NULL);
+ } else {
+ /* Log the result. */
+ print_notify(&recvnotify, log_print_notify_result, NULL);
+
+ /* Send the notification information to the client. */
+ for (i = 0; i < MAX_CLIENT_CONNECTIONS; ++i)
+ {
+ if (clientfd[i] == (int) notifysocket)
+ {
+ if (client_wants_text[i]) {
+ // Send the friendly text notification to the socket.
+ print_notify(&recvnotify, send_print_notify_result, (void *) &(clientfd[i]));
+ } else {
+ // Send the raw notification to the socket.
+ if (send((int) notifysocket, &recvnotify, sizeof(recvnotify), 0) < 0)
+ {
+ /* Something went wrong. Assume the socket will be closed below. */
+ MAAP_LOGF_ERROR("Error %d writing to client socket %d (%s)", errno, (int) notifysocket, strerror(errno));
+ }
+ }
+ break;
+ }
+ }
+ if (i >= MAX_CLIENT_CONNECTIONS)
+ {
+ MAAP_LOGF_WARNING("Notification for client socket %d, but that socket no longer exists", (int) notifysocket);
+ }
+ }
+ }
+
+ /* Determine how long to wait. */
+ waittime = maap_get_delay_to_next_timer(&mc);
+ if (waittime > 0)
+ {
+ tv.tv_sec = waittime / 1000000000;
+ tv.tv_usec = (waittime % 1000000000) / 1000;
+ }
+ else
+ {
+ /* Act immediately. */
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ }
+
+ /* Wait for something to happen. */
+ read_fds = master;
+ ret = select(fdmax+1, &read_fds, NULL, NULL, &tv);
+ if (ret < 0)
+ {
+ MAAP_LOGF_ERROR("select() error %d (%s)", errno, strerror(errno));
+ break;
+ }
+ if (ret == 0)
+ {
+ /* The timer timed out. Handle the timer. */
+ maap_handle_timer(&mc);
+ continue;
+ }
+
+ /* Handle any packets received. */
+ if (FD_ISSET(socketfd, &read_fds))
+ {
+ struct sockaddr_ll ll_addr = {0};
+ socklen_t addr_len = 0;
+
+ while ((recvbytes = recvfrom(socketfd, recvbuffer, sizeof(recvbuffer), MSG_DONTWAIT, (struct sockaddr*)&ll_addr, &addr_len)) > 0)
+ {
+ maap_handle_packet(&mc, (uint8_t *)recvbuffer, recvbytes);
+ }
+ if (recvbytes < 0 && errno != EWOULDBLOCK)
+ {
+ /* Something went wrong. Abort! */
+ MAAP_LOGF_ERROR("Error %d reading from network socket (%s)", errno, strerror(errno));
+ break;
+ }
+ }
+
+ /* Accept any new connections. */
+ if (FD_ISSET(listener, &read_fds)) {
+ int newfd;
+ socklen_t addrlen;
+ struct sockaddr_storage remoteaddr;
+ char remoteIP[INET6_ADDRSTRLEN];
+
+ addrlen = sizeof remoteaddr;
+ newfd = accept(listener,
+ (struct sockaddr *)&remoteaddr,
+ &addrlen);
+
+ if (newfd == -1) {
+ MAAP_LOGF_ERROR("Error %d accepting connection (%s)", errno, strerror(errno));
+ } else {
+ MAAP_LOGF_INFO("New connection from %s on socket %d",
+ inet_ntop(remoteaddr.ss_family,
+ get_in_addr((struct sockaddr*)&remoteaddr),
+ remoteIP, INET6_ADDRSTRLEN),
+ newfd);
+
+ /* Add the socket to our array of connected sockets. */
+ if (clientfd[nextclientindex] != -1)
+ {
+ /* Find the next available index. */
+ for (i = (nextclientindex + 1) % MAX_CLIENT_CONNECTIONS; i != nextclientindex; i = (i + 1) % MAX_CLIENT_CONNECTIONS)
+ {
+ if (clientfd[nextclientindex] == -1)
+ {
+ /* Found an empty array slot. */
+ break;
+ }
+ }
+ if (i == nextclientindex)
+ {
+ /* No more client slots available. Connection rejected. */
+ MAAP_LOG_ERROR("Out of client connection slots. Connection rejected.");
+ close(newfd);
+ newfd = -1;
+ }
+ }
+
+ if (newfd != -1)
+ {
+ clientfd[nextclientindex] = newfd;
+ nextclientindex = (nextclientindex + 1) % MAX_CLIENT_CONNECTIONS; /* Next slot used for the next try. */
+ FD_SET(newfd, &master); /* add to master set */
+ if (newfd > fdmax) { /* keep track of the max */
+ fdmax = newfd;
+ }
+ }
+ }
+ }
+
+ /* Handle any commands received via stdin. */
+ if (!daemonize && FD_ISSET(STDIN_FILENO, &read_fds))
+ {
+ recvbytes = read(STDIN_FILENO, recvbuffer, sizeof(recvbuffer) - 1);
+ if (recvbytes <= 0)
+ {
+ MAAP_LOGF_ERROR("Error %d reading from stdin (%s)", errno, strerror(errno));
+ }
+ else
+ {
+ recvbuffer[recvbytes] = '\0';
+
+ /* Process the command data (may be binary or text). */
+ memset(&recvcmd, 0, sizeof(recvcmd));
+ int result = parse_write(&mc, (const void *)(uintptr_t) -1, recvbuffer, NULL);
+ if (result > 0)
+ {
+ /* Received a command to exit. */
+ exit_received = 1;
+ }
+ else if (result < 0)
+ {
+ /* Invalid command. Tell the user what valid commands are. */
+ if (strncmp(recvbuffer, "help", 4) != 0) {
+ puts("Invalid command type");
+ }
+ parse_usage(display_print_notify_result, NULL);
+ }
+ }
+ }
+
+ /* Run through the existing connections looking for data to read. */
+ for (i = 0; i < MAX_CLIENT_CONNECTIONS; ++i)
+ {
+ if (clientfd[i] != -1 && FD_ISSET(clientfd[i], &read_fds))
+ {
+ recvbytes = recv(clientfd[i], recvbuffer, sizeof(recvbuffer), 0);
+ if (recvbytes < 0)
+ {
+ MAAP_LOGF_WARNING("Error %d reading from socket %d (%s). Connection closed.", errno, clientfd[i], strerror(errno));
+ close(clientfd[i]);
+ FD_CLR(clientfd[i], &master); /* remove from master set */
+ clientfd[i] = -1;
+ nextclientindex = i; /* We know this slot will be empty. */
+ }
+ else if (recvbytes == 0)
+ {
+ MAAP_LOGF_INFO("Socket %d closed", clientfd[i]);
+ close(clientfd[i]);
+ FD_CLR(clientfd[i], &master); /* remove from master set */
+ clientfd[i] = -1;
+ nextclientindex = i; /* We know this slot will be empty. */
+ }
+ else
+ {
+ recvbuffer[recvbytes] = '\0';
+
+ /* Process the command data (may be binary or text). */
+ memset(&recvcmd, 0, sizeof(recvcmd));
+ int result = parse_write(&mc, (const void *)(uintptr_t) clientfd[i], recvbuffer, &(client_wants_text[i]));
+ if (result > 0)
+ {
+ /* Received a command to exit. */
+ exit_received = 1;
+ }
+ else if (result < 0)
+ {
+ /* Invalid command. Tell the user what valid commands are. */
+ if (strncmp(recvbuffer, "help", 4) != 0) {
+ send_print_notify_result((void *) &(clientfd[i]), MAAP_LOG_LEVEL_INFO, "Invalid command type");
+ }
+ parse_usage(send_print_notify_result, (void *) &(clientfd[i]));
+ }
+ }
+ }
+ }
+
+ }
+
+ close(socketfd);
+ close(listener);
+
+ /* Close any connected sockets. */
+ for (i = 0; i < MAX_CLIENT_CONNECTIONS; ++i) {
+ if (clientfd[i] != -1) {
+ close(clientfd[i]);
+ clientfd[i] = -1;
+ }
+ }
+
+ maap_deinit_client(&mc);
+
+ MAAP_LOG_STATUS("Server stopped");
+
+ maapLogExit();
+
+ return (exit_received ? 0 : -1);
+}
+
+/* Initializes the MAAP raw socket support, and returns a socket handle for that socket. */
+static int init_maap_networking(const char *iface, uint8_t src_mac[ETH_ALEN], uint8_t dest_mac[ETH_ALEN])
+{
+ int socketfd;
+ struct ifreq ifbuffer;
+ int ifindex;
+ struct sockaddr_ll sockaddr;
+ struct packet_mreq mreq;
+
+ if ((socketfd = socket(PF_PACKET, SOCK_RAW, htons(MAAP_TYPE))) == -1 )
+ {
+ MAAP_LOGF_ERROR("Could not open socket %d (Are you running as an administrator?)",socketfd);
+ return -1;
+ }
+
+ if (fcntl(socketfd, F_SETFL, O_NONBLOCK) < 0)
+ {
+ MAAP_LOG_ERROR("Could not set the socket to non-blocking");
+ close(socketfd);
+ return -1;
+ }
+
+ memset(&ifbuffer, 0x00, sizeof(ifbuffer));
+ strncpy(ifbuffer.ifr_name, iface, IFNAMSIZ);
+ if (ioctl(socketfd, SIOCGIFINDEX, &ifbuffer) < 0)
+ {
+ MAAP_LOG_ERROR("Could not get interface index");
+ close(socketfd);
+ return -1;
+ }
+
+ ifindex = ifbuffer.ifr_ifindex;
+ if (ioctl(socketfd, SIOCGIFHWADDR, &ifbuffer) < 0) {
+ MAAP_LOG_ERROR("Could not get interface address");
+ close(socketfd);
+ return -1;
+ }
+
+ memcpy(src_mac, ifbuffer.ifr_hwaddr.sa_data, ETH_ALEN);
+
+ memset(&sockaddr, 0, sizeof(sockaddr));
+ sockaddr.sll_family = AF_PACKET;
+ sockaddr.sll_ifindex = ifindex;
+ sockaddr.sll_halen = ETH_ALEN;
+ memcpy(sockaddr.sll_addr, dest_mac, ETH_ALEN);
+
+ if (bind(socketfd, (struct sockaddr*)&sockaddr, sizeof(sockaddr))) {
+ MAAP_LOG_ERROR("Could not bind datagram socket");
+ close(socketfd);
+ return -1;
+ }
+
+ /* filter multicast address */
+ memset(&mreq, 0, sizeof(mreq));
+ mreq.mr_ifindex = ifindex;
+ mreq.mr_type = PACKET_MR_MULTICAST;
+ mreq.mr_alen = 6;
+ memcpy(mreq.mr_address, dest_mac, mreq.mr_alen);
+
+ if (setsockopt(socketfd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq,
+ sizeof(mreq)) < 0) {
+ MAAP_LOG_ERROR("setsockopt PACKET_ADD_MEMBERSHIP failed");
+ close(socketfd);
+ return -1;
+ }
+
+ return socketfd;
+}
+
+/* Initializes the listener socket, and returns a socket handle for that socket. */
+static int get_listener_socket(const char *listenport)
+{
+ int listener = -1;
+ struct addrinfo hints, *ai, *p;
+ int yes=1;
+ int ret;
+
+ /* Get us a localhost socket and bind it */
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE;
+ if ((ret = getaddrinfo(NULL, listenport, &hints, &ai)) != 0) {
+ MAAP_LOGF_ERROR("getaddrinfo failure %s", gai_strerror(ret));
+ return -1;
+ }
+
+ for(p = ai; p != NULL; p = p->ai_next) {
+ listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
+ if (listener == -1) {
+ continue;
+ }
+
+ /* Lose the pesky "address already in use" error message */
+ setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
+
+ if (bind(listener, p->ai_addr, p->ai_addrlen) < 0) {
+ close(listener);
+ continue;
+ }
+
+ break;
+ }
+
+ freeaddrinfo(ai);
+
+ /* If we got here, it means we didn't get bound */
+ if (p == NULL) {
+ MAAP_LOGF_ERROR("Socket failed to bind error %d (%s)", errno, strerror(errno));
+ if (listener != -1) {
+ close(listener);
+ }
+ return -1;
+ }
+
+ if (listen(listener, 10) < 0) {
+ MAAP_LOGF_ERROR("Socket listen error %d (%s)", errno, strerror(errno));
+ close(listener);
+ return -1;
+ }
+
+ return listener;
+}
+
+/* Local function to handle client side of network command & control. */
+static int act_as_client(const char *listenport)
+{
+ int socketfd;
+ struct addrinfo hints, *ai, *p;
+ int ret;
+
+ fd_set master, read_fds;
+ int fdmax;
+
+ char recvbuffer[200];
+ int recvbytes;
+ Maap_Cmd recvcmd;
+ int exit_received = 0;
+
+ /* Create a localhost socket. */
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = 0;
+ if ((ret = getaddrinfo("localhost", listenport, &hints, &ai)) != 0) {
+ MAAP_LOGF_ERROR("getaddrinfo failure %s", gai_strerror(ret));
+ maapLogExit();
+ return -1;
+ }
+
+ for(p = ai; p != NULL; p = p->ai_next) {
+ socketfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
+ if (socketfd == -1) {
+ continue;
+ }
+ ret = connect(socketfd, p->ai_addr, p->ai_addrlen);
+ if (ret == -1) {
+ close(socketfd);
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ if (p == NULL) {
+ MAAP_LOGF_ERROR("Unable to connect to the daemon, error %d (%s)", errno, strerror(errno));
+ freeaddrinfo(ai);
+ maapLogExit();
+ return -1;
+ }
+
+ freeaddrinfo(ai);
+
+ if (fcntl(socketfd, F_SETFL, O_NONBLOCK) < 0)
+ {
+ MAAP_LOG_ERROR("Could not set the socket to non-blocking");
+ close(socketfd);
+ maapLogExit();
+ return -1;
+ }
+
+ FD_ZERO(&read_fds);
+ FD_ZERO(&master);
+ FD_SET(STDIN_FILENO, &master);
+ FD_SET(socketfd, &master);
+ fdmax = socketfd;
+
+
+ /*
+ * Main event loop
+ */
+
+ puts("Client started");
+ puts("Enter \"help\" for a list of valid commands.");
+
+ while (!exit_received)
+ {
+ /* Wait for something to happen. */
+ read_fds = master;
+ ret = select(fdmax+1, &read_fds, NULL, NULL, NULL);
+ if (ret <= 0)
+ {
+ MAAP_LOGF_ERROR("select() error %d (%s)", errno, strerror(errno));
+ break;
+ }
+
+ /* Handle any responses received. */
+ if (FD_ISSET(socketfd, &read_fds))
+ {
+ while ((recvbytes = recv(socketfd, recvbuffer, sizeof(Maap_Notify), 0)) > 0)
+ {
+ recvbuffer[recvbytes] = '\0';
+
+ /* Process the response data (will be binary). */
+ if (recvbytes == sizeof(Maap_Notify))
+ {
+ print_notify((Maap_Notify *) recvbuffer, display_print_notify_result, NULL);
+ }
+ else
+ {
+ MAAP_LOGF_WARNING("Received unexpected response of size %d", recvbytes);
+ }
+ }
+ if (recvbytes == 0)
+ {
+ /* The MAAP daemon closed the connection. Assume it shut down, and we should too. */
+ MAAP_LOG_INFO("MAAP daemon exited. Closing application.");
+ exit_received = 1;
+ }
+ if (recvbytes < 0 && errno != EWOULDBLOCK)
+ {
+ /* Something went wrong. Abort! */
+ MAAP_LOGF_ERROR("Error %d reading from network socket (%s)", errno, strerror(errno));
+ break;
+ }
+ }
+
+ /* Handle any commands received via stdin. */
+ if (FD_ISSET(STDIN_FILENO, &read_fds))
+ {
+ recvbytes = read(STDIN_FILENO, recvbuffer, sizeof(recvbuffer) - 1);
+ if (recvbytes <= 0)
+ {
+ MAAP_LOGF_ERROR("Error %d reading from stdin (%s)", errno, strerror(errno));
+ }
+ else
+ {
+ Maap_Cmd *bufcmd = (Maap_Cmd *) recvbuffer;
+ int rv = 0;
+
+ recvbuffer[recvbytes] = '\0';
+
+ /* Determine the command requested (may be binary or text). */
+ switch (bufcmd->kind) {
+ case MAAP_CMD_INIT:
+ case MAAP_CMD_RESERVE:
+ case MAAP_CMD_RELEASE:
+ case MAAP_CMD_STATUS:
+ case MAAP_CMD_YIELD:
+ case MAAP_CMD_EXIT:
+ memcpy(&recvcmd, bufcmd, sizeof(Maap_Cmd));
+ rv = 1;
+ break;
+ default:
+ memset(&recvcmd, 0, sizeof(Maap_Cmd));
+ rv = parse_text_cmd(recvbuffer, &recvcmd);
+ if (!rv) {
+ if (strncmp(recvbuffer, "help", 4) != 0) {
+ puts("Invalid command type");
+ }
+ parse_usage(display_print_notify_result, NULL);
+ }
+ break;
+ }
+
+ /* If the command is valid, Send it to the MAAP daemon. */
+ if (rv)
+ {
+ if (send(socketfd, (char *) &recvcmd, sizeof(Maap_Cmd), 0) < 0)
+ {
+ /* Something went wrong. Abort! */
+ MAAP_LOGF_ERROR("Error %d writing to network socket (%s)", errno, strerror(errno));
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ close(socketfd);
+
+ maapLogExit();
+
+ return (exit_received ? 0 : -1);
+}
+
+static int do_daemonize(void)
+{
+ int x;
+ pid_t pid;
+
+ pid = fork();
+ if (pid < 0) {
+ exit(EXIT_FAILURE);
+ } else if (pid > 0) {
+ /* Let the controlling terminal know the first fork worked. */
+ exit(EXIT_SUCCESS);
+ }
+
+ /* Make child process session leader */
+ if (setsid() < 0) {
+ exit(EXIT_FAILURE);
+ }
+
+ signal(SIGCHLD, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+
+ if (fork() != 0) {
+ exit(EXIT_FAILURE);
+ }
+
+ umask(0);
+ x = chdir("/");
+
+ /* Close all open file descriptors */
+ for (x = sysconf(_SC_OPEN_MAX); x>=0; x--) {
+ close(x);
+ }
+
+ return 0;
+}
+
+static void log_print_notify_result(void *callback_data, int logLevel, const char *notifyText)
+{
+ switch (logLevel) {
+ case MAAP_LOG_LEVEL_ERROR:
+ MAAP_LOG_ERROR(notifyText);
+ break;
+ case MAAP_LOG_LEVEL_WARNING:
+ MAAP_LOG_WARNING(notifyText);
+ break;
+ case MAAP_LOG_LEVEL_INFO:
+ MAAP_LOG_INFO(notifyText);
+ break;
+ case MAAP_LOG_LEVEL_STATUS:
+ MAAP_LOG_STATUS(notifyText);
+ break;
+ case MAAP_LOG_LEVEL_DEBUG:
+ MAAP_LOG_DEBUG(notifyText);
+ break;
+ case MAAP_LOG_LEVEL_VERBOSE:
+ MAAP_LOG_VERBOSE(notifyText);
+ break;
+ }
+}
+
+static void format_print_notify_result(int logLevel, const char *notifyText, char *szOutputText)
+
+{
+ int i, nLastSpace;
+ int nInitial = -1;
+ char *pszOut = szOutputText;
+
+ /* Break the string up into one-line chunks.
+ * Note that tabs and newlines are not handled correctly. */
+ while (*notifyText) {
+ if (nInitial < 0) {
+ if (logLevel == MAAP_LOG_LEVEL_ERROR) {
+ strcpy(pszOut, "Error: ");
+ nInitial = (int) strlen(pszOut);
+ pszOut += nInitial;
+ } else if (logLevel == MAAP_LOG_LEVEL_WARNING) {
+ strcpy(pszOut, "Warning: ");
+ nInitial = (int) strlen(pszOut);
+ pszOut += nInitial;
+ } else {
+ nInitial = 0;
+ }
+ } else {
+ /* We already accounted for the initial text. */
+ nInitial = 0;
+ }
+
+ nLastSpace = -1;
+ for (i = 0; (i < MAAP_LOG_STDOUT_CONSOLE_WIDTH - nInitial || nLastSpace <= 0) && notifyText[i]; ++i) {
+ if (isspace(notifyText[i])) { nLastSpace = i; }
+ }
+ if (notifyText[i] == '\0') {
+ /* Print the remainder of the string. */
+ strcpy(pszOut, notifyText);
+ pszOut += strlen(pszOut);
+ *pszOut++ = '\r'; // Useful for Telnet interaction
+ *pszOut++ = '\n';
+ break;
+ }
+
+ /* Print the string up to the last space. */
+ for (i = 0; i < nLastSpace; ++i) {
+ *pszOut++ = *notifyText++;
+ }
+ *pszOut++ = '\r'; // Useful for Telnet interaction
+ *pszOut++ = '\n';
+
+ /* Go to the start of the next word in the string. */
+ while (isspace(*notifyText)) { notifyText++; }
+ }
+
+ *pszOut = '\0';
+}
+
+static void display_print_notify_result(void *callback_data, int logLevel, const char *notifyText)
+{
+ char szOutputText[ 300 ];
+
+ format_print_notify_result(logLevel, notifyText, szOutputText);
+ fputs(szOutputText, stdout);
+ fflush(stdout);
+}
+
+static void send_print_notify_result(void *callback_data, int logLevel, const char *notifyText)
+{
+ char szOutputText[ 300 ];
+
+ format_print_notify_result(logLevel, notifyText, szOutputText);
+ if (send(*(int *)callback_data, szOutputText, strlen(szOutputText), 0) < 0)
+ {
+ /* Something went wrong. Assume the socket will be closed below. */
+ MAAP_LOGF_ERROR("Error %d writing to client socket %d (%s)", errno, *(int *)callback_data, strerror(errno));
+ }
+}
diff --git a/daemons/maap/linux/src/maap_helper_linux.h b/daemons/maap/linux/src/maap_helper_linux.h
new file mode 100644
index 00000000..e5b3b3d1
--- /dev/null
+++ b/daemons/maap/linux/src/maap_helper_linux.h
@@ -0,0 +1,183 @@
+/*************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************/
+
+#ifndef MAAP_HELPER_LINUX_H
+#define MAAP_HELPER_LINUX_H
+
+#include <unistd.h>
+#include <pthread.h>
+#include <signal.h>
+#include <time.h>
+#include <semaphore.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <dlfcn.h>
+
+// Uncomment to use manual data alignment adjustments. Not needed for Linux
+//#define DATA_ALIGNMENT_ADJUSTMENT 1
+
+/// Number of nanoseconds in second
+#define NANOSECONDS_PER_SECOND (1000000000ULL)
+/// Number of nanoseconds in millisecond
+#define NANOSECONDS_PER_MSEC (1000000L)
+/// Number of nanoseconds in microsecond
+#define NANOSECONDS_PER_USEC (1000L)
+/// Number of microseconds in second
+#define MICROSECONDS_PER_SECOND (1000000L)
+/// Number of microseconds in millisecond
+#define MICROSECONDS_PER_MSEC (1000L)
+
+#define SLEEP(sec) sleep(sec)
+#define SLEEP_MSEC(mSec) usleep(mSec * 1000)
+#define SLEEP_NSEC(nSec) usleep(nSec / 1000)
+#define SLEEP_UNTIL_NSEC(nSec) xSleepUntilNSec(nSec)
+inline static void xSleepUntilNSec(uint64_t nSec)
+{
+ struct timespec tmpTime;
+ tmpTime.tv_sec = nSec / NANOSECONDS_PER_SECOND;
+ tmpTime.tv_nsec = nSec % NANOSECONDS_PER_SECOND;
+ clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &tmpTime, NULL);
+}
+
+#define RAND() random()
+#define SRAND(seed) srandom(seed)
+
+#define PRAGMA_ALIGN_8
+
+#define SIGNAL_CALLBACK_SETUP(__NAM, __CB) \
+ struct sigaction __NAM; \
+ __NAM.sa_handler = __CB
+
+#define SIGNAL_SIGNAL_SETUP(__SIG, __NAM, __CB, __ERR) \
+ sigemptyset(&__NAM.sa_mask); \
+ __NAM.sa_flags = 0; \
+ __ERR = sigaction(__SIG, &__NAM, NULL)
+
+
+// the following macros define thread related items
+#define THREAD_TYPE(thread) \
+typedef struct \
+{ \
+ pthread_t pthread; \
+ int err; \
+} thread##_type;
+
+#define THREAD_DEFINITON(thread) \
+ thread##_type thread##_ThreadData
+
+#define THREAD_CREATE(threadName, threadhandle, thread_attr_name, thread_function, thread_function_arg) \
+ { \
+ pthread_attr_t thread_attr; \
+ do { \
+ threadhandle##_ThreadData.err = pthread_attr_init(&thread_attr); \
+ if (threadhandle##_ThreadData.err) break; \
+ threadhandle##_ThreadData.err = pthread_attr_setstacksize(&thread_attr, threadName##_THREAD_STK_SIZE); \
+ if (threadhandle##_ThreadData.err) break; \
+ threadhandle##_ThreadData.err = pthread_create( \
+ (pthread_t*)&threadhandle##_ThreadData.pthread, \
+ &thread_attr, \
+ thread_function, \
+ (void*)thread_function_arg); \
+ } while (0); \
+ pthread_attr_destroy(&thread_attr); \
+ }
+
+#define THREAD_SET_RT_PRIORITY(threadhandle, priority) \
+ { \
+ struct sched_param param; \
+ param.__sched_priority = priority; \
+ pthread_setschedparam(threadhandle##_ThreadData.pthread, SCHED_RR, &param); \
+ }
+
+#define THREAD_PIN(threadhandle, affinity) \
+ { \
+ cpu_set_t cpuset; \
+ int i1; \
+ CPU_ZERO(&cpuset); \
+ for (i1 = 0; i1 < 32; i1++) { \
+ if (affinity & (1 << i1)) CPU_SET(i1, &cpuset); \
+ } \
+ pthread_setaffinity_np(threadhandle##_ThreadData.pthread, sizeof(cpu_set_t), &cpuset); \
+ }
+
+#define THREAD_CHECK_ERROR(threadhandle, message, error) \
+ do { \
+ error=FALSE; \
+ if (threadhandle##_ThreadData.err != 0) \
+ { \
+ MAAP_LOGF_ERROR("Thread error: %s code: %d", message, threadhandle##_ThreadData.err); \
+ error=TRUE; \
+ break; \
+ } \
+ } while (0)
+
+#define THREAD_STARTTHREAD(err)
+#define THREAD_KILL(threadhandle, signal) pthread_kill(threadhandle##_ThreadData.pthread, signal)
+#define THREAD_JOINABLE(threadhandle)
+#define THREAD_JOIN(threadhandle, signal) pthread_join(threadhandle##_ThreadData.pthread, (void**)signal)
+#define THREAD_SLEEP(threadhandle, secs) sleep(secs)
+
+#define THREAD_SELF() pthread_self()
+#define GET_PID() getpid()
+
+#define SEM_T(sem) sem_t sem;
+#define SEM_ERR_T(err) int err;
+#define SEM_INIT(sem, init, err) err = sem_init(&sem, 0, init);
+#define SEM_WAIT(sem, err) err = sem_wait(&sem);
+#define SEM_POST(sem, err) err = sem_post(&sem);
+#define SEM_DESTROY(sem, err) err = sem_destroy(&sem);
+#define SEM_IS_ERR_NONE(err) (0 == err)
+#define SEM_IS_ERR_TIMEOUT(err) (ETIMEDOUT == err || ((-1 == err) && (ETIMEDOUT == errno)))
+#define SEM_LOG_ERR(err) if (0 != err) MAAP_LOGF_ERROR("Semaphore error code: %d", err);
+
+#define MUTEX_ATTR_TYPE_DEFAULT PTHREAD_MUTEX_DEFAULT
+#define MUTEX_ATTR_TYPE_RECURSIVE PTHREAD_MUTEX_RECURSIVE
+#define MUTEX_HANDLE(mutex_handle) pthread_mutex_t mutex_handle
+#define MUTEX_ATTR_HANDLE(mutex_attr_name) pthread_mutexattr_t mutex_attr_name
+#define MUTEX_ATTR_CREATE_ERR() static mutex_err
+#define MUTEX_ATTR_INIT(mutex_attr_name) pthread_mutexattr_init(&mutex_attr_name)
+#define MUTEX_ATTR_SET_TYPE(mutex_attr_name,type) pthread_mutexattr_settype(&mutex_attr_name, type)
+#define MUTEX_ATTR_SET_NAME(mutex_attr_name, name)
+#define MUTEX_CREATE_ERR() int mutex_err
+#define MUTEX_CREATE(mutex_handle,mutex_attr_name) mutex_err=pthread_mutex_init(&mutex_handle, &mutex_attr_name)
+#define MUTEX_LOCK(mutex_handle) mutex_err=pthread_mutex_lock(&mutex_handle)
+#define MUTEX_UNLOCK(mutex_handle) mutex_err=pthread_mutex_unlock(&mutex_handle)
+#define MUTEX_DESTROY(mutex_handle) mutex_err=pthread_mutex_destroy(&mutex_handle)
+#define MUTEX_LOG_ERR(message) if (mutex_err) MAAP_LOG_ERROR(message);
+#define MUTEX_IS_ERR (mutex_err != 0)
+
+// Alternate simplified mutex mapping
+#define MUTEX_HANDLE_ALT(mutex_handle) pthread_mutex_t mutex_handle
+#define MUTEX_CREATE_ALT(mutex_handle) pthread_mutex_init(&mutex_handle, NULL)
+#define MUTEX_LOCK_ALT(mutex_handle) pthread_mutex_lock(&mutex_handle)
+#define MUTEX_UNLOCK_ALT(mutex_handle) pthread_mutex_unlock(&mutex_handle)
+#define MUTEX_DESTROY_ALT(mutex_handle) pthread_mutex_destroy(&mutex_handle)
+
+#endif // MAAP_HELPER_LINUX_H
+
diff --git a/daemons/maap/linux/src/maap_log_linux.c b/daemons/maap/linux/src/maap_log_linux.c
new file mode 100644
index 00000000..2d6f02b3
--- /dev/null
+++ b/daemons/maap/linux/src/maap_log_linux.c
@@ -0,0 +1,439 @@
+/*************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************/
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "platform.h"
+#include "maap_log_queue.h"
+#include "maap_helper_linux.h"
+
+#define MAAP_LOG_COMPONENT "Log"
+#include "maap_log.h"
+
+typedef struct {
+ uint8_t msg[LOG_QUEUE_MSG_SIZE];
+ int bRT; // TRUE = Details are in RT queue
+} log_queue_item_t;
+
+typedef struct {
+ char *pFormat;
+ log_rt_datatype_t dataType;
+ union {
+ struct timespec nowTS;
+ uint16_t unsignedShortVar;
+ int16_t signedShortVar;
+ uint32_t unsignedLongVar;
+ int32_t signedLongVar;
+ uint64_t unsignedLongLongVar;
+ int64_t signedLongLongVar;
+ float floatVar;
+ } data;
+ int bEnd;
+} log_rt_queue_item_t;
+
+static maap_log_queue_t logQueue;
+static maap_log_queue_t logRTQueue;
+
+static char msg[LOG_MSG_LEN] = "";
+static char time_msg[LOG_TIME_LEN] = "";
+static char timestamp_msg[LOG_TIMESTAMP_LEN] = "";
+static char file_msg[LOG_FILE_LEN] = "";
+static char proc_msg[LOG_PROC_LEN] = "";
+static char thread_msg[LOG_THREAD_LEN] = "";
+static char full_msg[LOG_FULL_MSG_LEN] = "";
+
+static char rt_msg[LOG_RT_MSG_LEN] = "";
+
+static int loggingThreadRunning = FALSE;
+extern void *loggingThreadFn(void *pv);
+THREAD_TYPE(loggingThread);
+THREAD_DEFINITON(loggingThread);
+
+#define THREAD_STACK_SIZE 65536
+#define loggingThread_THREAD_STK_SIZE THREAD_STACK_SIZE
+
+static MUTEX_HANDLE_ALT(gLogMutex);
+#define LOG_LOCK() MUTEX_LOCK_ALT(gLogMutex)
+#define LOG_UNLOCK() MUTEX_UNLOCK_ALT(gLogMutex)
+
+void maapLogRTRender(log_queue_item_t *pLogItem)
+{
+ if (logRTQueue) {
+ pLogItem->msg[0] = 0x00;
+ int bMore = TRUE;
+ while (bMore) {
+ maap_log_queue_elem_t elem = maapLogQueueTailLock(logRTQueue);
+ if (elem) {
+ log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)maapLogQueueData(elem);
+
+ switch (pLogRTItem->dataType) {
+ case LOG_RT_DATATYPE_CONST_STR:
+ strcat((char *)pLogItem->msg, pLogRTItem->pFormat);
+ break;
+ case LOG_RT_DATATYPE_NOW_TS:
+ sprintf(rt_msg, "[%lu:%09lu] ", pLogRTItem->data.nowTS.tv_sec, pLogRTItem->data.nowTS.tv_nsec);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_U16:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.unsignedShortVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_S16:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.signedShortVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_U32:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.unsignedLongVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_S32:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.signedLongVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_U64:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.unsignedLongLongVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_S64:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.signedLongLongVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_FLOAT:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.floatVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ default:
+ break;
+ }
+
+ if (pLogRTItem->bEnd) {
+ if (MAAP_LOG_EXTRA_NEWLINE)
+ strcat((char *)pLogItem->msg, "\n");
+ bMore = FALSE;
+ }
+ maapLogQueueTailPull(logRTQueue);
+ }
+ }
+ }
+}
+
+uint32_t maapLogGetMsg(uint8_t *pBuf, uint32_t bufSize)
+{
+ uint32_t dataLen = 0;
+ if (logQueue) {
+ maap_log_queue_elem_t elem = maapLogQueueTailLock(logQueue);
+ if (elem) {
+ log_queue_item_t *pLogItem = (log_queue_item_t *)maapLogQueueData(elem);
+
+ if (pLogItem->bRT)
+ maapLogRTRender(pLogItem);
+
+ dataLen = strlen((const char *)pLogItem->msg);
+ if (dataLen <= bufSize)
+ memcpy(pBuf, (uint8_t *)pLogItem->msg, dataLen);
+ else
+ memcpy(pBuf, (uint8_t *)pLogItem->msg, bufSize);
+ maapLogQueueTailPull(logQueue);
+ return dataLen;
+ }
+ }
+ return dataLen;
+}
+
+void *loggingThreadFn(void *pv)
+{
+ while (loggingThreadRunning) {
+ SLEEP_MSEC(LOG_QUEUE_SLEEP_MSEC);
+
+ int more = TRUE;
+
+ while (more) {
+ more = FALSE;
+ maap_log_queue_elem_t elem = maapLogQueueTailLock(logQueue);
+ if (elem) {
+ log_queue_item_t *pLogItem = (log_queue_item_t *)maapLogQueueData(elem);
+
+ if (pLogItem->bRT)
+ maapLogRTRender(pLogItem);
+
+ fputs((const char *)pLogItem->msg, MAAP_LOG_OUTPUT_FD);
+ maapLogQueueTailPull(logQueue);
+ more = TRUE;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+void maapLogInit(void)
+{
+ MUTEX_CREATE_ALT(gLogMutex);
+
+ logQueue = maapLogQueueNewQueue(sizeof(log_queue_item_t), LOG_QUEUE_MSG_CNT);
+ if (!logQueue) {
+ printf("Failed to initialize logging facility\n");
+ }
+
+ logRTQueue = maapLogQueueNewQueue(sizeof(log_rt_queue_item_t), LOG_RT_QUEUE_CNT);
+ if (!logRTQueue) {
+ printf("Failed to initialize logging RT facility\n");
+ }
+
+ // Start the logging task
+ if (MAAP_LOG_FROM_THREAD) {
+ int errResult;
+ loggingThreadRunning = TRUE;
+ THREAD_CREATE(loggingThread, loggingThread, NULL, loggingThreadFn, NULL);
+ THREAD_CHECK_ERROR(loggingThread, "Thread / task creation failed", errResult);
+ if (errResult); // Already reported
+ }
+}
+
+void maapLogExit()
+{
+ if (MAAP_LOG_FROM_THREAD) {
+ loggingThreadRunning = FALSE;
+ THREAD_JOIN(loggingThread, NULL);
+ }
+}
+
+void maapLogFn(
+ int level,
+ const char *tag,
+ const char *company,
+ const char *component,
+ const char *path,
+ int line,
+ const char *fmt,
+ ...)
+{
+ if (level <= MAAP_LOG_LEVEL) {
+ va_list args;
+ va_start(args, fmt);
+
+ LOG_LOCK();
+
+ vsprintf(msg, fmt, args);
+
+ if (MAAP_LOG_FILE_INFO && path) {
+ char* file = strrchr(path, '/');
+ if (!file)
+ file = strrchr(path, '\\');
+ if (file)
+ file += 1;
+ else
+ file = (char*)path;
+ sprintf(file_msg, " %s:%d", file, line);
+ }
+ if (MAAP_LOG_PROC_INFO) {
+ sprintf(proc_msg, " P:%5.5d", GET_PID());
+ }
+ if (MAAP_LOG_THREAD_INFO) {
+ sprintf(thread_msg, " T:%lu", THREAD_SELF());
+ }
+ if (MAAP_LOG_TIME_INFO) {
+ time_t tNow = time(NULL);
+ struct tm tmNow;
+ localtime_r(&tNow, &tmNow);
+
+ sprintf(time_msg, "%2.2d:%2.2d:%2.2d", tmNow.tm_hour, tmNow.tm_min, tmNow.tm_sec);
+ }
+ if (MAAP_LOG_TIMESTAMP_INFO) {
+ struct timespec nowTS;
+ clock_gettime(CLOCK_REALTIME, &nowTS);
+
+ sprintf(timestamp_msg, "%lu:%09lu", nowTS.tv_sec, nowTS.tv_nsec);
+ }
+
+ // using sprintf and puts allows using static buffers rather than heap.
+ if (MAAP_LOG_EXTRA_NEWLINE)
+ /* int32_t full_msg_len = */ sprintf(full_msg, "[%s%s%s%s %s %s%s] %s: %s\n", time_msg, timestamp_msg, proc_msg, thread_msg, company, component, file_msg, tag, msg);
+ else
+ /* int32_t full_msg_len = */ sprintf(full_msg, "[%s%s%s%s %s %s%s] %s: %s", time_msg, timestamp_msg, proc_msg, thread_msg, company, component, file_msg, tag, msg);
+
+ if (!MAAP_LOG_FROM_THREAD && !MAAP_LOG_PULL_MODE) {
+ fputs(full_msg, MAAP_LOG_OUTPUT_FD);
+ }
+ else {
+ if (logQueue) {
+ maap_log_queue_elem_t elem = maapLogQueueHeadLock(logQueue);
+ if (elem) {
+ log_queue_item_t *pLogItem = (log_queue_item_t *)maapLogQueueData(elem);
+ pLogItem->bRT = FALSE;
+ strncpy((char *)pLogItem->msg, full_msg, LOG_QUEUE_MSG_LEN);
+ maapLogQueueHeadPush(logQueue);
+ }
+ }
+ }
+
+ va_end(args);
+
+ LOG_UNLOCK();
+ }
+}
+
+void maapLogRT(int level, int bBegin, int bItem, int bEnd, char *pFormat, log_rt_datatype_t dataType, void *pVar)
+{
+ if (level <= MAAP_LOG_LEVEL) {
+ if (logRTQueue) {
+ if (bBegin) {
+ LOG_LOCK();
+
+ maap_log_queue_elem_t elem = maapLogQueueHeadLock(logRTQueue);
+ if (elem) {
+ log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)maapLogQueueData(elem);
+ pLogRTItem->bEnd = FALSE;
+ pLogRTItem->pFormat = NULL;
+ pLogRTItem->dataType = LOG_RT_DATATYPE_NOW_TS;
+ clock_gettime(CLOCK_REALTIME, &pLogRTItem->data.nowTS);
+ maapLogQueueHeadPush(logRTQueue);
+ }
+ }
+
+ if (bItem) {
+ maap_log_queue_elem_t elem = maapLogQueueHeadLock(logRTQueue);
+ if (elem) {
+ log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)maapLogQueueData(elem);
+ if (bEnd)
+ pLogRTItem->bEnd = TRUE;
+ else
+ pLogRTItem->bEnd = FALSE;
+ pLogRTItem->pFormat = pFormat;
+ pLogRTItem->dataType = dataType;
+
+ switch (pLogRTItem->dataType) {
+ case LOG_RT_DATATYPE_CONST_STR:
+ break;
+ case LOG_RT_DATATYPE_U16:
+ pLogRTItem->data.unsignedLongVar = *(uint16_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_S16:
+ pLogRTItem->data.signedLongVar = *(int16_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_U32:
+ pLogRTItem->data.unsignedLongVar = *(uint32_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_S32:
+ pLogRTItem->data.signedLongVar = *(int32_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_U64:
+ pLogRTItem->data.unsignedLongLongVar = *(uint64_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_S64:
+ pLogRTItem->data.signedLongLongVar = *(int64_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_FLOAT:
+ pLogRTItem->data.floatVar = *(float *)pVar;
+ break;
+ default:
+ break;
+ }
+ maapLogQueueHeadPush(logRTQueue);
+ }
+ }
+
+ if (!bItem && bEnd) {
+ maap_log_queue_elem_t elem = maapLogQueueHeadLock(logRTQueue);
+ if (elem) {
+ log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)maapLogQueueData(elem);
+ pLogRTItem->bEnd = TRUE;
+ pLogRTItem->pFormat = NULL;
+ pLogRTItem->dataType = LOG_RT_DATATYPE_NONE;
+ maapLogQueueHeadPush(logRTQueue);
+ }
+ }
+
+ if (bEnd) {
+ if (logQueue) {
+ maap_log_queue_elem_t elem = maapLogQueueHeadLock(logQueue);
+ if (elem) {
+ log_queue_item_t *pLogItem = (log_queue_item_t *)maapLogQueueData(elem);
+ pLogItem->bRT = TRUE;
+ if (MAAP_LOG_FROM_THREAD) {
+ maapLogQueueHeadPush(logQueue);
+ } else {
+ maapLogRTRender(pLogItem);
+ fputs((const char *)pLogItem->msg, MAAP_LOG_OUTPUT_FD);
+ maapLogQueueHeadUnlock(logQueue);
+ }
+ }
+ }
+
+ LOG_UNLOCK();
+ }
+ }
+ }
+}
+
+void maapLogBuffer(
+ int level,
+ const uint8_t *pData,
+ int dataLen,
+ int lineLen,
+ const char *company,
+ const char *component,
+ const char *path,
+ int line)
+{
+ char szDataLine[ 400 ];
+ char *pszOut;
+ size_t i, j;
+
+ if (level > MAAP_LOG_LEVEL) { return; }
+
+ for (i = 0; i < dataLen; i += lineLen) {
+ /* Create the hexadecimal output for the buffer. */
+ pszOut = szDataLine;
+ *pszOut++ = '\t';
+ for (j = i; j < i + lineLen; ++j) {
+ if (j < dataLen) {
+ sprintf(pszOut, "%02x ", pData[j]);
+ } else {
+ strcpy(pszOut, " ");
+ }
+ pszOut += 3;
+ }
+
+ *pszOut++ = ' ';
+ *pszOut++ = ' ';
+
+ /* Append the ASCII equivalent of each character. */
+ for (j = i; j < dataLen && j < i + lineLen; ++j) {
+ if (pData[j] >= 0x20 && pData[j] < 0x7f) {
+ *pszOut++ = (char) pData[j];
+ } else {
+ *pszOut++ = '.';
+ }
+ }
+
+ /* Display this line of text. */
+ *pszOut = '\0';
+ maapLogFn(level, "BUFFER", company, component, path, line, "%s", szDataLine);
+ }
+}
diff --git a/daemons/maap/linux/src/maap_timer_linux.c b/daemons/maap/linux/src/maap_timer_linux.c
new file mode 100644
index 00000000..a8d894e2
--- /dev/null
+++ b/daemons/maap/linux/src/maap_timer_linux.c
@@ -0,0 +1,157 @@
+/*************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <assert.h>
+#include <time.h>
+#include <errno.h>
+
+struct maap_timer {
+ timer_t timer_id;
+};
+
+#include "maap_timer.h"
+
+#define MAAP_LOG_COMPONENT "Timer"
+#include "maap_log.h"
+
+
+Timer *Time_newTimer(void)
+{
+ struct sigevent sev;
+ Timer * newTimer = malloc(sizeof (Timer));
+ if (newTimer)
+ {
+ sev.sigev_notify = SIGEV_NONE;
+ sev.sigev_signo = 0;
+ sev.sigev_value.sival_ptr = NULL;
+ if (timer_create(CLOCK_MONOTONIC, &sev, &(newTimer->timer_id)) < 0)
+ {
+ newTimer->timer_id = (timer_t)(-1);
+ }
+ }
+ return newTimer;
+}
+
+void Time_delTimer(Timer *timer)
+{
+ assert(timer);
+ if (timer && timer->timer_id != (timer_t)(-1))
+ {
+ timer_delete(timer->timer_id);
+ }
+ free(timer);
+}
+
+void Time_setTimer(Timer *timer, const Time *t)
+{
+ struct itimerspec tspec;
+ tspec.it_value.tv_sec = t->tv_sec;
+ tspec.it_value.tv_nsec = t->tv_nsec;
+ tspec.it_interval.tv_sec = 0;
+ tspec.it_interval.tv_nsec = 0;
+ timer_settime(timer->timer_id, TIMER_ABSTIME, &tspec, NULL);
+}
+
+int64_t Time_remaining(Timer *timer)
+{
+ struct itimerspec curr_value;
+
+ assert(timer);
+ if (timer_gettime(timer->timer_id, &curr_value) < 0)
+ {
+ MAAP_LOGF_ERROR("Error %d getting the timer time remaining (%s)", errno, strerror(errno));
+ return -1;
+ }
+
+ return ((int64_t) curr_value.it_value.tv_sec * 1000000000LL + (int64_t) curr_value.it_value.tv_nsec);
+}
+
+
+void Time_add(Time *a, const Time *b)
+{
+ a->tv_sec = a->tv_sec + b->tv_sec;
+ a->tv_nsec = a->tv_nsec + b->tv_nsec;
+ if (a->tv_nsec > 1000000000L) {
+ a->tv_sec++;
+ a->tv_nsec = a->tv_nsec - 1000000000L;
+ }
+}
+
+int64_t Time_diff(const Time *a, const Time *b)
+{
+ int64_t a_ns = (int64_t) a->tv_sec * 1000000000LL + (int64_t) a->tv_nsec;
+ int64_t b_ns = (int64_t) b->tv_sec * 1000000000LL + (int64_t) b->tv_nsec;
+ return b_ns - a_ns;
+}
+
+int Time_cmp(const Time *a, const Time *b)
+{
+ if (a->tv_sec < b->tv_sec) {
+ return -1;
+ }
+ if (a->tv_sec > b->tv_sec) {
+ return 1;
+ }
+ if (a->tv_nsec < b->tv_nsec) {
+ return -1;
+ }
+ if (a->tv_nsec > b->tv_nsec) {
+ return 1;
+ }
+ return 0;
+}
+
+int Time_passed(const Time *current, const Time *target)
+{
+ if (current->tv_sec < target->tv_sec) {
+ return 0;
+ }
+ if (current->tv_sec == target->tv_sec && current->tv_nsec < target->tv_nsec) {
+ return 0;
+ }
+ return 1;
+}
+
+void Time_setFromNanos(Time *t, uint64_t nsec)
+{
+ t->tv_sec = nsec / 1000000000LL;
+ t->tv_nsec = nsec - t->tv_sec * 1000000000LL;
+}
+
+void Time_setFromMonotonicTimer(Time *t)
+{
+ clock_gettime(CLOCK_MONOTONIC, t);
+}
+
+const char * Time_dump(const Time *t)
+{
+ static char buffer[40];
+ sprintf(buffer, "%lu sec, %09lu nsec", (unsigned long)t->tv_sec, (unsigned long)t->tv_nsec);
+ return buffer;
+}
diff --git a/daemons/maap/test/CMakeLists.txt b/daemons/maap/test/CMakeLists.txt
new file mode 100644
index 00000000..3ccafbfa
--- /dev/null
+++ b/daemons/maap/test/CMakeLists.txt
@@ -0,0 +1,15 @@
+cmake_minimum_required (VERSION 2.8)
+project (maap_tests)
+enable_testing()
+
+set (ComDir "../common" )
+
+include_directories( ${ComDir} )
+
+if(UNIX)
+ add_executable( test_intervals "test_intervals.c" "${ComDir}/intervals.c" )
+elseif(WIN32)
+ add_executable( test_intervals "test_intervals.c" "${ComDir}/intervals.c" )
+endif()
+
+add_test(IntervalTreeWorks test_intervals )
diff --git a/daemons/maap/test/maap_log_dummy.c b/daemons/maap/test/maap_log_dummy.c
new file mode 100644
index 00000000..7ac240de
--- /dev/null
+++ b/daemons/maap/test/maap_log_dummy.c
@@ -0,0 +1,127 @@
+/*************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************/
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#if defined(_WIN32) && (_MSC_VER < 1800)
+/* Visual Studio 2012 and earlier */
+typedef unsigned __int8 uint8_t;
+typedef unsigned __int32 uint32_t;
+#else
+#include <inttypes.h>
+#endif
+
+#include <assert.h>
+
+#include "platform.h"
+
+#define MAAP_LOG_COMPONENT "Log"
+#include "maap_log.h"
+
+static char s_lastLogTag[LOG_MSG_LEN];
+static char s_lastLogMessage[LOG_MSG_LEN];
+
+const char * Logging_getLastTag(void)
+{
+ static char returnLogTag[LOG_MSG_LEN];
+
+ /* Copy the current value. */
+ strncpy(returnLogTag, s_lastLogTag, sizeof(returnLogTag));
+ returnLogTag[sizeof(returnLogTag) - 1] = '\0';
+
+ /* Clear the current value, so it isn't returned again. */
+ s_lastLogTag[0] = '\0';
+
+ return returnLogTag;
+}
+
+const char * Logging_getLastMessage(void)
+{
+ static char returnLogMessage[LOG_MSG_LEN];
+
+ /* Copy the current value. */
+ strncpy(returnLogMessage, s_lastLogMessage, sizeof(returnLogMessage));
+ returnLogMessage[sizeof(returnLogMessage) - 1] = '\0';
+
+ /* Clear the current value, so it isn't returned again. */
+ s_lastLogMessage[0] = '\0';
+
+ return returnLogMessage;
+}
+
+
+void maapLogInit(void)
+{
+}
+
+void maapLogExit()
+{
+}
+
+void maapLogFn(
+ int level,
+ const char *tag,
+ const char *company,
+ const char *component,
+ const char *path,
+ int line,
+ const char *fmt,
+ ...)
+{
+ va_list args;
+ va_start(args, fmt);
+
+ if (strcmp(tag, "DEBUG") == 0 || strcmp(tag, "VERBOSE") == 0) { return; }
+
+ /* Save the supplied tag for use later. */
+ strncpy(s_lastLogTag, tag, sizeof(s_lastLogTag));
+ s_lastLogTag[sizeof(s_lastLogTag) - 1] = '\0';
+
+ /* Save the supplied message for use later. */
+ assert(sizeof(s_lastLogMessage) >= 1000);
+ vsprintf(s_lastLogMessage, fmt, args);
+
+#if 0
+ /* Print the highlights of the log data. */
+ printf("%s: %s\n", s_lastLogTag, s_lastLogMessage);
+#endif
+
+ va_end(args);
+}
+
+void maapLogBuffer(
+ int level,
+ const uint8_t *pData,
+ int dataLen,
+ int lineLen,
+ const char *company,
+ const char *component,
+ const char *path,
+ int line)
+{
+ /* Don't do anything with this. */
+}
diff --git a/daemons/maap/test/maap_log_dummy.h b/daemons/maap/test/maap_log_dummy.h
new file mode 100644
index 00000000..a32e9a69
--- /dev/null
+++ b/daemons/maap/test/maap_log_dummy.h
@@ -0,0 +1,57 @@
+/*************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************/
+
+/**
+ * @file
+ *
+ * @brief Support for logging operations unit tests
+ *
+ * These functions support additional functions used by unit tests for logging operations.
+ */
+
+#ifndef MAAP_LOG_DUMMY_H
+#define MAAP_LOG_DUMMY_H
+
+
+/**
+ * Get the last logging tag reported.
+ *
+ * @note Debug and Verbose logging items are not included
+ *
+ * @return A string indicating the last logging tag reported.
+ */
+const char * Logging_getLastTag(void);
+
+/**
+ * Get the last logging message reported.
+ *
+ * @note Debug and Verbose logging items are not included
+ *
+ * @return A string indicating the last logging message reported.
+ */
+const char * Logging_getLastMessage(void);
+
+
+#endif // MAAP_LOG_DUMMY_H
diff --git a/daemons/maap/test/maap_test.c b/daemons/maap/test/maap_test.c
new file mode 100644
index 00000000..28f11daa
--- /dev/null
+++ b/daemons/maap/test/maap_test.c
@@ -0,0 +1,648 @@
+/*************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************/
+
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <strings.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <pcap.h>
+#include <stdlib.h>
+#include <linux/if_packet.h>
+#include <net/if.h>
+#include <endian.h>
+
+/* Test function forward declarations */
+void test1_setup(void);
+void test2_setup(void);
+void test3_setup(void);
+void delay_setup(void);
+
+/* MAAP packet encoding/decoding */
+#define MAAP_RESERVED 0
+#define MAAP_PROBE 1
+#define MAAP_DEFEND 2
+#define MAAP_ANNOUNCE 3
+
+typedef struct maap_packet {
+ uint64_t DA;
+ uint64_t SA;
+ uint16_t Ethertype;
+ uint16_t subtype;
+ uint8_t SV;
+ uint8_t version;
+ uint8_t message_type;
+ uint8_t status;
+ uint16_t control_data_length;
+ uint64_t stream_id;
+ uint64_t requested_start_address;
+ uint16_t requested_count;
+ uint64_t start_address;
+ uint16_t count;
+} maap_packet_t;
+
+void dump_raw_stream(uint8_t *stream) {
+ int i;
+ for (i = 0; i < 42; i++) {
+ printf("%02x ", stream[i]);
+ if ((i+1) % 16 == 0) {
+ printf("\n");
+ }
+ }
+}
+
+void dump_packed_packet(maap_packet_t *packet) {
+ printf("\n\n");
+ printf("DA: %012llx\n", (unsigned long long)packet->DA);
+ printf("SA: %012llx\n", (unsigned long long)packet->SA);
+ printf("Ethertype: 0x%04x\n", packet->Ethertype);
+ printf("subtype: 0x%02x\n", packet->subtype);
+ printf("SV: %d\n", packet->SV);
+ printf("version: %d\n", packet->version);
+ printf("message_type: %d\n", packet->message_type);
+ printf("status: %d\n", packet->status);
+ printf("control_data_length: %d\n", packet->control_data_length);
+ printf("stream_id: %016llx\n", (unsigned long long)packet->stream_id);
+ printf("requested_start_address: %012llx\n", (unsigned long long)packet->requested_start_address);
+ printf("requested_count: %d\n", packet->requested_count);
+ printf("start_address: %012llx\n", (unsigned long long)packet->start_address);
+ printf("count: %d\n", packet->count);
+}
+
+int unpack_maap(maap_packet_t *packet, uint8_t *stream) {
+ packet->DA = be64toh(*(uint64_t *)stream) >> 16;
+ stream += 6;
+ packet->SA = be64toh(*(uint64_t *)stream) >> 16;
+ stream += 6;
+ packet->Ethertype = be16toh(*(uint16_t *)stream);
+ stream += 2;
+ packet->subtype = *stream;
+ stream++;
+ packet->SV = (*stream & 0x80) >> 7;
+ packet->version = (*stream & 0x70) >> 4;
+ packet->message_type = *stream & 0x0f;
+ stream++;
+ packet->status = (*stream & 0xf8) >> 3;
+ packet->control_data_length = be16toh(*(uint16_t *)stream) & 0x07ff;
+ stream += 2;
+ packet->stream_id = be64toh(*(uint64_t *)stream);
+ stream += 8;
+ packet->requested_start_address = be64toh(*(uint64_t *)stream) >> 16;
+ stream += 6;
+ packet->requested_count = be16toh(*(uint16_t *)stream);
+ stream += 2;
+ packet->start_address = be64toh(*(uint64_t *)stream) >> 16;
+ stream += 6;
+ packet->count = be16toh(*(uint16_t *)stream);
+ return 0;
+}
+
+int pack_maap(maap_packet_t *packet, uint8_t *stream) {
+ *(uint64_t *)stream = htobe64(packet->DA << 16);
+ stream += 6;
+ *(uint64_t *)stream = htobe64(packet->SA << 16);
+ stream += 6;
+ *(uint16_t *)stream = htobe16(packet->Ethertype);
+ stream += 2;
+ *stream = packet->subtype;
+ stream++;
+ *stream = (packet->SV << 7) | ((packet->version & 0x07) << 4) |
+ (packet->message_type & 0x0f);
+ stream++;
+ *(uint16_t *)stream = htobe16(((packet->status & 0x001f) << 11) |
+ (packet->control_data_length & 0x07ff));
+ stream += 2;
+ *(uint64_t *)stream = htobe64(packet->stream_id);
+ stream += 8;
+ *(uint64_t *)stream = htobe64(packet->requested_start_address << 16);
+ stream += 6;
+ *(uint16_t *)stream = htobe16(packet->requested_count);
+ stream += 2;
+ *(uint64_t *)stream = htobe64(packet->start_address << 16);
+ stream += 6;
+ *(uint16_t *)stream = htobe16(packet->count);
+ return 0;
+}
+
+/* callback for pcap when packets arrive */
+void parse_packet(u_char *args, const struct pcap_pkthdr *header,
+ const u_char *packet);
+
+struct maap_test_state {
+ int (*pkt_handler)(maap_packet_t *);
+ int state;
+ int rawsock;
+ uint64_t hwaddr;
+};
+
+struct maap_test_state test_state = {NULL, 0, 0, 0};
+
+int get_raw_sock(int ethertype) {
+ int rawsock;
+
+ if((rawsock = socket(PF_PACKET, SOCK_RAW, htons(ethertype))) == -1) {
+ perror("Error creating raw sock: ");
+ exit(-1);
+ }
+
+ return rawsock;
+}
+
+int bind_sock(char *device, int rawsock, int protocol) {
+ struct sockaddr_ll sll;
+ struct ifreq ifr;
+
+ bzero(&sll, sizeof(sll));
+ bzero(&ifr, sizeof(ifr));
+
+ /* First, get the interface index */
+ strncpy((char *)ifr.ifr_name, device, IFNAMSIZ);
+ if((ioctl(rawsock, SIOCGIFINDEX, &ifr)) == -1) {
+ printf("Error getting Interface index !\n");
+ printf("Problem interface: %s\n", device);
+ exit(-1);
+ }
+
+ /* Bind our raw socket to this interface */
+ sll.sll_family = AF_PACKET;
+ sll.sll_ifindex = ifr.ifr_ifindex;
+ sll.sll_protocol = htons(protocol);
+
+ /* Get the mac address */
+ if ((ioctl(rawsock, SIOCGIFHWADDR, &ifr)) == -1) {
+ printf("Error getting HW address\n");
+ exit(-1);
+ }
+ bcopy(ifr.ifr_hwaddr.sa_data, &test_state.hwaddr, 6);
+ test_state.hwaddr = be64toh(test_state.hwaddr) >> 16;
+ printf("Our MAC is %012llx\n", (unsigned long long int)test_state.hwaddr);
+
+ if((bind(rawsock, (struct sockaddr*)&sll, sizeof(sll))) == -1) {
+ perror("Error binding raw socket to interface\n");
+ exit(-1);
+ }
+
+ return 1;
+}
+
+int send_packet(int rawsock, maap_packet_t *mp) {
+ int sent = 0;
+ unsigned char pkt[60];
+
+ mp->SA = test_state.hwaddr;
+
+ pack_maap(mp, pkt);
+ if((sent = write(rawsock, pkt, 60)) != 60) {
+ return 0;
+ }
+ return 1;
+}
+
+int main(int argc, char *argv[]) {
+ char *dev, errbuf[PCAP_ERRBUF_SIZE];
+ pcap_t *handle;
+ struct bpf_program fp;
+ char filter_exp[] = "ether proto 0x22F0";
+ bpf_u_int32 mask;
+ bpf_u_int32 net;
+
+ if (argc < 2) {
+ dev = pcap_lookupdev(errbuf);
+ if (dev == NULL) {
+ fprintf(stderr, "Couldn't find default device: %s\n", errbuf);
+ fprintf(stderr, "Try specifying the device you want: %s <device>\n", argv[0]);
+ return 2;
+ }
+ } else {
+ dev = argv[1];
+ }
+
+ if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
+ fprintf(stderr, "Couldn't get netmask for device: %s\n", dev);
+ net = 0;
+ mask = 0;
+ }
+
+ handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
+ if (handle == NULL) {
+ fprintf(stderr, "Couldn't open device: %s\n", dev);
+ return 2;
+ }
+
+ printf("Listening on device: %s\n", dev);
+
+ if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
+ fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp,
+ pcap_geterr(handle));
+ return 2;
+ }
+
+ if (pcap_setfilter(handle, &fp) == -1) {
+ fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp,
+ pcap_geterr(handle));
+ return 2;
+ }
+
+ test_state.rawsock = get_raw_sock(0x22F0);
+ bind_sock(dev, test_state.rawsock, 0x22F0);
+
+ test1_setup();
+
+ pcap_loop(handle, -1, parse_packet, NULL);
+
+ return 0;
+}
+
+void parse_packet(u_char *args, const struct pcap_pkthdr *header,
+ const u_char *packet) {
+ maap_packet_t mp;
+
+ (void)args; (void)header;
+
+ unpack_maap(&mp, (uint8_t *)packet);
+
+ dump_packed_packet(&mp);
+
+ /* Ignore messages from us */
+ if (mp.SA == test_state.hwaddr) {
+ return;
+ }
+
+ if (test_state.pkt_handler) {
+ test_state.pkt_handler(&mp);
+ }
+
+ return;
+}
+
+/*************************************************************************
+ * Test functions
+ *************************************************************************/
+
+/* Wait for a probe, send a defense response, see if next probe is for a
+ different range */
+
+#define WAITING_FOR_1ST_PROBE 0
+#define WAITING_FOR_2ND_PROBE 1
+#define WAITING_FOR_3RD_PROBE 2
+
+int test1_handler(maap_packet_t *mp) {
+ static uint64_t start;
+ static uint16_t count;
+
+ switch (test_state.state) {
+
+ case WAITING_FOR_1ST_PROBE:
+
+ /* Make sure we're getting PROBE packets */
+ if (mp->message_type != MAAP_PROBE) {
+ fprintf(stderr, "Test 1: Error: Received a non-probe MAAP packet. Please start the test suite before starting the MAAP client to be tested.\n");
+ exit(2);
+ }
+ printf("Received a probe from %012llx for %d addresses starting at %012llx\n",
+ (long long unsigned int)mp->SA, mp->requested_count,
+ (long long unsigned int)mp->requested_start_address);
+
+ /* Store the range from the PROBE so we can conflict with it and compare
+ later */
+ start = mp->requested_start_address;
+ count = mp->requested_count;
+
+ /* Send a defense of this range */
+ mp->DA = mp->SA;
+ mp->SA = 0;
+ mp->message_type = MAAP_DEFEND;
+ mp->start_address = start;
+ mp->count = count;
+ send_packet(test_state.rawsock, mp);
+ printf("Sent defend packet\n");
+
+ /* Update testing state */
+ test_state.state = WAITING_FOR_2ND_PROBE;
+
+ break;
+
+ case WAITING_FOR_2ND_PROBE:
+
+ /* Make sure we got a probe in response */
+ if (mp->message_type != MAAP_PROBE) {
+ fprintf(stderr, "Test 1: FAIL - Got a non-probe packet, type %d.\n",
+ mp->message_type);
+ exit(2);
+ }
+
+ printf("Received a probe from %012llx for %d addresses starting at %012llx\n",
+ (long long unsigned int)mp->SA, mp->requested_count,
+ (long long unsigned int)mp->requested_start_address);
+
+ /* See if the address range has changed */
+ if (mp->requested_start_address == start) {
+ /* They may have sent before we did; give them one more try */
+ mp->DA = mp->SA;
+ mp->SA = 0;
+ mp->message_type = MAAP_DEFEND;
+ mp->start_address = start;
+ mp->count = count;
+ send_packet(test_state.rawsock, mp);
+ printf("Sent another defend packet\n");
+
+ /* Update testing state */
+ test_state.state = WAITING_FOR_3RD_PROBE;
+
+ } else {
+
+ /* Success! */
+ printf("Test 1: PASS\n");
+
+ test2_setup();
+
+ }
+
+ break;
+
+ case WAITING_FOR_3RD_PROBE:
+
+ /* Make sure we got a probe in response */
+ if (mp->message_type != MAAP_PROBE) {
+ fprintf(stderr, "Test 1: FAIL - Got a non-probe packet, type %d.\n",
+ mp->message_type);
+ exit(2);
+ }
+
+ printf("Received a probe from %012llx for %d addresses starting at %012llx\n",
+ (long long unsigned int)mp->SA, mp->requested_count,
+ (long long unsigned int)mp->requested_start_address);
+
+ /* Make sure the address range has changed */
+ if (mp->requested_start_address == start) {
+ fprintf(stderr, "Test 1: FAIL - Got a probe for the same range.\n");
+ exit(2);
+ }
+
+ /* Success! */
+ printf("Test 1: PASS\n");
+
+ test2_setup();
+
+ break;
+ }
+
+ return 0;
+}
+
+void test1_setup(void) {
+ test_state.state = WAITING_FOR_1ST_PROBE;
+ test_state.pkt_handler = test1_handler;
+ printf("Starting test 1: responding to a defend packet while probing\n");
+}
+
+/*
+ * Test 2
+ */
+
+/* Wait for an announce, send a probe for the same range, ensure we get a
+ * defend for the range */
+
+#define WAITING_FOR_ANNOUNCE 0
+#define WAITING_FOR_DEFEND 1
+
+int test2_handler(maap_packet_t *mp) {
+ static uint64_t start;
+ static uint16_t count;
+
+ switch (test_state.state) {
+
+ case WAITING_FOR_ANNOUNCE:
+ if (mp->message_type != MAAP_ANNOUNCE) {
+ /* Ignore non-announce packets */
+ break;
+ }
+ printf("Received an announce from %012llx for %d addresses starting at %012llx\n",
+ (long long unsigned int)mp->SA, mp->requested_count,
+ (long long unsigned int)mp->requested_start_address);
+
+ /* Store the range from the ANNOUNCE so we can check the defense of this
+ range */
+ start = mp->requested_start_address;
+ count = mp->requested_count;
+
+ /* Send a probe for this range */
+ mp->message_type = MAAP_PROBE;
+ send_packet(test_state.rawsock, mp);
+ printf("Sent probe packet\n");
+
+ /* Update testing state */
+ test_state.state = WAITING_FOR_DEFEND;
+
+ break;
+
+ case WAITING_FOR_DEFEND:
+ if (mp->message_type != MAAP_DEFEND) {
+ fprintf(stderr, "Test 2: FAIL - Got a non-defend packet, type %d.\n",
+ mp->message_type);
+ exit(2);
+ }
+ if (mp->requested_start_address != start) {
+ fprintf(stderr, "Test 2: FAIL - Requested start address wasn't filled out with the value from the probe.\n");
+ fprintf(stderr, "Req start address: %012llx Probe address: %012llx\n",
+ (unsigned long long)mp->requested_start_address,
+ (unsigned long long)start);
+ exit(2);
+ }
+ if (mp->requested_count != count) {
+ fprintf(stderr, "Test 2: FAIL - Requested count wasn't filled out with the value from the probe.\n");
+ fprintf(stderr, "Requested count: %d Probe count: %d\n",
+ mp->requested_count, count);
+ exit(2);
+ }
+ if (mp->start_address != start) {
+ fprintf(stderr, "Test 2: FAIL - Start address wasn't filled out with the first conflicting address from the probe.\n");
+ fprintf(stderr, "Start address: %012llx Conflicting address: %012llx\n",
+ (unsigned long long)mp->start_address,
+ (unsigned long long)start);
+ exit(2);
+ }
+ if (mp->count != count) {
+ fprintf(stderr, "Test 2: FAIL - Count wasn't filled out with the number of addresses conflicting with the probe.\n");
+ fprintf(stderr, "Defend count: %d Conflicting count: %d\n", mp->count, count);
+ exit(2);
+ }
+
+ /* Success! */
+ printf("Test 2: PASS\n");
+
+ test3_setup();
+
+ break;
+
+ }
+
+ return 0;
+}
+
+void test2_setup(void) {
+ test_state.state = WAITING_FOR_ANNOUNCE;
+ test_state.pkt_handler = test2_handler;
+ printf("Starting test 2: defending a reservation from a probe\n");
+ printf("Waiting for an announce packet...");
+}
+
+/*
+ * Test 3
+ */
+
+#define WAITING_FOR_PROBE 2
+
+int test3_handler(maap_packet_t *mp) {
+ static uint64_t start;
+ static uint16_t count;
+ static maap_packet_t saved_announce;
+
+ switch (test_state.state) {
+
+ case WAITING_FOR_ANNOUNCE:
+ if (mp->message_type != MAAP_ANNOUNCE) {
+ /* Ignore non-announce packets */
+ break;
+ }
+ printf("Received an announce from %012llx for %d addresses starting at %012llx\n",
+ (long long unsigned int)mp->SA, mp->requested_count,
+ (long long unsigned int)mp->requested_start_address);
+
+ /* Store the range from the ANNOUNCE so we can check the defense of this
+ range */
+ start = mp->requested_start_address;
+ count = mp->requested_count;
+
+ /* Send an announce for this range (send the same packet right back) */
+ send_packet(test_state.rawsock, mp);
+ printf("Sent announce packet\n");
+
+ /* Save a copy so we can send it again */
+ memcpy(&saved_announce, mp, sizeof (maap_packet_t));
+
+ /* Update testing state */
+ test_state.state = WAITING_FOR_DEFEND;
+
+ break;
+
+ case WAITING_FOR_DEFEND:
+ if (mp->message_type != MAAP_DEFEND) {
+ fprintf(stderr, "test 3: FAIL - Got a non-defend packet, type %d.\n",
+ mp->message_type);
+ exit(2);
+ }
+ if (mp->requested_start_address != start) {
+ fprintf(stderr, "test 3: FAIL - Requested start address wasn't filled out with the value from the probe.\n");
+ fprintf(stderr, "Req start address: %012llx Probe address: %012llx\n",
+ (unsigned long long)mp->requested_start_address,
+ (unsigned long long)start);
+ exit(2);
+ }
+ if (mp->requested_count != count) {
+ fprintf(stderr, "test 3: FAIL - Requested count wasn't filled out with the value from the probe.\n");
+ fprintf(stderr, "Requested count: %d Probe count: %d\n",
+ mp->requested_count, count);
+ exit(2);
+ }
+ if (mp->start_address != start) {
+ fprintf(stderr, "test 3: FAIL - Start address wasn't filled out with the first conflicting address from the probe.\n");
+ fprintf(stderr, "Start address: %012llx Conflicting address: %012llx\n",
+ (unsigned long long)mp->start_address,
+ (unsigned long long)start);
+ exit(2);
+ }
+ if (mp->count != count) {
+ fprintf(stderr, "test 3: FAIL - Count wasn't filled out with the number of addresses conflicting with the probe.\n");
+ fprintf(stderr, "Defend count: %d Conflicting count: %d\n", mp->count, count);
+ exit(2);
+ }
+
+ /* Send out the same announce again */
+ send_packet(test_state.rawsock, &saved_announce);
+ printf("Sent second announce\n");
+
+ /* Update testing state */
+ test_state.state = WAITING_FOR_PROBE;
+
+ break;
+
+ case WAITING_FOR_PROBE:
+ /* Make sure we got a probe in response */
+ if (mp->message_type != MAAP_PROBE) {
+ fprintf(stderr, "Test 3: FAIL - Got a non-probe packet, type %d.\n",
+ mp->message_type);
+ exit(2);
+ }
+
+ printf("Received a probe from %012llx for %d addresses starting at %012llx\n",
+ (long long unsigned int)mp->SA, mp->requested_count,
+ (long long unsigned int)mp->requested_start_address);
+
+ /* Make sure the address range has changed */
+ if (mp->requested_start_address == start) {
+ fprintf(stderr, "Test 3: FAIL - Got a probe for the same range.\n");
+ exit(2);
+ }
+
+ /* Success! */
+ printf("Test 3: PASS\n");
+
+ delay_setup();
+
+ break;
+
+ }
+
+ return 0;
+}
+
+void test3_setup(void) {
+ test_state.state = WAITING_FOR_ANNOUNCE;
+ test_state.pkt_handler = test3_handler;
+ printf("Starting Test 3: yielding a reservation after 2 announces\n");
+ printf("Waiting for an announce packet...\n");
+}
+
+int delay_handler(maap_packet_t *mp) {
+ if (mp->message_type == MAAP_ANNOUNCE) {
+ test_state.state += 1;
+ if (test_state.state == 10) {
+ printf("Received 10 Announce messages.\n");
+ test3_setup();
+ }
+ }
+ return 0;
+}
+
+void delay_setup(void) {
+ test_state.state = 0;
+ test_state.pkt_handler = delay_handler;
+ printf("Waiting for ~5min (10 Announces)\n");
+}
diff --git a/daemons/maap/test/maap_timer_dummy.c b/daemons/maap/test/maap_timer_dummy.c
new file mode 100644
index 00000000..243b3265
--- /dev/null
+++ b/daemons/maap/test/maap_timer_dummy.c
@@ -0,0 +1,165 @@
+/*************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <time.h>
+
+#include "platform.h"
+
+struct testtime {
+ unsigned long sec;
+ unsigned long nsec;
+};
+
+/* Use our local time structure rather than the OS-specific one. */
+#undef OS_TIME_TYPE
+#define OS_TIME_TYPE struct testtime
+
+#include "maap_timer.h"
+
+
+struct maap_timer {
+ int timer_id;
+ struct testtime expires;
+};
+
+static unsigned long long s_basetime = 1000000000LL;
+
+
+Timer *Time_newTimer(void)
+{
+ static int s_new_timer_id = 0;
+
+ Timer *newTimer = malloc(sizeof (Timer));
+ if (newTimer) {
+ newTimer->timer_id = ++s_new_timer_id;
+ newTimer->expires.sec = newTimer->expires.nsec = 0;
+ }
+ return newTimer;
+}
+
+void Time_delTimer(Timer *timer)
+{
+ assert(timer);
+ assert(timer->timer_id);
+ free(timer);
+}
+
+void Time_setTimer(Timer *timer, const Time *t)
+{
+ assert(timer);
+ assert(timer->timer_id);
+ assert(t);
+ timer->expires.sec = t->sec;
+ timer->expires.nsec = t->nsec;
+}
+
+int64_t Time_remaining(Timer *timer)
+{
+ Time timeCurrent;
+ int64_t timeRemaining;
+
+ assert(timer);
+ assert(timer->timer_id);
+ assert(timer->expires.sec || timer->expires.nsec);
+ Time_setFromMonotonicTimer(&timeCurrent);
+ timeRemaining = ((int64_t) timer->expires.sec - (int64_t) timeCurrent.sec) * 1000000000LL + ((int64_t) timer->expires.nsec - (int64_t) timeCurrent.nsec);
+ return (timeRemaining > 0LL ? timeRemaining : 0LL);
+}
+
+void Time_add(Time *a, const Time *b)
+{
+ a->sec = a->sec + b->sec;
+ a->nsec = a->nsec + b->nsec;
+ if (a->nsec > 1000000000L) {
+ a->sec++;
+ a->nsec = a->nsec - 1000000000L;
+ }
+}
+
+int64_t Time_diff(const Time *a, const Time *b)
+{
+ int64_t a_ns = (int64_t) a->sec * 1000000000LL + (int64_t) a->nsec;
+ int64_t b_ns = (int64_t) b->sec * 1000000000LL + (int64_t) b->nsec;
+ return b_ns - a_ns;
+}
+
+int Time_cmp(const Time *a, const Time *b)
+{
+ if (a->sec < b->sec) {
+ return -1;
+ }
+ if (a->sec > b->sec) {
+ return 1;
+ }
+ if (a->nsec < b->nsec) {
+ return -1;
+ }
+ if (a->nsec > b->nsec) {
+ return 1;
+ }
+ return 0;
+}
+
+int Time_passed(const Time *current, const Time *target)
+{
+ if (current->sec < target->sec) {
+ return 0;
+ }
+ if (current->sec == target->sec && current->nsec < target->nsec) {
+ return 0;
+ }
+ return 1;
+}
+
+void Time_setFromNanos(Time *t, uint64_t nsec)
+{
+ t->sec = (unsigned long) (nsec / 1000000000LL);
+ t->nsec = (unsigned long) (nsec % 1000000000LL);
+}
+
+void Time_setFromMonotonicTimer(Time *t)
+{
+ /* Use a hard-wired value. */
+ t->sec = (unsigned long) (s_basetime / 1000000000LL);
+ t->nsec = (unsigned long) (s_basetime % 1000000000LL);
+}
+
+const char * Time_dump(const Time *t)
+{
+ static char buffer[40];
+ sprintf(buffer, "%lu sec, %09lu nsec", t->sec, t->nsec);
+ return buffer;
+}
+
+
+/* Special function used for testing only. */
+void Time_increaseNanos(uint64_t nsec)
+{
+ assert(nsec < 60LL * 1000000000LL);
+ s_basetime += nsec;
+}
diff --git a/daemons/maap/test/maap_timer_dummy.h b/daemons/maap/test/maap_timer_dummy.h
new file mode 100644
index 00000000..a74e6cc1
--- /dev/null
+++ b/daemons/maap/test/maap_timer_dummy.h
@@ -0,0 +1,47 @@
+/*************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************/
+
+/**
+ * @file
+ *
+ * @brief Support for timer operations unit tests
+ *
+ * These functions support additional functions used by unit tests for timing operations.
+ */
+
+#ifndef MAAP_TIMER_DUMMY_H
+#define MAAP_TIMER_DUMMY_H
+
+#include <stdint.h>
+
+
+/**
+ * Advance the internal time by the number of nanoseconds.
+ *
+ * @param nsec Number of nanoseconds to advance the internal time
+ */
+void Time_increaseNanos(uint64_t nsec);
+
+#endif
diff --git a/daemons/maap/test/test_intervals.c b/daemons/maap/test/test_intervals.c
new file mode 100644
index 00000000..f09934cd
--- /dev/null
+++ b/daemons/maap/test/test_intervals.c
@@ -0,0 +1,223 @@
+/*************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include "intervals.h"
+
+#ifdef _WIN32
+/* Windows-specific header values */
+#define random() rand()
+#define srandom(s) srand(s)
+#endif
+
+#define INTERVALS_TO_ADD 1000
+#define INTERVALS_TO_REPLACE 100000
+#define INTERVALS_TO_SEARCH 10000
+
+uint32_t last_high = 0;
+int total = 0;
+
+void print_node(Interval *node) {
+ printf("[%d,%d] ", node->low, node->high);
+ if (node->low <= last_high ||
+ node->high < node->low) {
+ fprintf(stderr, "\nError: <%d,%d>\n", node->low, node->high);
+ exit(1);
+ }
+ last_high = node->high;
+ total++;
+}
+
+int main(void) {
+ Interval *set = NULL, *inter, *over, *prev;
+ int i, rv, count;
+
+ srandom((unsigned int) time(NULL));
+
+ printf("Testing duplicate values\n");
+ inter = alloc_interval(1, 10);
+ rv = insert_interval(&set, inter);
+ if (rv != INTERVAL_SUCCESS) {
+ fprintf(stderr, "Error: Insert of [%d,%d] failed unexpectedly\n", inter->low, inter->high);
+ return 1; /* Error */
+ } else {
+ printf("Inserted [%d,%d]\n", inter->low, inter->high);
+ }
+ inter = alloc_interval(1, 10);
+ rv = insert_interval(&set, inter);
+ if (rv != INTERVAL_OVERLAP) {
+ fprintf(stderr, "Error: Insert of [%d,%d] should have failed, but didn't\n", inter->low, inter->high);
+ return 1; /* Error */
+ } else {
+ printf("Repeat insert of [%d,%d] failed, so the test passed\n", inter->low, inter->high);
+ }
+
+ while (set) {
+ inter = remove_interval(&set, set);
+ free_interval(inter);
+ }
+
+ count = INTERVALS_TO_ADD;
+ printf("\nInserting %d random intervals into a set\n", count);
+
+ for (i = 0; i < count;) {
+ inter = alloc_interval(random() % 0xfffff, random() % 128 + 1);
+ rv = insert_interval(&set, inter);
+ if (rv == INTERVAL_OVERLAP) {
+ over = search_interval(set, inter->low, inter->high - inter->low + 1);
+ printf("[%d,%d] overlapped existing entry [%d,%d]\n",
+ inter->low, inter->high, over->low, over->high);
+ free_interval(inter);
+ } else {
+ printf("Inserted [%d,%d]:\n", inter->low, inter->high);
+ i++;
+ }
+ }
+
+ count = INTERVALS_TO_REPLACE;
+ printf("\nReplacing %d random intervals\n", count);
+
+ for (i = 0, over = NULL; i < count;) {
+ if (over) {
+ inter = alloc_interval(random() % 0xfffff, random() % 128 + 1);
+ rv = insert_interval(&set, inter);
+ if (rv == INTERVAL_SUCCESS) {
+ printf("Replaced [%d,%d] with [%d,%d]\n",
+ over->low, over->high, inter->low, inter->high);
+ free_interval(over);
+ over = NULL;
+ i++;
+ } else {
+ printf("Overlapping replacement interval\n");
+ free_interval(inter);
+ }
+ } else {
+ over = search_interval(set, random() % 0xfffff, random() % 128 + 1);
+ if (over) over = remove_interval(&set, over);
+ }
+ }
+
+ /* Test that searches always return the first match */
+ for (i = 0; i < INTERVALS_TO_SEARCH; i++) {
+ uint32_t search_base = random() % 0xfffff;
+ uint32_t search_size = random() % 2048 + 1;
+ inter = search_interval(set, search_base, search_size);
+ if (inter && !interval_check_overlap(inter, search_base, search_size)) {
+ fprintf(stderr, "Error: Search compare failure\n");
+ return 1; /* Error */
+ }
+ if (inter && (prev = prev_interval(inter)) != NULL) {
+ if (prev->high >= search_base) {
+ fprintf(stderr, "Error: Search lowest item failure\n");
+ return 1; /* Error */
+ }
+ if (interval_check_overlap(prev, search_base, search_size)) {
+ fprintf(stderr, "Error: interval_check_overlap compare failure\n");
+ return 1; /* Error */
+ }
+ }
+ }
+ printf("\n" "search_interval testing passed\n");
+
+ /* Test next_interval and search_interval */
+ i = 0;
+ count = INTERVALS_TO_ADD;
+ inter = minimum_interval(set);
+ prev = NULL;
+ while (inter) {
+ i++;
+ if (prev && prev->high >= inter->low) {
+ fprintf(stderr, "Error: Overlapping or out-of-order interval detected\n");
+ return 1; /* Error */
+ }
+ if (search_interval(set, inter->low, 1) != inter) {
+ fprintf(stderr, "Error: Search for interval [%d,%d] failed\n", inter->low, inter->high);
+ return 1; /* Error */
+ }
+ prev = inter;
+ inter = next_interval(inter);
+ }
+ if (i != count) {
+ fprintf(stderr, "Error: Found %d intervals during next_interval interation\n", i);
+ return 1; /* Error */
+ }
+ if (prev != maximum_interval(set)) {
+ fprintf(stderr, "Error: next_interval iteration didn't end at maximum_interval\n");
+ return 1; /* Error */
+ }
+ printf("\n" "next_interval testing passed\n");
+
+ /* Test previous_interval and search_interval */
+ i = 0;
+ count = INTERVALS_TO_ADD;
+ inter = maximum_interval(set);
+ prev = NULL;
+ while (inter) {
+ i++;
+ if (prev && prev->low <= inter->high) {
+ fprintf(stderr, "Error: Overlapping or out-of-order interval detected\n");
+ return 1; /* Error */
+ }
+ if (search_interval(set, inter->high, 1) != inter) {
+ fprintf(stderr, "Error: Search for interval [%d,%d] failed\n", inter->low, inter->high);
+ return 1; /* Error */
+ }
+ prev = inter;
+ inter = prev_interval(inter);
+ }
+ if (i != count) {
+ fprintf(stderr, "Error: Found %d intervals during next_interval interation\n", i);
+ return 1; /* Error */
+ }
+ if (prev != minimum_interval(set)) {
+ fprintf(stderr, "Error: prev_interval iteration didn't end at minimum_interval\n");
+ return 1; /* Error */
+ }
+ printf("\n" "previous_interval testing passed\n");
+
+ inter = minimum_interval(set);
+ printf("\nMinimum Interval: [%d,%d]\n", inter->low, inter->high);
+ inter = maximum_interval(set);
+ printf("Maximum Interval: [%d,%d]\n", inter->low, inter->high);
+
+ printf("\nFinal set:\n");
+ traverse_interval(set, print_node);
+ printf("\n\nTotal members: %d\n\n", total);
+
+ if (total != INTERVALS_TO_ADD) {
+ fprintf(stderr, "Error: Had %d intervals, rather an the expected %d\n", total, INTERVALS_TO_ADD);
+ return 1; /* Error */
+ }
+
+ while (set) {
+ inter = remove_interval(&set, set);
+ free_interval(inter);
+ }
+
+ fprintf(stderr, "Tests passed.\n");
+ return 0;
+}
diff --git a/daemons/maap/tests/AllTests.cpp b/daemons/maap/tests/AllTests.cpp
new file mode 100644
index 00000000..26d20f12
--- /dev/null
+++ b/daemons/maap/tests/AllTests.cpp
@@ -0,0 +1,39 @@
+/****************************************************************************
+ Copyright (c) 2014, J.D. Koftinoff Software, Ltd.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of J.D. Koftinoff Software, Ltd. nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+******************************************************************************/
+
+#include "CppUTest/TestHarness.h"
+#include "CppUTest/CommandLineTestRunner.h"
+
+int main(int ac, char **av)
+{
+ return CommandLineTestRunner::RunAllTests(ac, av);
+}
diff --git a/daemons/maap/tests/CMakeLists.txt b/daemons/maap/tests/CMakeLists.txt
new file mode 100644
index 00000000..a47ad885
--- /dev/null
+++ b/daemons/maap/tests/CMakeLists.txt
@@ -0,0 +1,38 @@
+cmake_minimum_required (VERSION 2.8)
+project (maap_test)
+enable_testing()
+
+set (CPPUTEST_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../thirdparty/cpputest" )
+set (SRC_DIR "../common" )
+set (TEST_DIR "../test" )
+add_definitions(-DMRP_CPPUTEST)
+
+include_directories( . "${CMAKE_CURRENT_LIST_DIR}/../common/" ${CPPUTEST_DIR}/include )
+file(GLOB CPPUTEST_SRC *.cpp)
+file(GLOB MAAP_SRC ${SRC_DIR}/intervals.c ${SRC_DIR}/maap.c ${SRC_DIR}/maap_log_queue.c ${SRC_DIR}/maap_net.c ${SRC_DIR}/maap_packet.c ${SRC_DIR}/maap_parse.c)
+file(GLOB MAAP_TEST_SRC ${TEST_DIR}/maap_log_dummy.c ${TEST_DIR}/maap_timer_dummy.c)
+
+if(APPLE)
+ include_directories( include ${SRC_DIR} ${CPPUTEST_DIR}/include/Platforms/Gcc )
+ link_directories(${CPPUTEST_DIR}/src/CppUTest ${CPPUTEST_DIR}/src/CppUTestExt )
+ add_executable (maap_test ${MAAP_SRC} ${MAAP_TEST_SRC} ${CPPUTEST_SRC} )
+ target_link_libraries(maap_test CppUTest CppUTestExt)
+elseif(UNIX)
+ include_directories( include ${SRC_DIR} ${CPPUTEST_DIR}/include/Platforms/Gcc )
+ link_directories(${CPPUTEST_DIR}/src/CppUTest ${CPPUTEST_DIR}/src/CppUTestExt )
+ add_executable (maap_test ${MAAP_SRC} ${MAAP_TEST_SRC} ${CPPUTEST_SRC} )
+ target_link_libraries(maap_test CppUTest CppUTestExt)
+elseif(WIN32)
+ if( CMAKE_SIZEOF_VOID_P EQUAL 8 )
+ link_directories($ENV{WPCAP_DIR}/Lib/x64 ${CPPUTEST_DIR}/src/CppUTest ${CPPUTEST_DIR}/src/CppUTestExt)
+ elseif( CMAKE_SIZEOF_VOID_P EQUAL 4 )
+ link_directories($ENV{WPCAP_DIR}/Lib ${CPPUTEST_DIR}/src/CppUTest ${CPPUTEST_DIR}/src/CppUTestExt)
+ endif()
+
+ add_definitions(-D_CRT_SECURE_NO_WARNINGS)
+ add_executable (maap_test ${MAAP_SRC} ${MAAP_TEST_SRC} ${CPPUTEST_SRC} )
+ target_link_libraries(maap_test CppUTest CppUTestExt Ws2_32 Winmm)
+endif()
+
+add_test( maap_test maap_test )
+
diff --git a/daemons/maap/tests/maap_net_tests.cpp b/daemons/maap/tests/maap_net_tests.cpp
new file mode 100644
index 00000000..ce666fbd
--- /dev/null
+++ b/daemons/maap/tests/maap_net_tests.cpp
@@ -0,0 +1,135 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "CppUTest/TestHarness.h"
+
+extern "C" {
+
+#include "maap_net.h"
+
+}
+
+/* Number of items to test in a group.
+ * This should be greater than NUM_BUFFERS in maap_net.c */
+#define GROUP_TEST_SIZE 100
+
+TEST_GROUP(maap_net_group)
+{
+ void setup() {
+ }
+
+ void teardown() {
+ }
+};
+
+TEST(maap_net_group, Single_Item)
+{
+ Net * net;
+ int *buffer;
+
+ net = Net_newNet();
+ CHECK(net != NULL);
+
+ /* Make sure the queue is empty. */
+ CHECK(Net_getNextQueuedPacket(net) == NULL);
+
+ /* Put a buffer in the queue. */
+ buffer = (int*) Net_getPacketBuffer(net);
+ CHECK(buffer != NULL);
+ *buffer = 0x1234;
+ LONGS_EQUAL(0, Net_queuePacket(net, buffer));
+
+ /* Get the buffer from the queue. */
+ /* Note that we don't assume this is the same buffer pointer that we queued. */
+ buffer = (int*) Net_getNextQueuedPacket(net);
+ CHECK(buffer != NULL);
+ LONGS_EQUAL(0x1234, *buffer);
+ LONGS_EQUAL(0, Net_freeQueuedPacket(net, buffer));
+
+ /* Make sure the queue is empty. */
+ CHECK(Net_getNextQueuedPacket(net) == NULL);
+
+ Net_delNet(net);
+}
+
+TEST(maap_net_group, Queue_Singly)
+{
+ Net * net;
+ int *buffer;
+ int i;
+
+ net = Net_newNet();
+ CHECK(net != NULL);
+
+ /* Make sure the queue is empty. */
+ CHECK(Net_getNextQueuedPacket(net) == NULL);
+
+ /* Put some buffers in the queue. */
+ /* Queue each item before going to the next item. */
+ for (i = 0; i < GROUP_TEST_SIZE; i++)
+ {
+ buffer = (int*) Net_getPacketBuffer(net);
+ CHECK(buffer != NULL);
+ *buffer = i;
+ LONGS_EQUAL(0, Net_queuePacket(net, buffer));
+ }
+
+ /* Get each buffer from the queue. */
+ /* Free each item before going to the next item. */
+ for (i = 0; i < GROUP_TEST_SIZE; i++)
+ {
+ buffer = (int*) Net_getNextQueuedPacket(net);
+ CHECK(buffer != NULL);
+ LONGS_EQUAL(i, *buffer);
+ LONGS_EQUAL(0, Net_freeQueuedPacket(net, buffer));
+ }
+
+ /* Make sure the queue is empty. */
+ CHECK(Net_getNextQueuedPacket(net) == NULL);
+
+ Net_delNet(net);
+}
+
+TEST(maap_net_group, Queue_Block)
+{
+ Net * net;
+ int *buffer[GROUP_TEST_SIZE];
+ int i;
+
+ net = Net_newNet();
+ CHECK(net != NULL);
+
+ /* Make sure the queue is empty. */
+ CHECK(Net_getNextQueuedPacket(net) == NULL);
+
+ /* Put some buffers in the queue. */
+ /* Get all the buffers before queuing the buffers. */
+ for (i = 0; i < GROUP_TEST_SIZE; i++)
+ {
+ buffer[i] = (int*) Net_getPacketBuffer(net);
+ CHECK(buffer[i] != NULL);
+ *(buffer[i]) = i;
+ }
+ for (i = 0; i < GROUP_TEST_SIZE; i++)
+ {
+ LONGS_EQUAL(0, Net_queuePacket(net, buffer[i]));
+ }
+
+ /* Get each buffer from the queue. */
+ /* Dequeue all the buffers before freeing the buffers. */
+ for (i = 0; i < GROUP_TEST_SIZE; i++)
+ {
+ buffer[i] = (int*) Net_getNextQueuedPacket(net);
+ CHECK(buffer[i] != NULL);
+ LONGS_EQUAL(i, *(buffer[i]));
+ }
+ for (i = 0; i < GROUP_TEST_SIZE; i++)
+ {
+ LONGS_EQUAL(0, Net_freeQueuedPacket(net, buffer[i]));
+ }
+
+ /* Make sure the queue is empty. */
+ CHECK(Net_getNextQueuedPacket(net) == NULL);
+
+ Net_delNet(net);
+}
diff --git a/daemons/maap/tests/maap_packet_tests.cpp b/daemons/maap/tests/maap_packet_tests.cpp
new file mode 100644
index 00000000..a9104ac5
--- /dev/null
+++ b/daemons/maap/tests/maap_packet_tests.cpp
@@ -0,0 +1,184 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "CppUTest/TestHarness.h"
+
+extern "C" {
+
+#include "maap.h"
+#include "maap_packet.h"
+
+static uint8_t test_stream[] = {
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x06, 0x05,
+ 0x04, 0x03, 0x02, 0x01,
+ 0x12, 0x34,
+ 0xfe, 0x11, 0x00, 0x10,
+ 0x01, 0x23, 0x45, 0x67,
+ 0x89, 0xab, 0xcd, 0xef,
+ 0xcb, 0xfe, 0x12, 0x34,
+ 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+static MAAP_Packet test_packet = {
+ 0x010203040506,
+ 0x060504030201,
+ 0x1234,
+ 0xfe,
+ 0,
+ 1,
+ 1,
+ 0,
+ 16,
+ 0x0123456789abcdef,
+ 0xcbfe12340000,
+ 255,
+ 0x000000000000,
+ 0
+};
+
+static MAAP_Packet initialized_packet = {
+ 0x020304050607,
+ 0x070605040302,
+ 0x22F0, /* Ethertype */
+ 0xFE, /* subtype */
+ 0, /* SV */
+ 0, /* version */
+ 0, /* message_type */
+ 1, /* maap_version */
+ 16, /* control_data_length */
+ 0, /* stream_id */
+ 0, /* requested_start_address */
+ 0, /* requested_count */
+ 0, /* conflict_start_address */
+ 0 /* conflict_count */
+};
+
+static void dump_stream(uint8_t *stream) {
+ int i;
+ for (i = 0; i < 42; i++) {
+ if (i % 4 == 0) {
+ printf("\n");
+ }
+ printf("%02x ", stream[i]);
+ }
+ printf("\n");
+}
+
+static void cmp_maap_packets(MAAP_Packet *a, MAAP_Packet *b) {
+ CHECK(a->DA == b->DA);
+ CHECK(a->SA == b->SA);
+ CHECK(a->Ethertype == b->Ethertype);
+ CHECK(a->subtype == b->subtype);
+ CHECK(a->SV == b->SV);
+ CHECK(a->version == b->version);
+ CHECK(a->message_type == b->message_type);
+ CHECK(a->maap_version == b->maap_version);
+ CHECK(a->control_data_length && b->control_data_length);
+ CHECK(a->stream_id == b->stream_id);
+ CHECK(a->requested_start_address == b->requested_start_address);
+ CHECK(a->requested_count == b->requested_count);
+ CHECK(a->conflict_start_address == b->conflict_start_address);
+ CHECK(a->conflict_count == b->conflict_count);
+}
+
+static void dump_maap_packet(MAAP_Packet *packet) {
+ printf("DA: %012llx\n", (unsigned long long int)packet->DA);
+ printf("SA: %012llx\n", (unsigned long long int)packet->SA);
+ printf("Ethertype: %04x\n", packet->Ethertype);
+ printf("subtype: %d\n", packet->subtype);
+ printf("SV: %d\n", packet->SV);
+ printf("version: %d\n", packet->version);
+ printf("message_type: %d\n", packet->message_type);
+ printf("maap_version: %d\n", packet->maap_version);
+ printf("control_data_length: %d\n", packet->control_data_length);
+ printf("stream_id: 0x%016llx\n",
+ (unsigned long long int)packet->stream_id);
+ printf("requested_start_address: 0x%012llx\n",
+ (unsigned long long int)packet->requested_start_address);
+ printf("requested_count: %d\n", packet->requested_count);
+ printf("conflict_start_address: 0x%012llx\n",
+ (unsigned long long int)packet->conflict_start_address);
+ printf("conflict_count: %d\n", packet->conflict_count);
+}
+
+
+} TEST_GROUP(maap_packet_group)
+{
+ void setup() {
+ }
+
+ void teardown() {
+ }
+};
+
+TEST(maap_packet_group, Init)
+{
+ MAAP_Packet result;
+
+ init_packet(&result, 0x020304050607, 0x070605040302);
+ cmp_maap_packets(&result, &initialized_packet);
+}
+
+TEST(maap_packet_group, Unpack)
+{
+ uint8_t buffer[42] = {0};
+ MAAP_Packet result;
+
+ unpack_maap(&result, test_stream);
+ cmp_maap_packets(&result, &test_packet);
+}
+
+TEST(maap_packet_group, Pack)
+{
+ uint8_t buffer[42] = {0};
+
+ pack_maap(&test_packet, buffer);
+ LONGS_EQUAL(0, memcmp(test_stream, buffer, 42));
+}
+
+TEST(maap_packet_group, Convert)
+{
+ uint8_t testaddr[6] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc};
+ unsigned long long result = convert_mac_address(testaddr);
+ CHECK(result == 0x123456789abcLL);
+}
+
+TEST(maap_packet_group, Compare_MAC)
+{
+ uint64_t local_mac, remote_mac;
+
+ local_mac = 0xffffffffff01;
+ remote_mac = 0x000000000002;
+ LONGS_EQUAL(1, compare_mac_addresses(local_mac, remote_mac));
+
+ local_mac = 0x000000000002;
+ remote_mac = 0xffffffffff01;
+ LONGS_EQUAL(0, compare_mac_addresses(local_mac, remote_mac));
+
+ local_mac = 0x000000000000;
+ remote_mac = 0xffffffffffff;
+ LONGS_EQUAL(1, compare_mac_addresses(local_mac, remote_mac));
+
+ local_mac = 0xffffffffffff;
+ remote_mac = 0x000000000000;
+ LONGS_EQUAL(0, compare_mac_addresses(local_mac, remote_mac));
+
+ local_mac = 0x112233445566;
+ remote_mac = 0x112277445566;
+ LONGS_EQUAL(1, compare_mac_addresses(local_mac, remote_mac));
+
+ local_mac = 0x112233445566;
+ remote_mac = 0x112200445566;
+ LONGS_EQUAL(0, compare_mac_addresses(local_mac, remote_mac));
+
+ local_mac = 0x102233445566;
+ remote_mac = 0x112233445566;
+ LONGS_EQUAL(1, compare_mac_addresses(local_mac, remote_mac));
+
+ local_mac = 0x112233445566;
+ remote_mac = 0x102233445566;
+ LONGS_EQUAL(0, compare_mac_addresses(local_mac, remote_mac));
+}
diff --git a/daemons/maap/tests/maap_tests.cpp b/daemons/maap/tests/maap_tests.cpp
new file mode 100644
index 00000000..7f276df5
--- /dev/null
+++ b/daemons/maap/tests/maap_tests.cpp
@@ -0,0 +1,1467 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "CppUTest/TestHarness.h"
+
+extern "C" {
+
+#include "maap.h"
+#include "maap_packet.h"
+#include "../test/maap_log_dummy.h"
+#include "../test/maap_timer_dummy.h"
+
+#ifdef _WIN32
+ /* Windows-specific header values */
+#define random() rand()
+#define srandom(s) srand(s)
+#endif
+
+#define TEST_DEST_ADDR 0x91E0F000FF00
+#define TEST_SRC_ADDR 0x123456789abc
+
+#define TEST_REMOTE_ADDR_LOWER 0x777777777777 /* Remote address that we should defer to */
+#define TEST_REMOTE_ADDR_HIGHER 0x1111111111ee /* Remote address that we should ignore */
+
+
+static void verify_sent_packets(Maap_Client *p_mc, Maap_Notify *p_mn,
+ const void **p_sender_out,
+ int *p_probe_packets_detected, int *p_announce_packets_detected,
+ int send_probe /* = -1 */, int send_announce /* = -1 */, int send_defend /* = -1 */,
+ uint64_t remote_addr, int stop_after_probe);
+
+
+} TEST_GROUP(maap_group)
+{
+ void setup() {
+ /* Try a variety of "random" values over subsequent tests. */
+ srandom((unsigned int) time(NULL));
+ }
+
+ void teardown() {
+ }
+};
+
+TEST(maap_group, Init)
+{
+ const uint64_t range_base_addr = MAAP_DYNAMIC_POOL_BASE + 0x1000;
+ const uint32_t range_size = MAAP_DYNAMIC_POOL_SIZE - 0x800;
+ Maap_Client mc;
+ Maap_Notify mn;
+ const int sender1_in = 1, sender2_in = 2, sender3_in = 3;
+ const void *sender_out;
+
+ /* Initialize the Maap_Client structure */
+ memset(&mc, 0, sizeof(Maap_Client));
+ mc.dest_mac = TEST_DEST_ADDR;
+ mc.src_mac = TEST_SRC_ADDR;
+
+ /* Test the maap_init_client() function */
+ LONGS_EQUAL(0, maap_init_client(&mc, &sender1_in, range_base_addr, range_size));
+ LONGS_EQUAL(range_base_addr, mc.address_base);
+ LONGS_EQUAL(range_size, mc.range_len);
+ CHECK(mc.ranges == NULL);
+ CHECK(mc.timer_queue == NULL);
+ CHECK(mc.timer != NULL);
+ CHECK(mc.net != NULL);
+ CHECK(mc.initialized);
+
+ /* We should receive exactly one notification of the initialization. */
+ sender_out = NULL;
+ memset(&mn, 0, sizeof(Maap_Notify));
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ CHECK(sender_out == &sender1_in);
+ LONGS_EQUAL(MAAP_NOTIFY_INITIALIZED, mn.kind);
+ LONGS_EQUAL(-1, mn.id);
+ LONGS_EQUAL(range_base_addr, mn.start);
+ LONGS_EQUAL(range_size, mn.count);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+ /* Test the maap_init_client() function again with the same information */
+ LONGS_EQUAL(0, maap_init_client(&mc, &sender2_in, range_base_addr, range_size));
+ LONGS_EQUAL(range_base_addr, mc.address_base);
+ LONGS_EQUAL(range_size, mc.range_len);
+ CHECK(mc.ranges == NULL);
+ CHECK(mc.timer_queue == NULL);
+ CHECK(mc.timer != NULL);
+ CHECK(mc.net != NULL);
+ CHECK(mc.initialized);
+
+ /* We should receive exactly one notification of the initialization. */
+ sender_out = NULL;
+ memset(&mn, 0, sizeof(Maap_Notify));
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ CHECK(sender_out == &sender2_in);
+ LONGS_EQUAL(MAAP_NOTIFY_INITIALIZED, mn.kind);
+ LONGS_EQUAL(-1, mn.id);
+ LONGS_EQUAL(range_base_addr, mn.start);
+ LONGS_EQUAL(range_size, mn.count);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+ /* Test the maap_init_client() function again with different information */
+ LONGS_EQUAL(-1, maap_init_client(&mc, &sender3_in, range_base_addr + 1, range_size));
+ LONGS_EQUAL(range_base_addr, mc.address_base);
+ LONGS_EQUAL(range_size, mc.range_len);
+ CHECK(mc.ranges == NULL);
+ CHECK(mc.timer_queue == NULL);
+ CHECK(mc.timer != NULL);
+ CHECK(mc.net != NULL);
+ CHECK(mc.initialized);
+
+ /* We should receive exactly one notification of the initialization error. */
+ sender_out = NULL;
+ memset(&mn, 0, sizeof(Maap_Notify));
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ CHECK(sender_out == &sender3_in);
+ LONGS_EQUAL(MAAP_NOTIFY_INITIALIZED, mn.kind);
+ LONGS_EQUAL(-1, mn.id);
+ LONGS_EQUAL(range_base_addr, mn.start);
+ LONGS_EQUAL(range_size, mn.count);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_ALREADY_INITIALIZED, mn.result);
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+ /* We are done with the Maap_Client structure */
+ maap_deinit_client(&mc);
+}
+
+TEST(maap_group, Reserve_Release)
+{
+ const uint64_t range_base_addr = MAAP_DYNAMIC_POOL_BASE;
+ const uint32_t range_size = MAAP_DYNAMIC_POOL_SIZE;
+ Maap_Client mc;
+ Maap_Notify mn;
+ const int sender1_in = 1, sender2_in = 2, sender3_in = 3;
+ const void *sender_out;
+ int id;
+ uint64_t range_reserved_start;
+ uint32_t range_reserved_count;
+ int probe_packets_detected, announce_packets_detected;
+ int64_t next_delay;
+ void *packet_data = NULL;
+ MAAP_Packet packet_contents;
+
+ /* Initialize the Maap_Client structure */
+ memset(&mc, 0, sizeof(Maap_Client));
+ mc.dest_mac = TEST_DEST_ADDR;
+ mc.src_mac = TEST_SRC_ADDR;
+
+ /* Initialize the range */
+ /* We should receive exactly one notification of the initialization. */
+ LONGS_EQUAL(0, maap_init_client(&mc, &sender1_in, range_base_addr, range_size));
+ sender_out = NULL;
+ memset(&mn, 0, sizeof(Maap_Notify));
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+ /* Reserve most of the range of addresses */
+ id = maap_reserve_range(&mc, &sender2_in, 0, range_size - 4);
+ CHECK(id > 0);
+
+ /* Verify that we get an acquiring notification. */
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ CHECK(sender_out == &sender2_in);
+ LONGS_EQUAL(MAAP_NOTIFY_ACQUIRING, mn.kind);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+
+ /* Verify that the reservation does not yet have a status */
+ maap_range_status(&mc, &sender1_in, id);
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ CHECK(sender_out == &sender1_in);
+ LONGS_EQUAL(MAAP_NOTIFY_STATUS, mn.kind);
+ LONGS_EQUAL(id, mn.id);
+ LONGS_EQUAL(0, mn.start);
+ LONGS_EQUAL(0, mn.count);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_RELEASE_INVALID_ID, mn.result);
+
+ /* Handle any packets generated during the activity.
+ * Stop once we are notified of a result. */
+ verify_sent_packets(&mc, &mn, &sender_out, &probe_packets_detected, &announce_packets_detected, -1, -1, -1, 0, 0);
+ LONGS_EQUAL(4, probe_packets_detected);
+ LONGS_EQUAL(1, announce_packets_detected);
+
+ /* Verify that the notification indicated a successful reservation. */
+ CHECK(sender_out == &sender2_in);
+ LONGS_EQUAL(MAAP_NOTIFY_ACQUIRED, mn.kind);
+ LONGS_EQUAL(id, mn.id);
+ CHECK(mn.start >= range_base_addr);
+ CHECK(mn.start + mn.count - 1 <= range_base_addr + range_size - 1);
+ LONGS_EQUAL(range_size - 4, mn.count);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+ /* Save the results for use later. */
+ range_reserved_start = mn.start;
+ range_reserved_count = mn.count;
+
+
+ /* Wait a while to see if an Announce is sent. */
+ /* Verify that the wait is 30-32 seconds. */
+ next_delay = maap_get_delay_to_next_timer(&mc);
+ CHECK(next_delay > MAAP_ANNOUNCE_INTERVAL_BASE * 1000000LL);
+ CHECK(next_delay < (MAAP_ANNOUNCE_INTERVAL_BASE + MAAP_ANNOUNCE_INTERVAL_VARIATION) * 1000000LL);
+ Time_increaseNanos(next_delay);
+ LONGS_EQUAL(0, maap_handle_timer(&mc));
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+ packet_data = Net_getNextQueuedPacket(mc.net);
+ CHECK(packet_data != NULL);
+ LONGS_EQUAL(0, unpack_maap(&packet_contents, (const uint8_t *) packet_data));
+ CHECK(packet_contents.message_type == MAAP_ANNOUNCE);
+ Net_freeQueuedPacket(mc.net, packet_data);
+
+ /* More time passes.... */
+ CHECK(maap_get_delay_to_next_timer(&mc) > MAAP_ANNOUNCE_INTERVAL_BASE * 1000000LL);
+ Time_increaseNanos(MAAP_ANNOUNCE_INTERVAL_BASE / 2 * 1000000LL);
+ LONGS_EQUAL(0, maap_handle_timer(&mc));
+ CHECK(Net_getNextQueuedPacket(mc.net) == NULL);
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+
+ /* Try another reasonable reservation. It should fail, as there is not enough space available. */
+ LONGS_EQUAL(-1, maap_reserve_range(&mc, &sender3_in, 0, 10));
+
+ /* We should receive exactly one notification of the reservation error. */
+ sender_out = NULL;
+ memset(&mn, 0, sizeof(Maap_Notify));
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ CHECK(sender_out == &sender3_in);
+ LONGS_EQUAL(MAAP_NOTIFY_ACQUIRED, mn.kind);
+ LONGS_EQUAL(-1, mn.id);
+ LONGS_EQUAL(0, mn.start);
+ LONGS_EQUAL(10, mn.count);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_RESERVE_NOT_AVAILABLE, mn.result);
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+
+ /* Verify the status of our existing reservation */
+ maap_range_status(&mc, &sender1_in, id);
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ CHECK(sender_out == &sender1_in);
+ LONGS_EQUAL(MAAP_NOTIFY_STATUS, mn.kind);
+ LONGS_EQUAL(id, mn.id);
+ LONGS_EQUAL(range_reserved_start, mn.start);
+ LONGS_EQUAL(range_reserved_count, mn.count);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+
+ /* Release the first reservation, and verify that we get one notification of the release. */
+ maap_release_range(&mc, &sender2_in, id);
+ sender_out = NULL;
+ memset(&mn, 0, sizeof(Maap_Notify));
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ CHECK(sender_out == &sender2_in);
+ LONGS_EQUAL(MAAP_NOTIFY_RELEASED, mn.kind);
+ LONGS_EQUAL(id, mn.id);
+ CHECK(mn.start >= range_base_addr);
+ CHECK(mn.start + mn.count - 1 <= range_base_addr + range_size - 1);
+ LONGS_EQUAL(range_size - 4, mn.count);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+
+ /* Verify that the status of the reservation is invalid. */
+ maap_range_status(&mc, &sender1_in, id);
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ CHECK(sender_out == &sender1_in);
+ LONGS_EQUAL(MAAP_NOTIFY_STATUS, mn.kind);
+ LONGS_EQUAL(id, mn.id);
+ LONGS_EQUAL(0, mn.start);
+ LONGS_EQUAL(0, mn.count);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_RELEASE_INVALID_ID, mn.result);
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+
+ /* Try our reasonable reservation again. Supply a preferred address. */
+ id = maap_reserve_range(&mc, &sender3_in, range_base_addr + 100, 10);
+ CHECK(id > 0);
+
+ /* Handle any packets generated during the activity.
+ * Stop once we are notified of a result. */
+ verify_sent_packets(&mc, &mn, &sender_out, &probe_packets_detected, &announce_packets_detected, -1, -1, -1, 0, 0);
+ LONGS_EQUAL(4, probe_packets_detected);
+ LONGS_EQUAL(1, announce_packets_detected);
+
+ /* Verify that the notification indicated a successful reservation at the preferred address. */
+ CHECK(sender_out == &sender3_in);
+ LONGS_EQUAL(MAAP_NOTIFY_ACQUIRED, mn.kind);
+ LONGS_EQUAL(id, mn.id);
+ LONGS_EQUAL(range_base_addr + 100, mn.start);
+ LONGS_EQUAL(10, mn.count);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+ /* Save the results for use later. */
+ range_reserved_start = mn.start;
+ range_reserved_count = mn.count;
+
+
+ /* Release the reservation. */
+ maap_release_range(&mc, &sender3_in, id);
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ CHECK(sender_out == &sender3_in);
+ LONGS_EQUAL(MAAP_NOTIFY_RELEASED, mn.kind);
+ LONGS_EQUAL(id, mn.id);
+ LONGS_EQUAL(range_reserved_start, mn.start);
+ LONGS_EQUAL(range_reserved_count, mn.count);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+ CHECK(Net_getNextQueuedPacket(mc.net) == NULL);
+
+ /* Verify that no additional announce packets are sent. */
+ Time_increaseNanos((MAAP_ANNOUNCE_INTERVAL_BASE + MAAP_ANNOUNCE_INTERVAL_VARIATION) * 1000000ull);
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+ CHECK(Net_getNextQueuedPacket(mc.net) == NULL);
+
+ /* We are done with the Maap_Client structure */
+ maap_deinit_client(&mc);
+}
+
+TEST(maap_group, Probing_vs_Probes)
+{
+ const uint64_t range_base_addr = MAAP_DYNAMIC_POOL_BASE;
+ const uint32_t range_size = MAAP_DYNAMIC_POOL_SIZE;
+ Maap_Client mc;
+ Maap_Notify mn;
+ const int sender1_in = 1, sender2_in = 2;
+ const void *sender_out;
+ int id;
+ int probe_packets_detected, announce_packets_detected;
+
+ /* Initialize the Maap_Client structure */
+ memset(&mc, 0, sizeof(Maap_Client));
+ mc.dest_mac = TEST_DEST_ADDR;
+ mc.src_mac = TEST_SRC_ADDR;
+
+ /* Initialize the range */
+ /* We should receive exactly one notification of the initialization. */
+ LONGS_EQUAL(0, maap_init_client(&mc, &sender1_in, range_base_addr, range_size));
+ sender_out = NULL;
+ memset(&mn, 0, sizeof(Maap_Notify));
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+ /* Try to reserve a block of addresses. */
+ id = maap_reserve_range(&mc, &sender2_in, 0, 10);
+ CHECK(id > 0);
+
+ /* Fake a Probe packet we must defer to after the first probe. */
+ verify_sent_packets(&mc, &mn, &sender_out, &probe_packets_detected, &announce_packets_detected, 1, -1, -1, TEST_REMOTE_ADDR_LOWER, 1);
+ LONGS_EQUAL(1, probe_packets_detected);
+ LONGS_EQUAL(0, announce_packets_detected);
+
+ /* We should not have a notification yet. */
+ CHECK(sender_out == NULL);
+
+ /* Handle the Acquiring message. */
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ LONGS_EQUAL(MAAP_NOTIFY_ACQUIRING, mn.kind);
+
+ /* Fake a Probe packet we must defer to after the third probe. */
+ verify_sent_packets(&mc, &mn, &sender_out, &probe_packets_detected, &announce_packets_detected, 3, -1, -1, TEST_REMOTE_ADDR_LOWER, 3);
+ LONGS_EQUAL(3, probe_packets_detected);
+ LONGS_EQUAL(0, announce_packets_detected);
+
+ /* We should not have a notification yet. */
+ CHECK(sender_out == NULL);
+
+ /* Handle the Acquiring message. */
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ LONGS_EQUAL(MAAP_NOTIFY_ACQUIRING, mn.kind);
+
+ /* Fake a Probe packet we should ignore after the second probe. */
+ /* This attempt should succeed. */
+ verify_sent_packets(&mc, &mn, &sender_out, &probe_packets_detected, &announce_packets_detected, 2, -1, -1, TEST_REMOTE_ADDR_HIGHER, 0);
+ LONGS_EQUAL(4, probe_packets_detected);
+ LONGS_EQUAL(1, announce_packets_detected);
+
+ /* Verify that the notification indicated a successful reservation. */
+ CHECK(sender_out == &sender2_in);
+ LONGS_EQUAL(MAAP_NOTIFY_ACQUIRED, mn.kind);
+ LONGS_EQUAL(id, mn.id);
+ CHECK(mn.start >= range_base_addr);
+ CHECK(mn.start + mn.count - 1 <= range_base_addr + range_size - 1);
+ LONGS_EQUAL(10, mn.count);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+
+ /* We are done with the Maap_Client structure */
+ maap_deinit_client(&mc);
+}
+
+TEST(maap_group, Probing_vs_Announces)
+{
+ const uint64_t range_base_addr = MAAP_DYNAMIC_POOL_BASE;
+ const uint32_t range_size = MAAP_DYNAMIC_POOL_SIZE;
+ Maap_Client mc;
+ Maap_Notify mn;
+ const int sender1_in = 1, sender2_in = 2;
+ const void *sender_out;
+ int id;
+ int probe_packets_detected, announce_packets_detected;
+
+ /* Initialize the Maap_Client structure */
+ memset(&mc, 0, sizeof(Maap_Client));
+ mc.dest_mac = TEST_DEST_ADDR;
+ mc.src_mac = TEST_SRC_ADDR;
+
+ /* Initialize the range */
+ /* We should receive exactly one notification of the initialization. */
+ LONGS_EQUAL(0, maap_init_client(&mc, &sender1_in, range_base_addr, range_size));
+ sender_out = NULL;
+ memset(&mn, 0, sizeof(Maap_Notify));
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+
+ /* Try to reserve a block of addresses. */
+ id = maap_reserve_range(&mc, &sender2_in, 0, 10);
+ CHECK(id > 0);
+
+ /* Fake an Announce packet after the first probe. */
+ verify_sent_packets(&mc, &mn, &sender_out, &probe_packets_detected, &announce_packets_detected, -1, 1, -1, TEST_REMOTE_ADDR_HIGHER, 1);
+ LONGS_EQUAL(1, probe_packets_detected);
+ LONGS_EQUAL(0, announce_packets_detected);
+
+ /* We should not have a notification yet. */
+ CHECK(sender_out == NULL);
+
+ /* Handle the Acquiring message. */
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ LONGS_EQUAL(MAAP_NOTIFY_ACQUIRING, mn.kind);
+
+ /* Fake an Announce packet after the third probe. */
+ verify_sent_packets(&mc, &mn, &sender_out, &probe_packets_detected, &announce_packets_detected, -1, 3, -1, TEST_REMOTE_ADDR_LOWER, 3);
+ LONGS_EQUAL(3, probe_packets_detected);
+ LONGS_EQUAL(0, announce_packets_detected);
+
+ /* We should not have a notification yet. */
+ CHECK(sender_out == NULL);
+
+ /* Handle the Acquiring message. */
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ LONGS_EQUAL(MAAP_NOTIFY_ACQUIRING, mn.kind);
+
+ /* Allow this attempt to succeed. */
+ verify_sent_packets(&mc, &mn, &sender_out, &probe_packets_detected, &announce_packets_detected, -1, -1, -1, 0, 0);
+ LONGS_EQUAL(4, probe_packets_detected);
+ LONGS_EQUAL(1, announce_packets_detected);
+
+ /* Verify that the notification indicated a successful reservation. */
+ CHECK(sender_out == &sender2_in);
+ LONGS_EQUAL(MAAP_NOTIFY_ACQUIRED, mn.kind);
+ LONGS_EQUAL(id, mn.id);
+ CHECK(mn.start >= range_base_addr);
+ CHECK(mn.start + mn.count - 1 <= range_base_addr + range_size - 1);
+ LONGS_EQUAL(10, mn.count);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+
+ /* We are done with the Maap_Client structure */
+ maap_deinit_client(&mc);
+}
+
+TEST(maap_group, Probing_vs_Defends)
+{
+ const uint64_t range_base_addr = MAAP_DYNAMIC_POOL_BASE;
+ const uint32_t range_size = MAAP_DYNAMIC_POOL_SIZE;
+ Maap_Client mc;
+ Maap_Notify mn;
+ const int sender1_in = 1, sender2_in = 2;
+ const void *sender_out;
+ int id;
+ int probe_packets_detected, announce_packets_detected;
+
+ /* Initialize the Maap_Client structure */
+ memset(&mc, 0, sizeof(Maap_Client));
+ mc.dest_mac = TEST_DEST_ADDR;
+ mc.src_mac = TEST_SRC_ADDR;
+
+ /* Initialize the range */
+ /* We should receive exactly one notification of the initialization. */
+ LONGS_EQUAL(0, maap_init_client(&mc, &sender1_in, range_base_addr, range_size));
+ sender_out = NULL;
+ memset(&mn, 0, sizeof(Maap_Notify));
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+
+ /* Try to reserve a block of addresses. */
+ id = maap_reserve_range(&mc, &sender2_in, 0, 10);
+ CHECK(id > 0);
+
+ /* Fake a Defend packet after the first probe. */
+ verify_sent_packets(&mc, &mn, &sender_out, &probe_packets_detected, &announce_packets_detected, -1, -1, 1, TEST_REMOTE_ADDR_LOWER, 1);
+ LONGS_EQUAL(1, probe_packets_detected);
+ LONGS_EQUAL(0, announce_packets_detected);
+
+ /* We should not have a notification yet. */
+ CHECK(sender_out == NULL);
+
+ /* Handle the Acquiring message. */
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ LONGS_EQUAL(MAAP_NOTIFY_ACQUIRING, mn.kind);
+
+ /* Fake a Defend packet after the third probe. */
+ verify_sent_packets(&mc, &mn, &sender_out, &probe_packets_detected, &announce_packets_detected, -1, -1, 3, TEST_REMOTE_ADDR_HIGHER, 3);
+ LONGS_EQUAL(3, probe_packets_detected);
+ LONGS_EQUAL(0, announce_packets_detected);
+
+ /* We should not have a notification yet. */
+ CHECK(sender_out == NULL);
+
+ /* Handle the Acquiring message. */
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ LONGS_EQUAL(MAAP_NOTIFY_ACQUIRING, mn.kind);
+
+ /* Allow this attempt to succeed. */
+ verify_sent_packets(&mc, &mn, &sender_out, &probe_packets_detected, &announce_packets_detected, -1, -1, -1, 0, 0);
+ LONGS_EQUAL(4, probe_packets_detected);
+ LONGS_EQUAL(1, announce_packets_detected);
+
+ /* Verify that the notification indicated a successful reservation. */
+ CHECK(sender_out == &sender2_in);
+ LONGS_EQUAL(MAAP_NOTIFY_ACQUIRED, mn.kind);
+ LONGS_EQUAL(id, mn.id);
+ CHECK(mn.start >= range_base_addr);
+ CHECK(mn.start + mn.count - 1 <= range_base_addr + range_size - 1);
+ LONGS_EQUAL(10, mn.count);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+
+ /* We are done with the Maap_Client structure */
+ maap_deinit_client(&mc);
+}
+
+TEST(maap_group, Defending_vs_Probes)
+{
+ const uint64_t range_base_addr = MAAP_DYNAMIC_POOL_BASE;
+ const uint32_t range_size = MAAP_DYNAMIC_POOL_SIZE;
+ Maap_Client mc;
+ Maap_Notify mn;
+ const int sender1_in = 1, sender2_in = 2, sender3_in = 3;
+ const void *sender_out;
+ int id;
+ uint64_t range_reserved_start;
+ uint32_t range_reserved_count;
+ int probe_packets_detected, announce_packets_detected;
+ void *packet_data = NULL;
+ MAAP_Packet packet_contents;
+ MAAP_Packet probe_packet;
+ uint8_t probe_buffer[MAAP_NET_BUFFER_SIZE];
+
+ /* Initialize the Maap_Client structure */
+ memset(&mc, 0, sizeof(Maap_Client));
+ mc.dest_mac = TEST_DEST_ADDR;
+ mc.src_mac = TEST_SRC_ADDR;
+
+ /* Initialize the range */
+ /* We should receive exactly one notification of the initialization. */
+ LONGS_EQUAL(0, maap_init_client(&mc, &sender1_in, range_base_addr, range_size));
+ sender_out = NULL;
+ memset(&mn, 0, sizeof(Maap_Notify));
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+ /* Reserve a block of addresses. */
+ id = maap_reserve_range(&mc, &sender2_in, 0, 10);
+ CHECK(id > 0);
+ verify_sent_packets(&mc, &mn, &sender_out, &probe_packets_detected, &announce_packets_detected, -1, -1, -1, 0, 0);
+ LONGS_EQUAL(4, probe_packets_detected);
+ LONGS_EQUAL(1, announce_packets_detected);
+ LONGS_EQUAL(MAAP_NOTIFY_ACQUIRED, mn.kind);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+ LONGS_EQUAL(id, mn.id);
+
+ /* Save the results for use later. */
+ range_reserved_start = mn.start;
+ range_reserved_count = mn.count;
+
+
+ /* Fake a probe request that conflicts with the start of our range. */
+ init_packet(&probe_packet, TEST_DEST_ADDR, TEST_REMOTE_ADDR_HIGHER);
+ probe_packet.message_type = MAAP_PROBE;
+ probe_packet.requested_start_address = range_reserved_start - 4; /* Use the start of our range. */
+ probe_packet.requested_count = 5;
+ LONGS_EQUAL(0, pack_maap(&probe_packet, probe_buffer));
+ maap_handle_packet(&mc, probe_buffer, MAAP_NET_BUFFER_SIZE);
+
+ /* Verify that we defended our range. */
+ LONGS_EQUAL(0, maap_handle_timer(&mc));
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+ CHECK((packet_data = Net_getNextQueuedPacket(mc.net)) != NULL);
+ LONGS_EQUAL(0, unpack_maap(&packet_contents, (const uint8_t *) packet_data));
+ CHECK(packet_contents.message_type == MAAP_DEFEND);
+ CHECK(packet_contents.requested_start_address == probe_packet.requested_start_address);
+ CHECK(packet_contents.requested_count == probe_packet.requested_count);
+ CHECK(packet_contents.conflict_start_address == range_reserved_start);
+ CHECK(packet_contents.conflict_count == 1); /* Only one address conflicts */
+ Net_freeQueuedPacket(mc.net, packet_data);
+
+ /* Verify the logging. */
+ CHECK(strcmp(Logging_getLastTag(), "INFO") == 0);
+ CHECK(strcmp(Logging_getLastMessage(), "DEFEND!") == 0);
+
+
+ /* Fake a probe request that conflicts with the end of our range. */
+ probe_packet.requested_start_address = range_reserved_start + range_reserved_count - 1; /* Use the end of our range. */
+ probe_packet.requested_count = 5;
+ LONGS_EQUAL(0, pack_maap(&probe_packet, probe_buffer));
+ maap_handle_packet(&mc, probe_buffer, MAAP_NET_BUFFER_SIZE);
+
+ /* Verify that we defended our range. */
+ LONGS_EQUAL(0, maap_handle_timer(&mc));
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+ CHECK((packet_data = Net_getNextQueuedPacket(mc.net)) != NULL);
+ LONGS_EQUAL(0, unpack_maap(&packet_contents, (const uint8_t *) packet_data));
+ CHECK(packet_contents.message_type == MAAP_DEFEND);
+ CHECK(packet_contents.requested_start_address == probe_packet.requested_start_address);
+ CHECK(packet_contents.requested_count == probe_packet.requested_count);
+ CHECK(packet_contents.conflict_start_address == probe_packet.requested_start_address);
+ CHECK(packet_contents.conflict_count == 1); /* Only one address conflicts */
+ Net_freeQueuedPacket(mc.net, packet_data);
+
+ /* Verify the logging. */
+ CHECK(strcmp(Logging_getLastTag(), "INFO") == 0);
+ CHECK(strcmp(Logging_getLastMessage(), "DEFEND!") == 0);
+
+
+ /* Try some probe requests adjacent to, but not overlapping, our range. */
+ probe_packet.requested_start_address = range_reserved_start - 5; /* Before the start of our range. */
+ probe_packet.requested_count = 5;
+ LONGS_EQUAL(0, pack_maap(&probe_packet, probe_buffer));
+ maap_handle_packet(&mc, probe_buffer, MAAP_NET_BUFFER_SIZE);
+ probe_packet.requested_start_address = range_reserved_start + range_reserved_count; /* After the end of our range. */
+ probe_packet.requested_count = 5;
+ LONGS_EQUAL(0, pack_maap(&probe_packet, probe_buffer));
+ maap_handle_packet(&mc, probe_buffer, MAAP_NET_BUFFER_SIZE);
+
+ /* Verify that we didn't defend our range. */
+ LONGS_EQUAL(0, maap_handle_timer(&mc));
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+ CHECK((packet_data = Net_getNextQueuedPacket(mc.net)) == NULL);
+
+
+ /* Verify that the status of the range is valid. */
+ maap_range_status(&mc, &sender3_in, id);
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ CHECK(sender_out == &sender3_in);
+ LONGS_EQUAL(MAAP_NOTIFY_STATUS, mn.kind);
+ LONGS_EQUAL(id, mn.id);
+ LONGS_EQUAL(range_reserved_start, mn.start);
+ LONGS_EQUAL(range_reserved_count, mn.count);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+
+
+ /* We are done with the Maap_Client structure */
+ maap_deinit_client(&mc);
+}
+
+TEST(maap_group, Defending_vs_Announces)
+{
+ const uint64_t range_base_addr = MAAP_DYNAMIC_POOL_BASE;
+ const uint32_t range_size = MAAP_DYNAMIC_POOL_SIZE;
+ Maap_Client mc;
+ Maap_Notify mn;
+ const int sender1_in = 1, sender2_in = 2, sender3_in = 3;
+ const void *sender_out;
+ int id;
+ uint64_t range_reserved_start;
+ uint32_t range_reserved_count;
+ int probe_packets_detected, announce_packets_detected;
+ void *packet_data = NULL;
+ MAAP_Packet announce_packet;
+ uint8_t announce_buffer[MAAP_NET_BUFFER_SIZE];
+
+ /* Initialize the Maap_Client structure */
+ memset(&mc, 0, sizeof(Maap_Client));
+ mc.dest_mac = TEST_DEST_ADDR;
+ mc.src_mac = TEST_SRC_ADDR;
+
+ /* Initialize the range */
+ /* We should receive exactly one notification of the initialization. */
+ LONGS_EQUAL(0, maap_init_client(&mc, &sender1_in, range_base_addr, range_size));
+ sender_out = NULL;
+ memset(&mn, 0, sizeof(Maap_Notify));
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+ /* Reserve a block of addresses. */
+ id = maap_reserve_range(&mc, &sender2_in, 0, 10);
+ CHECK(id > 0);
+ verify_sent_packets(&mc, &mn, &sender_out, &probe_packets_detected, &announce_packets_detected, -1, -1, -1, 0, 0);
+ LONGS_EQUAL(4, probe_packets_detected);
+ LONGS_EQUAL(1, announce_packets_detected);
+ LONGS_EQUAL(MAAP_NOTIFY_ACQUIRED, mn.kind);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+ LONGS_EQUAL(id, mn.id);
+
+ /* Save the results for use later. */
+ range_reserved_start = mn.start;
+ range_reserved_count = mn.count;
+
+
+ /* Try some announcements adjacent to, but not overlapping, our range. */
+ init_packet(&announce_packet, TEST_DEST_ADDR, TEST_REMOTE_ADDR_LOWER);
+ announce_packet.message_type = MAAP_ANNOUNCE;
+ announce_packet.requested_start_address = range_reserved_start - 5; /* Before the start of our range. */
+ announce_packet.requested_count = 5;
+ LONGS_EQUAL(0, pack_maap(&announce_packet, announce_buffer));
+ maap_handle_packet(&mc, announce_buffer, MAAP_NET_BUFFER_SIZE);
+ announce_packet.requested_start_address = range_reserved_start + range_reserved_count; /* After the end of our range. */
+ announce_packet.requested_count = 5;
+ LONGS_EQUAL(0, pack_maap(&announce_packet, announce_buffer));
+ maap_handle_packet(&mc, announce_buffer, MAAP_NET_BUFFER_SIZE);
+
+ /* Try an announcement that overlaps our range, but from an address we should ignore. */
+ init_packet(&announce_packet, TEST_DEST_ADDR, TEST_REMOTE_ADDR_HIGHER);
+ announce_packet.message_type = MAAP_ANNOUNCE;
+ announce_packet.requested_start_address = range_reserved_start - 2; /* Overlap the start of our range. */
+ announce_packet.requested_count = 5;
+ LONGS_EQUAL(0, pack_maap(&announce_packet, announce_buffer));
+ maap_handle_packet(&mc, announce_buffer, MAAP_NET_BUFFER_SIZE);
+
+ /* Verify that we didn't react. */
+ LONGS_EQUAL(0, maap_handle_timer(&mc));
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+ CHECK((packet_data = Net_getNextQueuedPacket(mc.net)) == NULL);
+
+ /* Verify the logging. */
+ CHECK(strcmp(Logging_getLastTag(), "INFO") == 0);
+ CHECK(strcmp(Logging_getLastMessage(), "IGNORE") == 0);
+
+ /* Verify that the status of the range is still valid. */
+ maap_range_status(&mc, &sender3_in, id);
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ CHECK(sender_out == &sender3_in);
+ LONGS_EQUAL(MAAP_NOTIFY_STATUS, mn.kind);
+ LONGS_EQUAL(id, mn.id);
+ LONGS_EQUAL(range_reserved_start, mn.start);
+ LONGS_EQUAL(range_reserved_count, mn.count);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+
+
+ /* Fake an announcement that conflicts with the start of our range. */
+ init_packet(&announce_packet, TEST_DEST_ADDR, TEST_REMOTE_ADDR_LOWER);
+ announce_packet.message_type = MAAP_ANNOUNCE;
+ announce_packet.requested_start_address = range_reserved_start - 2; /* Overlap the start of our range. */
+ announce_packet.requested_count = 5;
+ LONGS_EQUAL(0, pack_maap(&announce_packet, announce_buffer));
+ maap_handle_packet(&mc, announce_buffer, MAAP_NET_BUFFER_SIZE);
+
+ /* Verify that we yielded our range, and did not defend it. */
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ CHECK(sender_out == &sender2_in);
+ if (mn.kind == MAAP_NOTIFY_ACQUIRING) {
+ /* Skip over the acquiring notification. */
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ CHECK(sender_out == &sender2_in);
+ }
+ LONGS_EQUAL(MAAP_NOTIFY_YIELDED, mn.kind);
+ LONGS_EQUAL(id, mn.id);
+ LONGS_EQUAL(range_reserved_start, mn.start);
+ LONGS_EQUAL(range_reserved_count, mn.count);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+
+ /* Verify the logging. */
+ CHECK(strcmp(Logging_getLastTag(), "INFO") == 0);
+ CHECK(strcmp(Logging_getLastMessage(), "YIELD") == 0);
+
+ /* Verify that we requested a different range to replace the yielded one. */
+ verify_sent_packets(&mc, &mn, &sender_out, &probe_packets_detected, &announce_packets_detected, -1, -1, -1, 0, 0);
+ LONGS_EQUAL(4, probe_packets_detected);
+ LONGS_EQUAL(1, announce_packets_detected);
+ CHECK(sender_out == &sender2_in);
+ LONGS_EQUAL(MAAP_NOTIFY_ACQUIRED, mn.kind);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+ LONGS_EQUAL(id, mn.id); /* The ID should not have changed */
+
+ /* Verify that the new range doesn't overlap the old range. */
+ CHECK(mn.start + mn.count - 1 < range_reserved_start || range_reserved_start + range_reserved_count - 1 < mn.start);
+
+ /* We are done with the Maap_Client structure */
+ maap_deinit_client(&mc);
+}
+
+TEST(maap_group, Defending_vs_Defends)
+{
+ const uint64_t range_base_addr = MAAP_DYNAMIC_POOL_BASE;
+ const uint32_t range_size = MAAP_DYNAMIC_POOL_SIZE;
+ Maap_Client mc;
+ Maap_Notify mn;
+ const int sender1_in = 1, sender2_in = 2, sender3_in = 3;
+ const void *sender_out;
+ int id;
+ uint64_t range_reserved_start;
+ uint32_t range_reserved_count;
+ int probe_packets_detected, announce_packets_detected;
+ void *packet_data = NULL;
+ MAAP_Packet defend_packet;
+ uint8_t defend_buffer[MAAP_NET_BUFFER_SIZE];
+
+ /* Initialize the Maap_Client structure */
+ memset(&mc, 0, sizeof(Maap_Client));
+ mc.dest_mac = TEST_DEST_ADDR;
+ mc.src_mac = TEST_SRC_ADDR;
+
+ /* Initialize the range */
+ /* We should receive exactly one notification of the initialization. */
+ LONGS_EQUAL(0, maap_init_client(&mc, &sender1_in, range_base_addr, range_size));
+ sender_out = NULL;
+ memset(&mn, 0, sizeof(Maap_Notify));
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+ /* Reserve a block of addresses. */
+ id = maap_reserve_range(&mc, &sender2_in, 0, 10);
+ CHECK(id > 0);
+ verify_sent_packets(&mc, &mn, &sender_out, &probe_packets_detected, &announce_packets_detected, -1, -1, -1, 0, 0);
+ LONGS_EQUAL(4, probe_packets_detected);
+ LONGS_EQUAL(1, announce_packets_detected);
+ LONGS_EQUAL(MAAP_NOTIFY_ACQUIRED, mn.kind);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+ LONGS_EQUAL(id, mn.id);
+
+ /* Save the results for use later. */
+ range_reserved_start = mn.start;
+ range_reserved_count = mn.count;
+
+
+ /* Try some defends adjacent to, but not overlapping, our range. */
+ init_packet(&defend_packet, TEST_DEST_ADDR, TEST_REMOTE_ADDR_LOWER);
+ defend_packet.message_type = MAAP_DEFEND;
+ defend_packet.requested_start_address = range_reserved_start - 5; /* Before the start of our range. */
+ defend_packet.requested_count = 5;
+ LONGS_EQUAL(0, pack_maap(&defend_packet, defend_buffer));
+ maap_handle_packet(&mc, defend_buffer, MAAP_NET_BUFFER_SIZE);
+ defend_packet.requested_start_address = range_reserved_start + range_reserved_count; /* After the end of our range. */
+ defend_packet.requested_count = 5;
+ LONGS_EQUAL(0, pack_maap(&defend_packet, defend_buffer));
+ maap_handle_packet(&mc, defend_buffer, MAAP_NET_BUFFER_SIZE);
+
+ /* Try a defend that overlaps our range, but from an address we should ignore. */
+ init_packet(&defend_packet, TEST_DEST_ADDR, TEST_REMOTE_ADDR_HIGHER);
+ defend_packet.message_type = MAAP_DEFEND;
+ defend_packet.requested_start_address = range_reserved_start - 2; /* Overlap the start of our range. */
+ defend_packet.requested_count = 5;
+ LONGS_EQUAL(0, pack_maap(&defend_packet, defend_buffer));
+ maap_handle_packet(&mc, defend_buffer, MAAP_NET_BUFFER_SIZE);
+
+ /* Verify that we didn't react. */
+ LONGS_EQUAL(0, maap_handle_timer(&mc));
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+ CHECK((packet_data = Net_getNextQueuedPacket(mc.net)) == NULL);
+
+ /* Verify the logging. */
+ CHECK(strcmp(Logging_getLastTag(), "INFO") == 0);
+ CHECK(strcmp(Logging_getLastMessage(), "IGNORE") == 0);
+
+ /* Verify that the status of the range is still valid. */
+ maap_range_status(&mc, &sender3_in, id);
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ CHECK(sender_out == &sender3_in);
+ LONGS_EQUAL(MAAP_NOTIFY_STATUS, mn.kind);
+ LONGS_EQUAL(id, mn.id);
+ LONGS_EQUAL(range_reserved_start, mn.start);
+ LONGS_EQUAL(range_reserved_count, mn.count);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+
+
+ /* Fake a defend that conflicts with the start of our range. */
+ init_packet(&defend_packet, TEST_DEST_ADDR, TEST_REMOTE_ADDR_LOWER);
+ defend_packet.message_type = MAAP_DEFEND;
+ defend_packet.requested_start_address = range_reserved_start - 2; /* Overlap the start of our range. */
+ defend_packet.requested_count = 5;
+ LONGS_EQUAL(0, pack_maap(&defend_packet, defend_buffer));
+ maap_handle_packet(&mc, defend_buffer, MAAP_NET_BUFFER_SIZE);
+
+ /* Verify that we yielded our range, and did not defend it. */
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ CHECK(sender_out == &sender2_in);
+ if (mn.kind == MAAP_NOTIFY_ACQUIRING) {
+ /* Skip over the acquiring notification. */
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ CHECK(sender_out == &sender2_in);
+ }
+ LONGS_EQUAL(MAAP_NOTIFY_YIELDED, mn.kind);
+ LONGS_EQUAL(id, mn.id);
+ LONGS_EQUAL(range_reserved_start, mn.start);
+ LONGS_EQUAL(range_reserved_count, mn.count);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+
+ /* Verify the logging. */
+ CHECK(strcmp(Logging_getLastTag(), "INFO") == 0);
+ CHECK(strcmp(Logging_getLastMessage(), "YIELD") == 0);
+
+ /* Verify that we requested a different range to replace the yielded one. */
+ verify_sent_packets(&mc, &mn, &sender_out, &probe_packets_detected, &announce_packets_detected, -1, -1, -1, 0, 0);
+ LONGS_EQUAL(4, probe_packets_detected);
+ LONGS_EQUAL(1, announce_packets_detected);
+ CHECK(sender_out == &sender2_in);
+ LONGS_EQUAL(MAAP_NOTIFY_ACQUIRED, mn.kind);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+ LONGS_EQUAL(id, mn.id); /* The ID should not have changed */
+
+ /* Verify that the new range doesn't overlap the old range. */
+ CHECK(mn.start + mn.count - 1 < range_reserved_start || range_reserved_start + range_reserved_count - 1 < mn.start);
+
+ /* We are done with the Maap_Client structure */
+ maap_deinit_client(&mc);
+}
+
+TEST(maap_group, Verify_Timing)
+{
+ const uint64_t range_base_addr = MAAP_DYNAMIC_POOL_BASE;
+ const uint32_t range_size = MAAP_DYNAMIC_POOL_SIZE;
+ Maap_Client mc;
+ Maap_Notify mn;
+ const int sender_in = 1;
+ const void *sender_out;
+ int id;
+ int probe_packets_detected, announce_packets_detected;
+ MAAP_Packet announce_packet;
+ uint8_t announce_buffer[MAAP_NET_BUFFER_SIZE];
+ void *packet_data;
+ MAAP_Packet packet_contents;
+ Time previous_time, current_time;
+
+ /* Initialize the Maap_Client structure */
+ memset(&mc, 0, sizeof(Maap_Client));
+ mc.dest_mac = TEST_DEST_ADDR;
+ mc.src_mac = TEST_SRC_ADDR;
+
+ /* Initialize the range */
+ /* We should receive exactly one notification of the initialization. */
+ LONGS_EQUAL(0, maap_init_client(&mc, &sender_in, range_base_addr, range_size));
+ sender_out = NULL;
+ memset(&mn, 0, sizeof(Maap_Notify));
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+
+ /* Reserve a block of addresses. */
+ id = maap_reserve_range(&mc, &sender_in, 0, 10);
+ CHECK(id > 0);
+
+ /* Verify the timing between Probes when interrupted. */
+ for (int i = 0; i < 100; ++i)
+ {
+ /* Wait for three probes to be sent.
+ * Probe timing will be tested by verify_sent_packets. */
+ verify_sent_packets(&mc, &mn, &sender_out, &probe_packets_detected, &announce_packets_detected, -1, -1, -1, 0, 3);
+ LONGS_EQUAL(3, probe_packets_detected);
+ LONGS_EQUAL(0, announce_packets_detected);
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+ /* Wait up to 500 ms */
+ Time_increaseNanos((random() % MAAP_PROBE_INTERVAL_BASE) * 1000000LL);
+
+ /* Send an announce that conflicts with the current reservation. */
+ init_packet(&announce_packet, TEST_DEST_ADDR, TEST_REMOTE_ADDR_LOWER);
+ announce_packet.message_type = MAAP_ANNOUNCE;
+ announce_packet.requested_start_address = mn.start;
+ announce_packet.requested_count = mn.count;
+ LONGS_EQUAL(0, pack_maap(&announce_packet, announce_buffer));
+ maap_handle_packet(&mc, announce_buffer, MAAP_NET_BUFFER_SIZE);
+ }
+
+
+ /* Verify the timing between Probes when reservation is successful. */
+ for (int i = 0; i < 100; ++i)
+ {
+ /* Wait for the previous attempt to succeed.
+ * Probe timing will be tested by verify_sent_packets. */
+ verify_sent_packets(&mc, &mn, &sender_out, &probe_packets_detected, &announce_packets_detected, -1, -1, -1, 0, 0);
+ LONGS_EQUAL(4, probe_packets_detected);
+ LONGS_EQUAL(1, announce_packets_detected);
+
+ /* Verify that the notification indicated a successful reservation. */
+ LONGS_EQUAL(MAAP_NOTIFY_ACQUIRED, mn.kind);
+ LONGS_EQUAL(id, mn.id);
+ CHECK(mn.start >= range_base_addr);
+ CHECK(mn.start + mn.count - 1 <= range_base_addr + range_size - 1);
+ LONGS_EQUAL(10, mn.count);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+ /* Wait up to 30000 ms */
+ Time_increaseNanos((random() % MAAP_ANNOUNCE_INTERVAL_BASE) * 1000000LL);
+
+ /* Send an announce that conflicts with the current reservation. */
+ init_packet(&announce_packet, TEST_DEST_ADDR, TEST_REMOTE_ADDR_LOWER);
+ announce_packet.message_type = MAAP_ANNOUNCE;
+ announce_packet.requested_start_address = mn.start;
+ announce_packet.requested_count = mn.count;
+ LONGS_EQUAL(0, pack_maap(&announce_packet, announce_buffer));
+ maap_handle_packet(&mc, announce_buffer, MAAP_NET_BUFFER_SIZE);
+
+ /* Verify that we yielded our range, and did not defend it. */
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ if (mn.kind == MAAP_NOTIFY_ACQUIRING) {
+ /* Skip over the acquiring notification. */
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ }
+ LONGS_EQUAL(MAAP_NOTIFY_YIELDED, mn.kind);
+ LONGS_EQUAL(id, mn.id);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+
+ /* Verify the logging. */
+ CHECK(strcmp(Logging_getLastTag(), "INFO") == 0);
+ CHECK(strcmp(Logging_getLastMessage(), "YIELD") == 0);
+ }
+
+
+ /* Wait for the reservation to succeed. */
+ verify_sent_packets(&mc, &mn, &sender_out, &probe_packets_detected, &announce_packets_detected, -1, -1, -1, 0, 0);
+ LONGS_EQUAL(4, probe_packets_detected);
+ LONGS_EQUAL(1, announce_packets_detected);
+ LONGS_EQUAL(MAAP_NOTIFY_ACQUIRED, mn.kind);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+ /* Record the time of the announcement. */
+ Time_setFromMonotonicTimer(&previous_time);
+
+ /* Verify the timing between Announcements */
+ for (int i = 0; i < 100; ++i)
+ {
+ /* Wait for the next announcement. */
+ Time_increaseNanos(maap_get_delay_to_next_timer(&mc));
+ LONGS_EQUAL(0, maap_handle_timer(&mc));
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+ packet_data = Net_getNextQueuedPacket(mc.net);
+ for (int j = 0; j < 100 && packet_data == NULL; ++j) {
+ /* Timer expiration could be to free a reservation. Keep waiting. */
+ Time_increaseNanos(maap_get_delay_to_next_timer(&mc));
+ LONGS_EQUAL(0, maap_handle_timer(&mc));
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+ packet_data = Net_getNextQueuedPacket(mc.net);
+ }
+ CHECK(packet_data != NULL);
+ LONGS_EQUAL(0, unpack_maap(&packet_contents, (const uint8_t *) packet_data));
+ Net_freeQueuedPacket(mc.net, packet_data);
+ CHECK(packet_contents.message_type == MAAP_ANNOUNCE);
+
+ /* Get the current time. */
+ Time_setFromMonotonicTimer(&current_time);
+
+ /* Determine the minimum time from the last announce. */
+ Time time_min;
+ Time_setFromNanos(&time_min, MAAP_ANNOUNCE_INTERVAL_BASE * 1000000LL);
+ Time_add(&time_min, &previous_time);
+ CHECK(Time_cmp(&time_min, &current_time) < 0);
+
+ /* Determine the maximum time from the last announce. */
+ Time time_max;
+ Time_setFromNanos(&time_max, (MAAP_ANNOUNCE_INTERVAL_BASE + MAAP_ANNOUNCE_INTERVAL_VARIATION) * 1000000LL);
+ Time_add(&time_max, &previous_time);
+ CHECK(Time_cmp(&current_time, &time_max) < 0);
+
+ /* Save the current time for the next comparison. */
+ Time_setFromMonotonicTimer(&previous_time);
+ }
+
+ /* We are done with the Maap_Client structure */
+ maap_deinit_client(&mc);
+}
+
+TEST(maap_group, Ignore_Versioning)
+{
+ const uint64_t range_base_addr = MAAP_DYNAMIC_POOL_BASE;
+ const uint32_t range_size = MAAP_DYNAMIC_POOL_SIZE;
+ Maap_Client mc;
+ Maap_Notify mn;
+ const int sender1_in = 1, sender2_in = 2, sender3_in = 3;
+ const void *sender_out;
+ int id;
+ uint64_t range_reserved_start;
+ uint32_t range_reserved_count;
+ int probe_packets_detected, announce_packets_detected;
+ MAAP_Packet custom_packet;
+ uint8_t custom_buffer[MAAP_NET_BUFFER_SIZE];
+
+ /* Initialize the Maap_Client structure */
+ memset(&mc, 0, sizeof(Maap_Client));
+ mc.dest_mac = TEST_DEST_ADDR;
+ mc.src_mac = TEST_SRC_ADDR;
+
+ /* Initialize the range */
+ /* We should receive exactly one notification of the initialization. */
+ LONGS_EQUAL(0, maap_init_client(&mc, &sender1_in, range_base_addr, range_size));
+ sender_out = NULL;
+ memset(&mn, 0, sizeof(Maap_Notify));
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+ /* Reserve a block of addresses. */
+ id = maap_reserve_range(&mc, &sender2_in, 0, 10);
+ CHECK(id > 0);
+ verify_sent_packets(&mc, &mn, &sender_out, &probe_packets_detected, &announce_packets_detected, -1, -1, -1, 0, 0);
+ LONGS_EQUAL(4, probe_packets_detected);
+ LONGS_EQUAL(1, announce_packets_detected);
+
+ /* Verify that the notification indicated a successful reservation. */
+ CHECK(sender_out == &sender2_in);
+ LONGS_EQUAL(MAAP_NOTIFY_ACQUIRED, mn.kind);
+ LONGS_EQUAL(id, mn.id);
+ CHECK(mn.start >= range_base_addr);
+ CHECK(mn.start + mn.count - 1 <= range_base_addr + range_size - 1);
+ LONGS_EQUAL(10, mn.count);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+ /* Save the results for use later. */
+ range_reserved_start = mn.start;
+ range_reserved_count = mn.count;
+
+
+ /* Send an unknown PDU with a greater maap_version value that overlaps our reservation. */
+ init_packet(&custom_packet, TEST_DEST_ADDR, TEST_REMOTE_ADDR_LOWER);
+ custom_packet.maap_version++;
+ custom_packet.message_type = 4; /* Not a valid message type. */
+ custom_packet.requested_start_address = range_base_addr;
+ custom_packet.requested_count = range_size;
+ LONGS_EQUAL(0, pack_maap(&custom_packet, custom_buffer));
+ maap_handle_packet(&mc, custom_buffer, MAAP_NET_BUFFER_SIZE);
+
+ /* Verify that nothing happened. */
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+ CHECK(Net_getNextQueuedPacket(mc.net) == NULL);
+
+ /* Verify the logging. */
+ CHECK(strcmp(Logging_getLastTag(), "ERROR") == 0);
+ CHECK(strcmp(Logging_getLastMessage(), "MAAP packet message type 4 not recognized") == 0);
+
+ /* Verify that the logging is cleared after testing. */
+ CHECK(strcmp(Logging_getLastTag(), "") == 0);
+ CHECK(strcmp(Logging_getLastMessage(), "") == 0);
+
+ /* Verify the status of our existing reservation */
+ maap_range_status(&mc, &sender3_in, id);
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ CHECK(sender_out == &sender3_in);
+ LONGS_EQUAL(MAAP_NOTIFY_STATUS, mn.kind);
+ LONGS_EQUAL(id, mn.id);
+ LONGS_EQUAL(range_reserved_start, mn.start);
+ LONGS_EQUAL(range_reserved_count, mn.count);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+
+ /* We are done with the Maap_Client structure */
+ maap_deinit_client(&mc);
+}
+
+TEST(maap_group, Multiple_Conflicts_Defend)
+{
+ #define num_reservations 10
+
+ const uint64_t range_base_addr = MAAP_DYNAMIC_POOL_BASE;
+ const uint32_t range_size = MAAP_DYNAMIC_POOL_SIZE;
+ Maap_Client mc;
+ Maap_Notify mn;
+ const int sender_in[num_reservations] = {0};
+ const void *sender_out;
+ int i;
+ int id[num_reservations];
+ int probe_packets_detected, announce_packets_detected;
+ MAAP_Packet defend_packet;
+ uint8_t defend_buffer[MAAP_NET_BUFFER_SIZE];
+ int countdown;
+ void *packet_data;
+ MAAP_Packet packet_contents;
+
+ /* Initialize the Maap_Client structure */
+ memset(&mc, 0, sizeof(Maap_Client));
+ mc.dest_mac = TEST_DEST_ADDR;
+ mc.src_mac = TEST_SRC_ADDR;
+
+ /* Initialize the range */
+ /* We should receive exactly one notification of the initialization. */
+ LONGS_EQUAL(0, maap_init_client(&mc, &sender_in[0], range_base_addr, range_size));
+ sender_out = NULL;
+ memset(&mn, 0, sizeof(Maap_Notify));
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+
+ /*
+ * Reserve some address ranges
+ */
+
+ for (i = 0; i < num_reservations; ++i) {
+ /* Reserve an address range */
+ id[i] = maap_reserve_range(&mc, &sender_in[i], 0, 1);
+ CHECK(id[i] > 0);
+ verify_sent_packets(&mc, &mn, &sender_out, &probe_packets_detected, &announce_packets_detected, -1, -1, -1, 0, 0);
+ LONGS_EQUAL(4, probe_packets_detected);
+ LONGS_EQUAL(1, announce_packets_detected);
+ CHECK(sender_out == &sender_in[i]);
+ LONGS_EQUAL(MAAP_NOTIFY_ACQUIRED, mn.kind);
+ LONGS_EQUAL(id[i], mn.id);
+ CHECK(mn.start >= range_base_addr);
+ CHECK(mn.start + mn.count - 1 <= range_base_addr + range_size - 1);
+ LONGS_EQUAL(1, mn.count);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+ }
+
+
+ /*
+ * Verify that a Defend conflicting with all the reservations from a higher address is ignored.
+ */
+
+ /* Send a Defend packet that conflicts with all the ranges. */
+ init_packet(&defend_packet, TEST_DEST_ADDR, TEST_REMOTE_ADDR_HIGHER);
+ defend_packet.message_type = MAAP_DEFEND;
+ defend_packet.requested_start_address = range_base_addr;
+ defend_packet.requested_count = range_size;
+ defend_packet.conflict_start_address = range_base_addr;
+ defend_packet.conflict_count = range_size;
+ LONGS_EQUAL(0, pack_maap(&defend_packet, defend_buffer));
+ maap_handle_packet(&mc, defend_buffer, MAAP_NET_BUFFER_SIZE);
+
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+ /* Verify that the status of each range is valid. */
+ for (i = 1; i < num_reservations; ++i) {
+ maap_range_status(&mc, &sender_in[i], id[i]);
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ CHECK(sender_out == &sender_in[i]);
+ LONGS_EQUAL(MAAP_NOTIFY_STATUS, mn.kind);
+ LONGS_EQUAL(id[i], mn.id);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+ }
+
+
+ /*
+ * Verify that a Defend conflicting with all the reservations from a lower address results in new addresses.
+ *
+ * The test uses Defend instead of Announce so that the app can use the defended range
+ * for selecting a new reservation, which it can't do if tracking annoucements.
+ */
+
+ /* Send a Defend packet that conflicts with all the ranges. */
+ init_packet(&defend_packet, TEST_DEST_ADDR, TEST_REMOTE_ADDR_LOWER);
+ defend_packet.message_type = MAAP_DEFEND;
+ defend_packet.requested_start_address = range_base_addr;
+ defend_packet.requested_count = range_size;
+ defend_packet.conflict_start_address = range_base_addr;
+ defend_packet.conflict_count = range_size;
+ LONGS_EQUAL(0, pack_maap(&defend_packet, defend_buffer));
+ maap_handle_packet(&mc, defend_buffer, MAAP_NET_BUFFER_SIZE);
+
+ /* Wait for the right number of probes and announcements. */
+ probe_packets_detected = 0;
+ announce_packets_detected = 0;
+ for (countdown = 1000; countdown > 0 && announce_packets_detected < num_reservations; --countdown)
+ {
+ Time_increaseNanos(maap_get_delay_to_next_timer(&mc));
+ LONGS_EQUAL(0, maap_handle_timer(&mc));
+
+ while ((packet_data = Net_getNextQueuedPacket(mc.net)) != NULL)
+ {
+ LONGS_EQUAL(0, unpack_maap(&packet_contents, (const uint8_t *) packet_data));
+ Net_freeQueuedPacket(mc.net, packet_data);
+ CHECK(packet_contents.message_type >= MAAP_PROBE && packet_contents.message_type <= MAAP_ANNOUNCE);
+ if (packet_contents.message_type == MAAP_PROBE)
+ {
+ (probe_packets_detected)++;
+ CHECK(probe_packets_detected <= 4 * num_reservations);
+ CHECK(announce_packets_detected < probe_packets_detected / 4 + 1);
+ }
+ else if (packet_contents.message_type == MAAP_ANNOUNCE)
+ {
+ (announce_packets_detected)++;
+ CHECK(probe_packets_detected > 3 * num_reservations);
+ CHECK(announce_packets_detected <= num_reservations);
+ }
+ else
+ {
+ /* Unexpected MAAP_DEFEND packet. */
+ CHECK(0);
+ }
+ }
+ }
+ CHECK(countdown > 0);
+ CHECK(NULL == Net_getNextQueuedPacket(mc.net));
+
+ /* We should have a yield notification and announce notification for each reservation. */
+ for (i = 0; i < num_reservations; ++i) {
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ while (mn.kind == MAAP_NOTIFY_ACQUIRING) {
+ /* Ignore any acquiring messages. */
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ }
+ LONGS_EQUAL(MAAP_NOTIFY_YIELDED, mn.kind);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+ }
+ for (i = 0; i < num_reservations; ++i) {
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ while (mn.kind == MAAP_NOTIFY_ACQUIRING) {
+ /* Ignore any acquiring messages. */
+ LONGS_EQUAL(1, get_notify(&mc, &sender_out, &mn));
+ }
+ LONGS_EQUAL(MAAP_NOTIFY_ACQUIRED, mn.kind);
+ LONGS_EQUAL(MAAP_NOTIFY_ERROR_NONE, mn.result);
+ }
+ LONGS_EQUAL(0, get_notify(&mc, &sender_out, &mn));
+
+
+ /* We are done with the Maap_Client structure */
+ maap_deinit_client(&mc);
+}
+
+
+static void verify_sent_packets(Maap_Client *p_mc, Maap_Notify *p_mn,
+ const void **p_sender_out,
+ int *p_probe_packets_detected, int *p_announce_packets_detected,
+ int send_probe /* = -1 */, int send_announce /* = -1 */, int send_defend /* = -1 */,
+ uint64_t remote_addr, int stop_after_probe)
+{
+ int countdown;
+ void *packet_data;
+ MAAP_Packet packet_contents;
+ Time probe_time[4], announce_time;
+ int acquiring_notification = 0;
+
+ /* Handle any packets generated during the activity.
+ * Stop once we are notified of a result. */
+ *p_sender_out = NULL;
+ memset(p_mn, 0, sizeof(Maap_Notify));
+ *p_probe_packets_detected = 0;
+ *p_announce_packets_detected = 0;
+ for (countdown = 1000; countdown > 0; --countdown)
+ {
+ while ((packet_data = Net_getNextQueuedPacket(p_mc->net)) != NULL)
+ {
+ /** @todo Add more verification that the packet to send is a proper packet. */
+ LONGS_EQUAL(0, unpack_maap(&packet_contents, (const uint8_t *) packet_data));
+ Net_freeQueuedPacket(p_mc->net, packet_data);
+ CHECK(packet_contents.message_type >= MAAP_PROBE && packet_contents.message_type <= MAAP_ANNOUNCE);
+ if (packet_contents.message_type == MAAP_PROBE)
+ {
+ CHECK(*p_probe_packets_detected < 4);
+ LONGS_EQUAL(0, *p_announce_packets_detected);
+
+ /* Save and test the timing between probes. */
+ Time_setFromMonotonicTimer(&(probe_time[*p_probe_packets_detected]));
+ if (*p_probe_packets_detected > 0) {
+
+ /* Determine the minimum time from the last probe. */
+ Time time_min;
+ Time_setFromNanos(&time_min, MAAP_PROBE_INTERVAL_BASE * 1000000LL);
+ Time_add(&time_min, &probe_time[*p_probe_packets_detected - 1]);
+ CHECK(Time_cmp(&time_min, &(probe_time[*p_probe_packets_detected])) < 0);
+
+ /* Determine the maximum time from the last probe. */
+ Time time_max;
+ Time_setFromNanos(&time_max, (MAAP_PROBE_INTERVAL_BASE + MAAP_PROBE_INTERVAL_VARIATION) * 1000000LL);
+ Time_add(&time_max, &probe_time[*p_probe_packets_detected - 1]);
+ CHECK(Time_cmp(&(probe_time[*p_probe_packets_detected]), &time_max) < 0);
+ }
+
+ (*p_probe_packets_detected)++;
+ /* printf("Probe packet sent (%d)\n", *p_probe_packets_detected); */
+
+ if (*p_probe_packets_detected == send_probe)
+ {
+ MAAP_Packet probe_packet;
+ uint8_t probe_buffer[MAAP_NET_BUFFER_SIZE];
+
+ /* Send a probe packet in response to the probe packet. */
+ init_packet(&probe_packet, TEST_DEST_ADDR, remote_addr);
+ probe_packet.message_type = MAAP_PROBE;
+ probe_packet.requested_start_address = packet_contents.requested_start_address;
+ probe_packet.requested_count = 1;
+ LONGS_EQUAL(0, pack_maap(&probe_packet, probe_buffer));
+ maap_handle_packet(p_mc, probe_buffer, MAAP_NET_BUFFER_SIZE);
+ /* printf("Probe packet received\n"); */
+ }
+
+ if (*p_probe_packets_detected == send_announce)
+ {
+ MAAP_Packet announce_packet;
+ uint8_t announce_buffer[MAAP_NET_BUFFER_SIZE];
+
+ /* Send an announce packet in response to the probe packet. */
+ init_packet(&announce_packet, TEST_DEST_ADDR, remote_addr);
+ announce_packet.message_type = MAAP_ANNOUNCE;
+ announce_packet.requested_start_address = packet_contents.requested_start_address;
+ announce_packet.requested_count = 1;
+ LONGS_EQUAL(0, pack_maap(&announce_packet, announce_buffer));
+ maap_handle_packet(p_mc, announce_buffer, MAAP_NET_BUFFER_SIZE);
+ /* printf("Announce packet received\n"); */
+ }
+
+ if (*p_probe_packets_detected == send_defend)
+ {
+ MAAP_Packet defend_packet;
+ uint8_t defend_buffer[MAAP_NET_BUFFER_SIZE];
+
+ /* Send a defend packet in response to the probe packet. */
+ init_packet(&defend_packet, TEST_DEST_ADDR, remote_addr);
+ defend_packet.message_type = MAAP_DEFEND;
+ defend_packet.requested_start_address = packet_contents.requested_start_address;
+ defend_packet.requested_count = packet_contents.requested_count;
+ defend_packet.conflict_start_address = packet_contents.requested_start_address; /* Just use the same address */
+ defend_packet.conflict_count = 1;
+ LONGS_EQUAL(0, pack_maap(&defend_packet, defend_buffer));
+ maap_handle_packet(p_mc, defend_buffer, MAAP_NET_BUFFER_SIZE);
+ /* printf("Defend packet received\n"); */
+ }
+
+ /* If requested, stop the processing at this point so the caller can see what happens next. */
+ if (*p_probe_packets_detected == stop_after_probe) { return; }
+ }
+ else if (packet_contents.message_type == MAAP_ANNOUNCE)
+ {
+ LONGS_EQUAL(4, *p_probe_packets_detected);
+ LONGS_EQUAL(0, *p_announce_packets_detected);
+ (*p_announce_packets_detected)++;
+ /* printf("Announce packet sent (%d)\n", *p_announce_packets_detected); */
+
+ /* Save and test the timing between the last probe and the announce. */
+ Time_setFromMonotonicTimer(&announce_time);
+
+ /* Determine the minimum time from the last probe. */
+ Time time_min;
+ Time_setFromNanos(&time_min, MAAP_PROBE_INTERVAL_BASE * 1000000LL);
+ Time_add(&time_min, &probe_time[*p_probe_packets_detected - 1]);
+ CHECK(Time_cmp(&time_min, &announce_time) < 0);
+
+ /* Determine the maximum time from the last probe. */
+ Time time_max;
+ Time_setFromNanos(&time_max, (MAAP_PROBE_INTERVAL_BASE + MAAP_PROBE_INTERVAL_VARIATION) * 1000000LL);
+ Time_add(&time_max, &probe_time[*p_probe_packets_detected - 1]);
+ CHECK(Time_cmp(&announce_time, &time_max) < 0);
+ }
+ else
+ {
+ /* Unexpected MAAP_DEFEND packet. */
+ CHECK(0);
+ }
+ }
+
+ if (get_notify(p_mc, p_sender_out, p_mn)) {
+ if (p_mn->kind == MAAP_NOTIFY_ACQUIRING) {
+ /* This is a MAAP_NOTIFY_ACQUIRING notification. We can ignore this once early on. */
+ CHECK(!acquiring_notification);
+ CHECK(*p_probe_packets_detected <= 1);
+ acquiring_notification++;
+ *p_sender_out = NULL;
+ } else {
+ /* We received a notification. Stop processing so it can be evaluated by the caller. */
+ break;
+ }
+ }
+
+ /* Wait for the next event. */
+ Time_increaseNanos(maap_get_delay_to_next_timer(p_mc));
+ LONGS_EQUAL(0, maap_handle_timer(p_mc));
+ }
+ CHECK(countdown > 0);
+}
diff --git a/daemons/maap/windows/src/maap_log_windows.c b/daemons/maap/windows/src/maap_log_windows.c
new file mode 100644
index 00000000..12180a28
--- /dev/null
+++ b/daemons/maap/windows/src/maap_log_windows.c
@@ -0,0 +1,452 @@
+/*************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************/
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#if defined(_WIN32) && (_MSC_VER < 1800)
+/* Visual Studio 2012 and earlier */
+typedef __int8 int8_t;
+typedef __int16 int16_t;
+typedef __int32 int32_t;
+typedef __int64 int64_t;
+typedef unsigned __int8 uint8_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+#else
+#include <inttypes.h>
+#endif
+
+#include "platform.h"
+#include "maap_log_queue.h"
+
+#define MAAP_LOG_COMPONENT "Log"
+#include "maap_log.h"
+
+typedef struct {
+ uint8_t msg[LOG_QUEUE_MSG_SIZE];
+ int bRT; // TRUE = Details are in RT queue
+} log_queue_item_t;
+
+typedef struct {
+ char *pFormat;
+ log_rt_datatype_t dataType;
+ union {
+ SYSTEMTIME nowST;
+ uint16_t unsignedShortVar;
+ int16_t signedShortVar;
+ uint32_t unsignedLongVar;
+ int32_t signedLongVar;
+ uint64_t unsignedLongLongVar;
+ int64_t signedLongLongVar;
+ float floatVar;
+ } data;
+ int bEnd;
+} log_rt_queue_item_t;
+
+static maap_log_queue_t logQueue;
+static maap_log_queue_t logRTQueue;
+
+static char msg[LOG_MSG_LEN] = "";
+static char time_msg[LOG_TIME_LEN] = "";
+static char timestamp_msg[LOG_TIMESTAMP_LEN] = "";
+static char file_msg[LOG_FILE_LEN] = "";
+static char proc_msg[LOG_PROC_LEN] = "";
+static char thread_msg[LOG_THREAD_LEN] = "";
+static char full_msg[LOG_FULL_MSG_LEN] = "";
+
+static char rt_msg[LOG_RT_MSG_LEN] = "";
+
+static int loggingThreadRunning = FALSE;
+DWORD WINAPI loggingThreadFn(LPVOID pv);
+static HANDLE loggingThread = NULL;
+
+#define THREAD_STACK_SIZE 65536
+
+static HANDLE gLogMutex = NULL;
+#define MUTEX_CREATE_ALT(h) h = CreateMutex(NULL, FALSE, NULL)
+#define LOG_LOCK() WaitForSingleObject(gLogMutex, INFINITE)
+#define LOG_UNLOCK() ReleaseMutex(gLogMutex)
+#define MUTEX_FREE_ALT(h) do { CloseHandle(h); h = NULL; } while (0)
+
+void maapLogRTRender(log_queue_item_t *pLogItem)
+{
+ if (logRTQueue) {
+ int bMore = TRUE;
+ pLogItem->msg[0] = 0x00;
+ while (bMore) {
+ maap_log_queue_elem_t elem = maapLogQueueTailLock(logRTQueue);
+ if (elem) {
+ log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)maapLogQueueData(elem);
+
+ switch (pLogRTItem->dataType) {
+ case LOG_RT_DATATYPE_CONST_STR:
+ strcat((char *)pLogItem->msg, pLogRTItem->pFormat);
+ break;
+ case LOG_RT_DATATYPE_NOW_TS:
+ sprintf(rt_msg, "[%2.2d:%2.2d:%2.2d.%3.3d] ", pLogRTItem->data.nowST.wHour, pLogRTItem->data.nowST.wMinute, pLogRTItem->data.nowST.wSecond, pLogRTItem->data.nowST.wMilliseconds);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_U16:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.unsignedShortVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_S16:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.signedShortVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_U32:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.unsignedLongVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_S32:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.signedLongVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_U64:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.unsignedLongLongVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_S64:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.signedLongLongVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_FLOAT:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.floatVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ default:
+ break;
+ }
+
+ if (pLogRTItem->bEnd) {
+ if (MAAP_LOG_EXTRA_NEWLINE)
+ strcat((char *)pLogItem->msg, "\n");
+ bMore = FALSE;
+ }
+ maapLogQueueTailPull(logRTQueue);
+ }
+ }
+ }
+}
+
+uint32_t maapLogGetMsg(uint8_t *pBuf, uint32_t bufSize)
+{
+ uint32_t dataLen = 0;
+ if (logQueue) {
+ maap_log_queue_elem_t elem = maapLogQueueTailLock(logQueue);
+ if (elem) {
+ log_queue_item_t *pLogItem = (log_queue_item_t *)maapLogQueueData(elem);
+
+ if (pLogItem->bRT)
+ maapLogRTRender(pLogItem);
+
+ dataLen = (uint32_t) strlen((const char *)pLogItem->msg);
+ if (dataLen <= bufSize)
+ memcpy(pBuf, (uint8_t *)pLogItem->msg, dataLen);
+ else
+ memcpy(pBuf, (uint8_t *)pLogItem->msg, bufSize);
+ maapLogQueueTailPull(logQueue);
+ return dataLen;
+ }
+ }
+ return dataLen;
+}
+
+DWORD WINAPI loggingThreadFn(LPVOID pv)
+{
+ while (loggingThreadRunning) {
+ int more = TRUE;
+
+ Sleep(LOG_QUEUE_SLEEP_MSEC);
+
+ while (more) {
+ maap_log_queue_elem_t elem = maapLogQueueTailLock(logQueue);
+ more = FALSE;
+ if (elem) {
+ log_queue_item_t *pLogItem = (log_queue_item_t *)maapLogQueueData(elem);
+
+ if (pLogItem->bRT)
+ maapLogRTRender(pLogItem);
+
+ fputs((const char *)pLogItem->msg, MAAP_LOG_OUTPUT_FD);
+ maapLogQueueTailPull(logQueue);
+ more = TRUE;
+ }
+ }
+ }
+
+ return 0;
+}
+
+void maapLogInit(void)
+{
+ MUTEX_CREATE_ALT(gLogMutex);
+
+ logQueue = maapLogQueueNewQueue(sizeof(log_queue_item_t), LOG_QUEUE_MSG_CNT);
+ if (!logQueue) {
+ printf("Failed to initialize logging facility\n");
+ }
+
+ logRTQueue = maapLogQueueNewQueue(sizeof(log_rt_queue_item_t), LOG_RT_QUEUE_CNT);
+ if (!logRTQueue) {
+ printf("Failed to initialize logging RT facility\n");
+ }
+
+ // Start the logging task
+ if (MAAP_LOG_FROM_THREAD) {
+ loggingThreadRunning = TRUE;
+ loggingThread = CreateThread(NULL, THREAD_STACK_SIZE, loggingThreadFn, NULL, 0, NULL);
+ if (loggingThread == NULL) {
+ fprintf(stderr, "Thread / task creation failed");
+ }
+ }
+}
+
+void maapLogExit()
+{
+ MUTEX_FREE_ALT(gLogMutex);
+
+ if (MAAP_LOG_FROM_THREAD) {
+ loggingThreadRunning = FALSE;
+ WaitForSingleObject(loggingThread, INFINITE);
+ }
+}
+
+void maapLogFn(
+ int level,
+ const char *tag,
+ const char *company,
+ const char *component,
+ const char *path,
+ int line,
+ const char *fmt,
+ ...)
+{
+ if (level <= MAAP_LOG_LEVEL) {
+ va_list args;
+ va_start(args, fmt);
+
+ LOG_LOCK();
+
+ vsprintf(msg, fmt, args);
+
+ if (MAAP_LOG_FILE_INFO && path) {
+ const char* file = strrchr(path, '/');
+ if (!file)
+ file = strrchr(path, '\\');
+ if (file)
+ file += 1;
+ else
+ file = (char*)path;
+ sprintf(file_msg, " %s:%d", file, line);
+ }
+ if (MAAP_LOG_PROC_INFO) {
+ sprintf(proc_msg, " P:%u", GetCurrentProcessId());
+ }
+ if (MAAP_LOG_THREAD_INFO) {
+ sprintf(thread_msg, " T:%u", GetCurrentThreadId());
+ }
+ if (MAAP_LOG_TIME_INFO) {
+ SYSTEMTIME nowST;
+ GetLocalTime(&nowST);
+
+ sprintf(time_msg, "%2.2d:%2.2d:%2.2d.%3.3d", nowST.wHour, nowST.wMinute, nowST.wSecond, nowST.wMilliseconds);
+ }
+ if (MAAP_LOG_TIMESTAMP_INFO) {
+ DWORD nowTicks = GetTickCount();
+
+ sprintf(timestamp_msg, "%7.7d.%3.3d", nowTicks / 1000, nowTicks % 1000);
+ }
+
+ // using sprintf and puts allows using static buffers rather than heap.
+ if (MAAP_LOG_EXTRA_NEWLINE)
+ /* int32_t full_msg_len = */ sprintf(full_msg, "[%s%s%s%s %s %s%s] %s: %s\n", time_msg, timestamp_msg, proc_msg, thread_msg, company, component, file_msg, tag, msg);
+ else
+ /* int32_t full_msg_len = */ sprintf(full_msg, "[%s%s%s%s %s %s%s] %s: %s", time_msg, timestamp_msg, proc_msg, thread_msg, company, component, file_msg, tag, msg);
+
+ if (!MAAP_LOG_FROM_THREAD && !MAAP_LOG_PULL_MODE) {
+ fputs(full_msg, MAAP_LOG_OUTPUT_FD);
+ }
+ else {
+ if (logQueue) {
+ maap_log_queue_elem_t elem = maapLogQueueHeadLock(logQueue);
+ if (elem) {
+ log_queue_item_t *pLogItem = (log_queue_item_t *)maapLogQueueData(elem);
+ pLogItem->bRT = FALSE;
+ strncpy((char *)pLogItem->msg, full_msg, LOG_QUEUE_MSG_LEN);
+ maapLogQueueHeadPush(logQueue);
+ }
+ }
+ }
+
+ va_end(args);
+
+ LOG_UNLOCK();
+ }
+}
+
+void maapLogRT(int level, int bBegin, int bItem, int bEnd, char *pFormat, log_rt_datatype_t dataType, void *pVar)
+{
+ if (level <= MAAP_LOG_LEVEL) {
+ if (logRTQueue) {
+ if (bBegin) {
+ maap_log_queue_elem_t elem;
+ LOG_LOCK();
+
+ elem = maapLogQueueHeadLock(logRTQueue);
+ if (elem) {
+ log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)maapLogQueueData(elem);
+ pLogRTItem->bEnd = FALSE;
+ pLogRTItem->pFormat = NULL;
+ pLogRTItem->dataType = LOG_RT_DATATYPE_NOW_TS;
+ GetLocalTime(&pLogRTItem->data.nowST);
+ maapLogQueueHeadPush(logRTQueue);
+ }
+ }
+
+ if (bItem) {
+ maap_log_queue_elem_t elem = maapLogQueueHeadLock(logRTQueue);
+ if (elem) {
+ log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)maapLogQueueData(elem);
+ if (bEnd)
+ pLogRTItem->bEnd = TRUE;
+ else
+ pLogRTItem->bEnd = FALSE;
+ pLogRTItem->pFormat = pFormat;
+ pLogRTItem->dataType = dataType;
+
+ switch (pLogRTItem->dataType) {
+ case LOG_RT_DATATYPE_CONST_STR:
+ break;
+ case LOG_RT_DATATYPE_U16:
+ pLogRTItem->data.unsignedLongVar = *(uint16_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_S16:
+ pLogRTItem->data.signedLongVar = *(int16_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_U32:
+ pLogRTItem->data.unsignedLongVar = *(uint32_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_S32:
+ pLogRTItem->data.signedLongVar = *(int32_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_U64:
+ pLogRTItem->data.unsignedLongLongVar = *(uint64_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_S64:
+ pLogRTItem->data.signedLongLongVar = *(int64_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_FLOAT:
+ pLogRTItem->data.floatVar = *(float *)pVar;
+ break;
+ default:
+ break;
+ }
+ maapLogQueueHeadPush(logRTQueue);
+ }
+ }
+
+ if (!bItem && bEnd) {
+ maap_log_queue_elem_t elem = maapLogQueueHeadLock(logRTQueue);
+ if (elem) {
+ log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)maapLogQueueData(elem);
+ pLogRTItem->bEnd = TRUE;
+ pLogRTItem->pFormat = NULL;
+ pLogRTItem->dataType = LOG_RT_DATATYPE_NONE;
+ maapLogQueueHeadPush(logRTQueue);
+ }
+ }
+
+ if (bEnd) {
+ if (logQueue) {
+ maap_log_queue_elem_t elem = maapLogQueueHeadLock(logQueue);
+ if (elem) {
+ log_queue_item_t *pLogItem = (log_queue_item_t *)maapLogQueueData(elem);
+ pLogItem->bRT = TRUE;
+ if (MAAP_LOG_FROM_THREAD) {
+ maapLogQueueHeadPush(logQueue);
+ } else {
+ maapLogRTRender(pLogItem);
+ fputs((const char *)pLogItem->msg, MAAP_LOG_OUTPUT_FD);
+ maapLogQueueHeadUnlock(logQueue);
+ }
+ }
+ }
+
+ LOG_UNLOCK();
+ }
+ }
+ }
+}
+
+void maapLogBuffer(
+ int level,
+ const uint8_t *pData,
+ int dataLen,
+ int lineLen,
+ const char *company,
+ const char *component,
+ const char *path,
+ int line)
+{
+ char szDataLine[ 400 ];
+ char *pszOut;
+ int i, j;
+
+ if (level > MAAP_LOG_LEVEL) { return; }
+
+ for (i = 0; i < dataLen; i += lineLen) {
+ /* Create the hexadecimal output for the buffer. */
+ pszOut = szDataLine;
+ *pszOut++ = '\t';
+ for (j = i; j < i + lineLen; ++j) {
+ if (j < dataLen) {
+ sprintf(pszOut, "%02x ", pData[j]);
+ } else {
+ strcpy(pszOut, " ");
+ }
+ pszOut += 3;
+ }
+
+ *pszOut++ = ' ';
+ *pszOut++ = ' ';
+
+ /* Append the ASCII equivalent of each character. */
+ for (j = i; j < dataLen && j < i + lineLen; ++j) {
+ if (pData[j] >= 0x20 && pData[j] < 0x7f) {
+ *pszOut++ = (char) pData[j];
+ } else {
+ *pszOut++ = '.';
+ }
+ }
+
+ /* Display this line of text. */
+ *pszOut = '\0';
+ maapLogFn(level, "BUFFER", company, component, path, line, "%s", szDataLine);
+ }
+}
diff --git a/daemons/maap/windows/src/maap_main.c b/daemons/maap/windows/src/maap_main.c
new file mode 100644
index 00000000..6c817d71
--- /dev/null
+++ b/daemons/maap/windows/src/maap_main.c
@@ -0,0 +1,3 @@
+/*
+ * TODO: This code still needs to be added!
+ */
diff --git a/daemons/maap/windows/src/maap_timer_windows.c b/daemons/maap/windows/src/maap_timer_windows.c
new file mode 100644
index 00000000..55615f04
--- /dev/null
+++ b/daemons/maap/windows/src/maap_timer_windows.c
@@ -0,0 +1,165 @@
+/*************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <signal.h>
+#include <string.h>
+#include <assert.h>
+#include <time.h>
+
+struct maap_timer {
+ /* Time values in nanoseconds */
+ uint64_t nStartTime;
+ uint64_t nExpireTime;
+};
+
+#include "maap_timer.h"
+
+#define MAAP_LOG_COMPONENT "Timer"
+#include "maap_log.h"
+
+
+/* Return the current time, in nanoseconds. */
+static uint64_t getCurrentTime(void)
+{
+ /* Using GetTickCount64() is not ideal, as it only provides a 10-16 millisecond resolution.
+ * However, for our purposes, it is sufficient.
+ * If higher precision is needed, QueryPerformanceCounter() is one possibility. */
+ uint64_t nTime = GetTickCount64();
+ nTime *= 1000000; /* Convert from milliseconds to nanoseconds */
+ return nTime;
+}
+
+/* Convert a Time structure to a nanoseconds value */
+static uint64_t timeToNanoseconds(const Time *t)
+{
+ uint64_t nTime =
+ ((uint64_t)t->tv_sec * 1000000000ULL) + /* Convert seconds to nanoseconds */
+ ((uint64_t)t->tv_usec * 1000ULL); /* Convert microseconds to nanoseconds */
+ return nTime;
+}
+
+
+Timer *Time_newTimer(void)
+{
+ Timer * newTimer = malloc(sizeof (Timer));
+ if (newTimer)
+ {
+ newTimer->nStartTime = newTimer->nExpireTime = 0ULL;
+ }
+ return newTimer;
+}
+
+void Time_delTimer(Timer *timer)
+{
+ assert(timer);
+ free(timer);
+}
+
+void Time_setTimer(Timer *timer, const Time *t)
+{
+ assert(timer);
+ timer->nStartTime = getCurrentTime();
+ timer->nExpireTime = timer->nStartTime + timeToNanoseconds(t);
+}
+
+int64_t Time_remaining(Timer *timer)
+{
+ uint64_t curr_value = getCurrentTime();
+
+ assert(timer);
+ if (curr_value >= timer->nExpireTime)
+ {
+ /* Timer has exired. */
+ return 0;
+ }
+ return (int64_t)(timer->nExpireTime - curr_value);
+}
+
+
+void Time_add(Time *a, const Time *b)
+{
+ a->tv_sec = a->tv_sec + b->tv_sec;
+ a->tv_usec = a->tv_usec + b->tv_usec;
+ if (a->tv_usec > 1000000L) {
+ a->tv_sec++;
+ a->tv_usec = a->tv_usec - 1000000L;
+ }
+}
+
+int64_t Time_diff(const Time *a, const Time *b)
+{
+ int64_t a_ns = (int64_t)timeToNanoseconds(a);
+ int64_t b_ns = (int64_t)timeToNanoseconds(b);
+ return b_ns - a_ns;
+}
+
+int Time_cmp(const Time *a, const Time *b)
+{
+ if (a->tv_sec < b->tv_sec) {
+ return -1;
+ }
+ if (a->tv_sec > b->tv_sec) {
+ return 1;
+ }
+ if (a->tv_usec < b->tv_usec) {
+ return -1;
+ }
+ if (a->tv_usec > b->tv_usec) {
+ return 1;
+ }
+ return 0;
+}
+
+int Time_passed(const Time *current, const Time *target)
+{
+ if (current->tv_sec < target->tv_sec) {
+ return 0;
+ }
+ if (current->tv_sec == target->tv_sec && current->tv_usec < target->tv_usec) {
+ return 0;
+ }
+ return 1;
+}
+
+void Time_setFromNanos(Time *t, uint64_t nsec)
+{
+ t->tv_sec = (long)(nsec / 1000000000LL);
+ t->tv_usec = (long)((nsec - (t->tv_sec * 1000000000LL)) / 1000LL);
+}
+
+void Time_setFromMonotonicTimer(Time *t)
+{
+ Time_setFromNanos(t, getCurrentTime());
+}
+
+const char * Time_dump(const Time *t)
+{
+ static char buffer[40];
+ sprintf(buffer, "%lu sec, %06lu usec", (unsigned long)t->tv_sec, (unsigned long)t->tv_usec);
+ return buffer;
+}
diff --git a/daemons/mrpd/mmrp.c b/daemons/mrpd/mmrp.c
index 741ab154..15fba7f0 100644
--- a/daemons/mrpd/mmrp.c
+++ b/daemons/mrpd/mmrp.c
@@ -327,6 +327,11 @@ int mmrp_event(int event, struct mmrp_attribute *rattrib)
attrib = mmrp_lookup(rattrib);
if (NULL == attrib) {
+ /* ignore rMT! if attribute does not already exist */
+ if (MRP_EVENT_RMT == event) {
+ free(rattrib);
+ return 0;
+ }
mmrp_add(rattrib);
attrib = rattrib;
} else {
@@ -1809,6 +1814,7 @@ void mmrp_reset(void)
sattrib = sattrib->next;
free(free_sattrib);
}
+ mrp_client_remove_all(&MMRP_db->mrp_db.clients);
free(MMRP_db);
}
diff --git a/daemons/mrpd/mrp.c b/daemons/mrpd/mrp.c
index 3a162b37..73831a6f 100644
--- a/daemons/mrpd/mrp.c
+++ b/daemons/mrpd/mrp.c
@@ -335,6 +335,21 @@ int mrp_client_delete(client_t ** list, struct sockaddr_in *newclient)
return 0;
}
+int mrp_client_remove_all(client_t ** list)
+{
+ client_t *client_item = *list;
+ client_t *client_next;
+
+ while (NULL != client_item) {
+ client_next = client_item->next;
+ free(client_item);
+ client_item = client_next;
+ }
+ *list = NULL;
+ return 0;
+}
+
+
int mrp_jointimer_start(struct mrp_database *mrp_db)
{
int ret = 0;
diff --git a/daemons/mrpd/mrp.h b/daemons/mrpd/mrp.h
index 8486b972..a54924b9 100644
--- a/daemons/mrpd/mrp.h
+++ b/daemons/mrpd/mrp.h
@@ -214,6 +214,7 @@ struct mrp_database {
int mrp_client_count(client_t * list);
int mrp_client_add(client_t ** list, struct sockaddr_in *newclient);
int mrp_client_delete(client_t ** list, struct sockaddr_in *newclient);
+int mrp_client_remove_all(client_t ** list);
int mrp_init(void);
char *mrp_event_string(int e);
diff --git a/daemons/mrpd/mrpctl.c b/daemons/mrpd/mrpctl.c
index 5ebe77a2..3a3e2add 100644
--- a/daemons/mrpd/mrpctl.c
+++ b/daemons/mrpd/mrpctl.c
@@ -261,8 +261,10 @@ int main(int argc, char *argv[])
if (-1 == rc) goto out;
/* yield replies */
- rc = mrpdclient_recv(mrpd_sock, process_ctl_msg);
- if (-1 == rc) goto out;
+ do {
+ rc = mrpdclient_recv(mrpd_sock, process_ctl_msg);
+ if (-1 == rc) goto out;
+ } while (rc >=0);
sleep(1);
} while (1);
diff --git a/daemons/mrpd/msrp.c b/daemons/mrpd/msrp.c
index 8dd127e4..4ce4bd90 100644
--- a/daemons/mrpd/msrp.c
+++ b/daemons/mrpd/msrp.c
@@ -124,7 +124,7 @@ void msrp_print_debug_info(int evt, const struct msrp_attribute *attrib)
}
#endif
-int msrp_count_type(int attrib_type)
+int msrp_count_type(uint32_t attrib_type)
{
int count = 0;
struct msrp_attribute *attrib;
@@ -581,6 +581,11 @@ int msrp_event(int event, struct msrp_attribute *rattrib)
attrib = msrp_lookup(rattrib);
if (NULL == attrib) {
+ /* ignore rMT! if attribute does not already exist */
+ if (MRP_EVENT_RMT == event) {
+ free(rattrib);
+ return 0;
+ }
msrp_add(rattrib);
attrib = rattrib;
} else {
@@ -628,6 +633,9 @@ int msrp_event(int event, struct msrp_attribute *rattrib)
#if LOG_MSRP
msrp_print_debug_info(event, attrib);
#endif
+ } else {
+ /* free this attrib if we are not interested */
+ free(rattrib);
}
break;
@@ -3899,6 +3907,7 @@ void msrp_reset(void)
free(free_sattrib);
}
eui64set_free(&MSRP_db->interesting_stream_ids);
+ mrp_client_remove_all(&MSRP_db->mrp_db.clients);
free(MSRP_db);
}
diff --git a/daemons/mrpd/msrp.h b/daemons/mrpd/msrp.h
index 7228e2e2..96d0eb5d 100644
--- a/daemons/mrpd/msrp.h
+++ b/daemons/mrpd/msrp.h
@@ -187,7 +187,7 @@ int msrp_recv_msg(void);
* \param attrib_type The attribute type to count.
* \return The number of attributes of type attrib_type in the MSRP database.
*/
-int msrp_count_type(int attrib_type);
+int msrp_count_type(uint32_t attrib_type);
/**
* Return the number of interesting talker stream ids recorded in the
diff --git a/daemons/mrpd/mvrp.c b/daemons/mrpd/mvrp.c
index 6b3c1678..b36e3ace 100644
--- a/daemons/mrpd/mvrp.c
+++ b/daemons/mrpd/mvrp.c
@@ -283,6 +283,11 @@ int mvrp_event(int event, struct mvrp_attribute *rattrib)
attrib = mvrp_lookup(rattrib);
if (NULL == attrib) {
+ /* ignore rMT! if attribute does not already exist */
+ if (MRP_EVENT_RMT == event) {
+ free(rattrib);
+ return 0;
+ }
mvrp_add(rattrib);
attrib = rattrib;
} else {
@@ -1349,6 +1354,7 @@ void mvrp_reset(void)
sattrib = sattrib->next;
free(free_sattrib);
}
+ mrp_client_remove_all(&MVRP_db->mrp_db.clients);
free(MVRP_db);
}
diff --git a/daemons/mrpd/tests/simple/CMakeLists.txt b/daemons/mrpd/tests/simple/CMakeLists.txt
index 3a79637c..a52790bc 100644
--- a/daemons/mrpd/tests/simple/CMakeLists.txt
+++ b/daemons/mrpd/tests/simple/CMakeLists.txt
@@ -2,7 +2,7 @@ cmake_minimum_required (VERSION 2.8)
project (mrpd_simple_test)
enable_testing()
-set (CPPUTEST_DIR "../../../../thirdparty/cpputest" )
+set (CPPUTEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../../thirdparty/cpputest )
set (SRC_DIR "../.." )
add_definitions(-DMRP_CPPUTEST)
@@ -10,16 +10,27 @@ include_directories( . "../../../common" ${CPPUTEST_DIR}/include )
file(GLOB CPPUTEST_SRC *.cpp)
file(GLOB MRPD_SRC ${SRC_DIR}/mrp.c ${SRC_DIR}/mvrp.c ${SRC_DIR}/mmrp.c ${SRC_DIR}/msrp.c "../../../common/parse.c" "../../../common/eui64set.c" )
+# memory leak test
+add_definitions(-DCPPUTEST_USE_MEM_LEAK_DETECTION)
+
if(APPLE)
+ set(CPPUTEST_C_FLAGS "${CPPUTEST_C_FLAGS} -include ${CPPUTEST_DIR}/include/CppUTest/MemoryLeakDetectorMallocMacros.h")
+ set(CPPUTEST_CXX_FLAGS "${CPPUTEST_CXX_FLAGS} -include ${CPPUTEST_DIR}/include/CppUTest/MemoryLeakDetectorNewMacros.h")
+ set(CPPUTEST_CXX_FLAGS "${CPPUTEST_CXX_FLAGS} -include ${CPPUTEST_DIR}/include/CppUTest/MemoryLeakDetectorMallocMacros.h")
include_directories( include ${CPPUTEST_DIR}/include/Platforms/Gcc )
add_executable (mrpd_simple_test ${MRPD_SRC} ${CPPUTEST_SRC} )
target_link_libraries(mrpd_simple_test CppUTest CppUTestExt)
elseif(UNIX)
+ set(CPPUTEST_C_FLAGS "${CPPUTEST_C_FLAGS} -include ${CPPUTEST_DIR}/include/CppUTest/MemoryLeakDetectorMallocMacros.h")
+ set(CPPUTEST_CXX_FLAGS "${CPPUTEST_CXX_FLAGS} -include ${CPPUTEST_DIR}/include/CppUTest/MemoryLeakDetectorNewMacros.h")
+ set(CPPUTEST_CXX_FLAGS "${CPPUTEST_CXX_FLAGS} -include ${CPPUTEST_DIR}/include/CppUTest/MemoryLeakDetectorMallocMacros.h")
include_directories( include ${CPPUTEST_DIR}/include/Platforms/Gcc )
link_directories(mrpd_simple_test ${CPPUTEST_DIR}/src/CppUTest ${CPPUTEST_DIR}/src/CppUTestExt )
add_executable (mrpd_simple_test ${MRPD_SRC} ${CPPUTEST_SRC} mrp_doubles.c)
target_link_libraries(mrpd_simple_test CppUTest CppUTestExt)
elseif(WIN32)
+ set(CPPUTEST_C_FLAGS "${CPPUTEST_C_FLAGS} /FI${CPPUTEST_DIR}/include/CppUTest/MemoryLeakDetectorMallocMacros.h")
+ set(CPPUTEST_CXX_FLAGS "${CPPUTEST_CXX_FLAGS} /FI${CPPUTEST_DIR}/include/CppUTest/MemoryLeakDetectorMallocMacros.h")
if( CMAKE_SIZEOF_VOID_P EQUAL 8 )
link_directories(mrpd_simple_test $ENV{WPCAP_DIR}/Lib/x64 ${CPPUTEST_DIR}/src/CppUTest ${CPPUTEST_DIR}/src/CppUTestExt)
elseif( CMAKE_SIZEOF_VOID_P EQUAL 4 )
@@ -32,4 +43,7 @@ elseif(WIN32)
target_link_libraries(mrpd_simple_test wpcap Iphlpapi Ws2_32 CppUTest CppUTestExt)
endif()
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CPPUTEST_C_FLAGS}")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CPPUTEST_CXX_FLAGS}")
+
add_test( test_mrpd mrpd_simple_test -v )
diff --git a/daemons/mrpd/tests/simple/mrp_doubles.c b/daemons/mrpd/tests/simple/mrp_doubles.c
index 859b5d6c..935e24da 100644
--- a/daemons/mrpd/tests/simple/mrp_doubles.c
+++ b/daemons/mrpd/tests/simple/mrp_doubles.c
@@ -42,6 +42,8 @@ TRACE
memset(test_state.tx_PDU, 0, MAX_FRAME_SIZE);
test_state.sent_count = 0;
+ test_state.sent_ctl_msg_count = 0;
+
memset(test_state.msrp_event_counts, 0, sizeof test_state.msrp_event_counts);
memset(test_state.msrp_event_counts_per_type, 0, sizeof test_state.msrp_event_counts_per_type);
test_state.forward_msrp_events = 1;
@@ -168,6 +170,7 @@ TRACE
(void)client_addr; /* unused */
memcpy(test_state.ctl_msg_data, notify_data, notify_len);
+ test_state.sent_ctl_msg_count++;
return notify_len;
}
@@ -295,6 +298,12 @@ int msrp_event(int event, struct msrp_attribute *rattrib) {
}
if (test_state.forward_msrp_events) {
msrp_event_orig(event, rattrib);
+ } else {
+ /* RLA event has free embedded in the packet processing for some reason */
+ if (MRP_EVENT_RLA != event) {
+ /* if rattrib is not forwarded to MSRP stack, need to free it */
+ free(rattrib);
+ }
}
return 0;
}
diff --git a/daemons/mrpd/tests/simple/mrp_doubles.h b/daemons/mrpd/tests/simple/mrp_doubles.h
index 92534f92..6ca96398 100644
--- a/daemons/mrpd/tests/simple/mrp_doubles.h
+++ b/daemons/mrpd/tests/simple/mrp_doubles.h
@@ -60,6 +60,13 @@ typedef void (*msrp_observer_t)(int event, struct msrp_attribute *attrib);
*/
void dump_msrp_attrib(struct msrp_attribute *attr);
+/**
+* Callback function type that can be used to observe and validate
+* MVRP events
+*/
+typedef void(*mvrp_observer_t)(int event, struct mvrp_attribute *attrib);
+
+
/**
* Structure that holds all test double state.
@@ -88,12 +95,20 @@ struct mrpd_test_state {
size_t tx_PDU_len;
int sent_count;
+ /* CTL Msg */
+ int sent_ctl_msg_count;
+
/* MSRP Events */
uint16_t msrp_event_counts[21];
uint16_t msrp_event_counts_per_type[4][21];
int forward_msrp_events;
msrp_observer_t msrp_observe;
+ /* MVRP Events */
+ uint16_t mvrp_event_counts[21];
+ int forward_mvrp_events;
+ mvrp_observer_t mvrp_observe;
+
/* Log Buffer */
char mrpd_log[MRPD_DOUBLE_LOG_SIZE];
};
diff --git a/daemons/mrpd/tests/simple/mvrp_pdu_tests.cpp b/daemons/mrpd/tests/simple/mvrp_pdu_tests.cpp
new file mode 100644
index 00000000..d8e4a12a
--- /dev/null
+++ b/daemons/mrpd/tests/simple/mvrp_pdu_tests.cpp
@@ -0,0 +1,157 @@
+#ifdef __linux__
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+#else
+typedef __int32 int32_t;
+typedef unsigned __int32 uint32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#define PRIu64 "I64u"
+#define PRIx64 "I64x"
+#endif
+
+#include "CppUTest/TestHarness.h"
+
+extern "C"
+{
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "mrp_doubles.h"
+#include "mrp.h"
+#include "mvrp.h"
+#include "parse.h"
+
+/* Most MVRP commands operate on the global DB */
+extern struct mvrp_database *MVRP_db;
+
+void mvrp_event_observer(int event, struct mvrp_attribute *attr);
+char *mvrp_attrib_type_string(int t);
+char *mrp_event_string(int e);
+}
+
+/* This include file contains all the byte buffers implementing
+ * packets for the tests */
+#include "sample_mvrp_packets.h"
+
+/* Needed for mvrp_recv_cmd() */
+static struct sockaddr_in client;
+
+/*
+ * The test_state keeps track of counts of all events that are
+ * triggered during a test, and these functions show how to read
+ * them.
+ */
+
+static void mvrp_dump_events() {
+ int i, evtid, evtcount;
+ evtcount = (sizeof test_state.mvrp_event_counts /
+ sizeof *test_state.mvrp_event_counts);
+ printf("\nMVRP Event Counts:\n");
+ for (i = 0; i < evtcount; i++) {
+ if (test_state.mvrp_event_counts[i] > 0) {
+ printf("%s: %d\n", mrp_event_string(MSRP_EVENT_ID(i)),
+ test_state.mvrp_event_counts[i]);
+ }
+ }
+}
+
+static int mvrp_count_events() {
+ int i, total, evtcount;
+ evtcount = (sizeof test_state.mvrp_event_counts /
+ sizeof *test_state.mvrp_event_counts);
+ total = 0;
+ for (i = 0; i < evtcount; i++) {
+ total += test_state.mvrp_event_counts[i];
+ }
+ return total;
+}
+
+int mvrp_tests_cmd_ok(const char *zstr)
+{
+ int status;
+
+ status = (zstr[0] != 'E') && (zstr[1] != 'R');
+
+ return status;
+}
+
+/* A sample event observer; this is called on every event generated by
+ * the mvrp_recv_msg function, so each attribute parsed will be passed
+ * to it in turn and can be analyzed. The following line inserted into
+ * a test will enable it:
+ *
+ * test_state.mvrp_observe = mvrp_event_observer;
+ */
+void mvrp_event_observer(int event, struct mvrp_attribute *attr)
+{
+ printf("Event: %s vlan: %02d",
+ mrp_event_string(event),
+ attr->attribute);
+}
+
+/* Test doubles for the mrpd functionality enable feeding PDU buffers
+ * into the msrp code as if they were received from the network and
+ * observing the resulting MSRP events.
+ *
+ * test_state.rx_PDU - a buffer to hold packet data for simulated Rx
+ *
+ * test_state.rx_PDU_len - store the length of stored PDU data here
+ *
+ * test_state.forward_msrp_events - when set to 0, only the test
+ * double code for observing events will run. When set to 1, the
+ * observation code will run and then the events will pass to the
+ * normal processing.
+ *
+ * test_state.msrp_observe - a function pointer that, if not NULL,
+ * will be called on every event that occurs during a test.
+ */
+
+/******* Start of test cases *******/
+
+TEST_GROUP(MvrpPDUTests)
+{
+ void setup() {
+ mrpd_reset();
+ mvrp_init(1);
+ test_state.forward_mvrp_events = 0;
+ }
+ void teardown() {
+ mvrp_reset();
+ mrpd_reset();
+ }
+};
+
+/*
+ * This is a sample packet captured via wireshark. In this case the
+ * packet contains a single rJoinMT! and more than 4000 rMT!. This
+ * test verfies that the rMT! events are ignored.
+ */
+TEST(MvrpPDUTests, ParsePkt1)
+{
+ static struct sockaddr_in client1;
+ int rv;
+
+ memset(&client1, 0, sizeof(client1));
+
+ /* no error returned for first client */
+ mvrp_recv_cmd("V??", strlen("V??") + 1, &client1);
+ CHECK(mvrp_tests_cmd_ok(test_state.ctl_msg_data));
+ /* one client notification sent in response to V?? */
+ LONGS_EQUAL(1, test_state.sent_ctl_msg_count);
+
+ memcpy(test_state.rx_PDU, mvrp_pdu_pkt1, sizeof mvrp_pdu_pkt1);
+ test_state.rx_PDU_len = sizeof mvrp_pdu_pkt1;
+ rv = mvrp_recv_msg();
+ LONGS_EQUAL(0, rv);
+ /* no errors send to client */
+ CHECK(mvrp_tests_cmd_ok(test_state.ctl_msg_data));
+ /*
+ * second client notification sent in response to PDU decode.
+ * Notifcations that could potentially be generated from each
+ * rMT! event in the packet are ignored.
+ */
+ LONGS_EQUAL(2, test_state.sent_ctl_msg_count);
+
+}
diff --git a/daemons/mrpd/tests/simple/parse_tests.cpp b/daemons/mrpd/tests/simple/parse_tests.cpp
index b7bdfe7d..f66b2f27 100644
--- a/daemons/mrpd/tests/simple/parse_tests.cpp
+++ b/daemons/mrpd/tests/simple/parse_tests.cpp
@@ -70,7 +70,7 @@ TEST(ParseTestGroup, TestParse_null)
int err_index;
int status;
struct parse_param specs[] = {
- { "C" PARSE_ASSIGN, parse_null, &value },
+ { (char*)"C" PARSE_ASSIGN, parse_null, &value },
{ 0, parse_null, 0 }};
const char strz[] = "C=1234";
@@ -96,7 +96,7 @@ TEST(ParseTestGroup, TestParse_u8)
int err_index;
int status;
struct parse_param specs[] = {
- { "C" PARSE_ASSIGN, parse_u8, &value },
+ { (char*)"C" PARSE_ASSIGN, parse_u8, &value },
{ 0, parse_null, 0 } };
char strz[64];
int i;
@@ -147,7 +147,7 @@ TEST(ParseTestGroup, TestParse_u16)
int err_index;
int status;
struct parse_param specs[] = {
- { "C" PARSE_ASSIGN, parse_u16, &value },
+ { (char*)"C" PARSE_ASSIGN, parse_u16, &value },
{ 0, parse_null, 0 } };
char strz[64];
int i;
@@ -197,7 +197,7 @@ TEST(ParseTestGroup, TestParse_u16_04x)
int err_index;
int status;
struct parse_param specs[] = {
- { "C" PARSE_ASSIGN, parse_u16_04x, &value },
+ { (char*)"C" PARSE_ASSIGN, parse_u16_04x, &value },
{ 0, parse_null, 0 } };
char strz[64];
int i;
@@ -247,7 +247,7 @@ TEST(ParseTestGroup, TestParse_u32)
int err_index;
int status;
struct parse_param specs[] = {
- { "C" PARSE_ASSIGN, parse_u32, &value },
+ { (char*)"C" PARSE_ASSIGN, parse_u32, &value },
{ 0, parse_null, 0 } };
char strz[64];
int i;
@@ -298,13 +298,13 @@ TEST(ParseTestGroup, TestParse_u64)
int err_index;
int status;
struct parse_param specsu[] = {
- { "C" PARSE_ASSIGN, parse_u64, &value },
+ { (char*)"C" PARSE_ASSIGN, parse_u64, &value },
{ 0, parse_null, 0 } };
struct parse_param specsx[] = {
- { "C" PARSE_ASSIGN, parse_h64, &value },
+ { (char*)"C" PARSE_ASSIGN, parse_h64, &value },
{ 0, parse_null, 0 } };
struct parse_param specsc[] = {
- { "C" PARSE_ASSIGN, parse_c64, &stream_id },
+ { (char*)"C" PARSE_ASSIGN, parse_c64, &stream_id },
{ 0, parse_null, 0 } };
char strz[64];
int i, j;
diff --git a/daemons/mrpd/tests/simple/sample_mvrp_packets.h b/daemons/mrpd/tests/simple/sample_mvrp_packets.h
new file mode 100644
index 00000000..71eb3849
--- /dev/null
+++ b/daemons/mrpd/tests/simple/sample_mvrp_packets.h
@@ -0,0 +1,117 @@
+/*
+ * This file contains some sample MVRP packets for testing purposes as
+ * byte buffers. The buffers have been heavily annotated for
+ * verification and analysis purposes.
+ */
+
+/* This is from a live capture; a device is sending a LeaveAll event */
+unsigned char mvrp_pdu_pkt1[] = {
+
+ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x21, /* Destination MAC */
+ 0x00, 0x02, 0x03, 0x04, 0x1b, 0x85, /* Source MAC */
+ 0x88, 0xf5, /* Ethertype */
+
+ 0x00, /* Protocol vesrion */
+
+ 0x01, /* VLAN Id */
+
+ 0x02, /* attrib len */
+
+ 0x00f, 0xfe, /* number of values */
+ 0x00, 0x01, /* First value */
+
+ 0x88, /* Attibute event JointMT, MT, MT*/
+
+ /* A LOT of MT */
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac,
+ 0xa8,
+
+ 0x00, 0x00, /* EndMark */
+
+ 0x00, 0x00 /* EndMark */
+};
diff --git a/daemons/shaper/LICENSE b/daemons/shaper/LICENSE
new file mode 100644
index 00000000..9a67d06a
--- /dev/null
+++ b/daemons/shaper/LICENSE
@@ -0,0 +1,25 @@
+/*************************************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************************************/
+
diff --git a/daemons/shaper/Makefile b/daemons/shaper/Makefile
new file mode 100644
index 00000000..13e4b037
--- /dev/null
+++ b/daemons/shaper/Makefile
@@ -0,0 +1,37 @@
+CC ?= gcc
+OPT = -O2 -g
+CFLAGS = $(OPT) -Wall -Wextra
+INCFLAGS =
+LDLIBS = -lm -pthread
+
+SRC_DIR = src
+OUT_O_DIR = build
+
+all: shaper_daemon
+
+shaper_daemon: \
+ $(OUT_O_DIR)/shaper_daemon.o \
+ $(OUT_O_DIR)/shaper_log_queue.o \
+ $(OUT_O_DIR)/shaper_log_linux.o
+
+$(OUT_O_DIR)/shaper_daemon.o: $(SRC_DIR)/shaper_daemon.c \
+ $(SRC_DIR)/shaper_log.h
+ @mkdir -p $(@D)
+ $(CC) $(CFLAGS) $(INCFLAGS) -c $(SRC_DIR)/shaper_daemon.c -o $(OUT_O_DIR)/shaper_daemon.o
+
+$(OUT_O_DIR)/shaper_log_queue.o: $(SRC_DIR)/shaper_log_queue.c \
+ $(SRC_DIR)/shaper_log.h $(SRC_DIR)/shaper_log_queue.h
+ @mkdir -p $(@D)
+ $(CC) $(CFLAGS) $(INCFLAGS) -c $(SRC_DIR)/shaper_log_queue.c -o $(OUT_O_DIR)/shaper_log_queue.o
+
+$(OUT_O_DIR)/shaper_log_linux.o: $(SRC_DIR)/shaper_log_linux.c \
+ $(SRC_DIR)/platform.h $(SRC_DIR)/shaper_log.h $(SRC_DIR)/shaper_log_queue.h $(SRC_DIR)/shaper_helper_linux.h
+ @mkdir -p $(@D)
+ $(CC) $(CFLAGS) $(INCFLAGS) -c $(SRC_DIR)/shaper_log_linux.c -o $(OUT_O_DIR)/shaper_log_linux.o
+
+%: $(OUT_O_DIR)/%.o
+ $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
+
+clean:
+ $(RM) shaper_daemon
+ $(RM) -r $(OUT_O_DIR)
diff --git a/daemons/shaper/README.rst b/daemons/shaper/README.rst
new file mode 100644
index 00000000..370ae1b7
--- /dev/null
+++ b/daemons/shaper/README.rst
@@ -0,0 +1,38 @@
+OpenAvnu Traffic Shaping Daemon
+===============================
+
+.. contents::
+..
+ 1 Introduction
+ 2 Support
+ 3 Future Updates
+
+Introduction
+------------
+
+The shaper daemon is an interface to use the tc (Traffic Control) command to
+configure the kernel traffic shaping with the Hierarchy Token Bucket. While
+tc could be called directly, using the daemon allows for a simpler interface
+and keeps track of the current traffic shaping configurations in use.
+
+Support
+-------
+
+To enable the Shaper daemon support for AVTP Pipeline, edit the endpoint.ini
+file and uncomment the port=15365 line of the shaper section.
+
+The Shaper daemon does not work (i.e. no shaping occurs) if the Intel IGB
+support is loaded for the adapter being used. You may also need to compile
+the AVTP Pipeline with PLATFORM_TOOLCHAIN=generic to not include the IGB
+features.
+
+Future Updates
+--------------
+
+- Have the daemon verify that tc is installed
+- Have the daemon verify that the kernel is configured to support Hierarchy
+ Token Bucket traffic shaping
+- Add a method to interlace frames from multiple streams of the same class
+ (perhaps using multiple layers of queues)
+- Add updates to support IEEE 802.1Qcc configurable classes
+
diff --git a/daemons/shaper/src/platform.h b/daemons/shaper/src/platform.h
new file mode 100644
index 00000000..3691d584
--- /dev/null
+++ b/daemons/shaper/src/platform.h
@@ -0,0 +1,74 @@
+/*************************************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************************************/
+
+#ifndef MAAP_PLATFORM_H
+#define MAAP_PLATFORM_H
+
+#if defined(__linux__)
+
+#include <endian.h>
+#include <time.h>
+
+#define OS_TIME_TYPE struct timespec
+
+#elif defined(__APPLE__)
+
+#include <libkern/OSByteOrder.h>
+#include <sys/time.h>
+
+#define htobe16(x) OSSwapHostToBigInt16(x)
+#define be16toh(x) OSSwapBigToHostInt16(x)
+#define htobe64(x) OSSwapHostToBigInt64(x)
+#define be64toh(x) OSSwapBigToHostInt64(x)
+
+#define ETH_ALEN 6
+
+#define OS_TIME_TYPE struct timeval
+
+#elif defined(_WIN32)
+
+#include <Winsock2.h>
+
+#define htobe16(x) htons(x)
+#define be16toh(x) ntohs(x)
+#define htobe64(x) ((htonl(1) == 1) ? x : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
+#define be64toh(x) ((ntohl(1) == 1) ? x : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))
+
+#define OS_TIME_TYPE struct timeval
+
+#else
+
+#error Please create the platform support definitions for this platform
+
+#endif
+
+
+#define HTOBE16(x) htobe16(x)
+#define BE16TOH(x) be16toh(x)
+#define HTOBE64(x) htobe64(x)
+#define BE64TOH(x) be64toh(x)
+
+
+#endif
diff --git a/daemons/shaper/src/shaper_daemon.c b/daemons/shaper/src/shaper_daemon.c
new file mode 100644
index 00000000..1ef6a69c
--- /dev/null
+++ b/daemons/shaper/src/shaper_daemon.c
@@ -0,0 +1,986 @@
+/*************************************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************************************/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <ctype.h>
+#include <net/if.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#define SHAPER_LOG_COMPONENT "Main"
+#include "shaper_log.h"
+
+#define STREAMDA_LENGTH 18
+#define SHAPER_PORT 15365 /* Unassigned at https://www.iana.org/assignments/port-numbers */
+#define MAX_CLIENT_CONNECTIONS 10
+#define USER_COMMAND_PROMPT "\nEnter the command: "
+
+typedef struct cmd_ip
+{
+ int reserve_bw;
+ int unreserve_bw;
+ char interface[IFNAMSIZ];
+ int class_a, class_b;
+ int measurement_interval;//usec
+ int max_frame_size;
+ int max_frame_interval;
+ char stream_da[STREAMDA_LENGTH];
+ int delete_qdisc;
+ int quit;
+} cmd_ip;
+
+typedef struct stream_da
+{
+ char dest_addr[STREAMDA_LENGTH];
+ int bandwidth;
+ char class_id[5];
+ int filter_handle;
+ struct stream_da *next;
+} stream_da;
+
+stream_da *head = NULL;
+int sr_classa=0, sr_classb=0;
+int classa_48=0, classa_44=0, classb_48=0, classb_44=0;
+int classa_bw_48=0, classa_bw_44=0, classb_bw_48=0, classb_bw_44=0;
+int daemonize=0,c=0;
+int filterhandle_classa=1,filterhandle_classb=20;
+char classid_a_48[]="2:10";
+char classid_a_44[]="2:20";
+char classid_b_48[]="3:30";
+char classid_b_44[]="3:40";
+char interface[IFNAMSIZ] = {0};
+int bandwidth = 0;
+int classa_parent = 2, classb_parent=3;
+int exit_received = 0;
+
+static void signal_handler(int signal)
+{
+ if (signal == SIGINT || signal == SIGTERM) {
+ if (!exit_received) {
+ SHAPER_LOG_INFO("Shutdown signal received");
+ exit_received = 1;
+ }
+ else {
+ // Force shutdown
+ exit(2);
+ }
+ }
+ else if (signal == SIGUSR1) {
+ SHAPER_LOG_DEBUG("Waking up streaming thread");
+ }
+ else {
+ SHAPER_LOG_ERROR("Unexpected signal");
+ }
+}
+
+void log_client_error_message(int sockfd, const char *fmt, ...)
+{
+ static char error_msg[200], combined_error_msg[250];
+ va_list args;
+
+ if (SHAPER_LOG_LEVEL_ERROR > SHAPER_LOG_LEVEL)
+ {
+ return;
+ }
+
+ /* Get the error message. */
+ va_start(args, fmt);
+ vsprintf(error_msg, fmt, args);
+ va_end(args);
+
+ if (sockfd < 0)
+ {
+ /* Received from stdin. Just log this error. */
+ SHAPER_LOG_ERROR(error_msg);
+ }
+ else
+ {
+ /* Log this as a remote client error. */
+ sprintf(combined_error_msg, "Client %d: %s", sockfd, error_msg);
+ SHAPER_LOG_ERROR(combined_error_msg);
+
+ /* Send the error message to the client. */
+ sprintf(combined_error_msg, "ERROR: %s\n", error_msg);
+ send(sockfd, combined_error_msg, strlen(combined_error_msg), 0);
+ }
+}
+
+void log_client_debug_message(int sockfd, const char *fmt, ...)
+{
+ static char debug_msg[200], combined_debug_msg[250];
+ va_list args;
+
+ if (SHAPER_LOG_LEVEL_DEBUG > SHAPER_LOG_LEVEL)
+ {
+ return;
+ }
+
+ /* Get the debug message. */
+ va_start(args, fmt);
+ vsprintf(debug_msg, fmt, args);
+ va_end(args);
+
+ if (sockfd < 0)
+ {
+ /* Received from stdin. Just log this message. */
+ SHAPER_LOG_DEBUG(debug_msg);
+ }
+ else
+ {
+ /* Log this as a remote client message. */
+ sprintf(combined_debug_msg, "Client %d: %s", sockfd, debug_msg);
+ SHAPER_LOG_DEBUG(combined_debug_msg);
+
+ /* Send the message to the client. */
+ sprintf(combined_debug_msg, "DEBUG: %s\n", debug_msg);
+ send(sockfd, combined_debug_msg, strlen(combined_debug_msg), 0);
+ }
+}
+
+int is_empty()
+{
+ return head == NULL;
+}
+
+void insert_stream_da(int sockfd, char dest_addr[], int bandwidth, char class_id[], int filter_handle)
+{
+ stream_da *node = (stream_da *)malloc(sizeof(stream_da));
+ if (node == NULL)
+ {
+ log_client_error_message(sockfd, "Unable to allocate memory. Exiting program");
+ shaperLogExit();
+ exit(1);
+ }
+ strcpy(node->dest_addr,dest_addr);
+ node->bandwidth = bandwidth;
+ strcpy(node->class_id,class_id);
+ node->filter_handle=filter_handle;
+ node->next = NULL;
+ if (is_empty())
+ {
+ head = node;
+ }
+ else
+ {
+ stream_da *current = head;
+ while (current->next != NULL)
+ {
+ current = current->next;
+ }
+ current->next = node;
+ }
+}
+
+int check_stream_da(int sockfd, char dest_addr[])
+{
+ stream_da *current = head;
+ while (current != NULL)
+ {
+ if (!strcmp(current->dest_addr, dest_addr))
+ {
+ log_client_error_message(sockfd, "Stream DA already present");
+ return 1;
+ }
+ current = current->next;
+ }
+ return 0;
+}
+
+stream_da* get_stream_da(int sockfd, char dest_addr[])
+{
+ stream_da *current = head;
+ while (current != NULL)
+ {
+ if (!strcmp(current->dest_addr, dest_addr))
+ {
+
+ return current;
+ }
+ current = current->next;
+ }
+ log_client_error_message(sockfd, "Unknown Stream DA");
+ return NULL;
+}
+
+void remove_stream_da(int sockfd, char dest_addr[])
+{
+ stream_da *current = head;
+ (void) sockfd;
+
+ if (current != NULL && !strcmp(current->dest_addr, dest_addr))
+ {
+ head = current->next;
+ free(current);
+ return;
+ }
+
+ while (current->next != NULL)
+ {
+ if (!strcmp(current->next->dest_addr, dest_addr))
+ {
+ stream_da *temp = current->next;
+ current->next = current->next->next;
+ free(temp);
+ return;
+ }
+ current = current->next;
+ }
+}
+
+void delete_streamda_list()
+{
+ stream_da *current = head;
+ stream_da *next = NULL;
+ while (current != NULL)
+ {
+ next = current->next;
+ free(current);
+ current = next;
+ }
+ head = NULL;
+}
+
+void usage (int sockfd)
+{
+ const char *usage = "Usage:\n"
+ " -r Reserve Bandwidth\n"
+ " -u Unreserve Bandwidth\n"
+ " -i Interface\n"
+ " -c Class ('A' or 'B')\n"
+ " -s Measurement interval (in microseconds)\n"
+ " -b Maximum frame size (in bytes)\n"
+ " -f Maximum frame interval\n"
+ " -a Stream Destination Address\n"
+ " -d Delete qdisc\n"
+ " -q Quit Application\n"
+ "Reserving Bandwidth Example:\n"
+ " -ri eth2 -c A -s 125 -b 74 -f 1 -a ff:ff:ff:ff:ff:11\n"
+ "Unreserving Bandwidth Example:\n"
+ " -ua ff:ff:ff:ff:ff:11\n"
+ "Quit Example:\n"
+ " -q\n"
+ "Delete qdisc Example:\n"
+ " -d\n";
+ if (sockfd < 0)
+ {
+ printf("%s",usage);
+ }
+ else
+ {
+ send(sockfd, usage, strlen(usage),0);
+ }
+
+}
+
+cmd_ip parse_cmd(char command[])
+{
+ cmd_ip inputs={0};
+ int i=0;
+ char temp[100];
+ while(command[i++] != '\0')
+ {
+
+ if (command[i] == 'r')
+ {
+ inputs.reserve_bw=1;
+ i++;
+ }
+
+ if (command[i] == 'u')
+ {
+ inputs.unreserve_bw=1;
+ i++;
+ }
+
+ if (command[i] == 'i')
+ {
+ int k=0;
+ i = i+2;
+ while (command[i] != ' ' && k < IFNAMSIZ-1)
+ {
+ inputs.interface[k] = command[i];
+ k++;i++;
+ }
+ inputs.interface[k] = '\0';
+ }
+
+ if (command[i] == 'c')
+ {
+ i = i+2;
+ if (command[i] == 'A' || command[i] == 'a')
+ {
+ inputs.class_a = 1;
+ }
+ else if (command[i] == 'B' || command[i] == 'b')
+ {
+ inputs.class_b = 1;
+ }
+ i++;
+ }
+
+ if (command[i] == 's')
+ {
+ int k=0;
+ i = i+2;
+ while (command[i] != ' ' && k < (int) sizeof(temp)-1)
+ {
+ temp[k] = command[i];
+ k++;i++;
+ }
+ temp[k] = '\0';
+ inputs.measurement_interval = atoi(temp);
+ }
+
+ if (command[i] == 'b')
+ {
+ int k=0;
+ i = i+2;
+ while (command[i] != ' ' && k < (int) sizeof(temp)-1)
+ {
+ temp[k] = command[i];
+ k++;i++;
+ }
+ temp[k] = '\0';
+ inputs.max_frame_size = atoi(temp);
+ }
+
+ if (command[i] == 'f')
+ {
+ int k=0;
+ i = i+2;
+ while (command[i] != ' ' && k < (int) sizeof(temp)-1)
+ {
+ temp[k] = command[i];
+ k++;i++;
+ }
+ temp[k] = '\0';
+ inputs.max_frame_interval = atoi(temp);
+ }
+
+ if (command[i] == 'a')
+ {
+ int k=0;
+ i = i+2;
+ while (command[i] != ' ' && k < STREAMDA_LENGTH-1)
+ {
+ inputs.stream_da[k] = command[i];
+ k++;i++;
+ }
+ inputs.stream_da[k] = '\0';
+ }
+
+ if (command[i] == 'd')
+ {
+ inputs.delete_qdisc=1;
+ i++;
+ }
+
+ if (command[i] == 'q')
+ {
+ inputs.quit = 1;
+ i++;
+ }
+ }
+ return inputs;
+}
+
+void tc_class_command(int sockfd, char command[], char class_id[], char interface[], int bandwidth, int cburst)
+{
+ char tc_command[1000]={0};
+ sprintf(tc_command, "tc class %s dev %s classid %s htb rate %dbps cburst %d",
+ command, interface, class_id, bandwidth, cburst);
+ log_client_debug_message(sockfd, "tc command: \"%s\"", tc_command);
+ if (system(tc_command) < 0)
+ {
+ log_client_error_message(sockfd, "command(\"%s\") failed", tc_command);
+ }
+}
+
+void add_filter(int sockfd, char interface[], int parent, int filter_handle, char class_id[], char dest_addr[])
+{
+ char tc_command[1000]={0};
+ sprintf(tc_command, "tc filter add dev %s prio 1 handle 800::%d parent %d: u32 classid %s match ether dst %s",
+ interface, filter_handle, parent, class_id, dest_addr);
+ log_client_debug_message(sockfd, "tc command: \"%s\"", tc_command);
+ if (system(tc_command) < 0)
+ {
+ log_client_error_message(sockfd, "command(\"%s\") failed", tc_command);
+ }
+}
+
+// Returns 1 if successful, -1 on an error, or 0 if exit requested.
+int process_command(int sockfd, char command[])
+{
+ cmd_ip input = parse_cmd(command);
+ char tc_command[1000]={0};
+ int maxburst = 0;
+
+ if (input.reserve_bw && input.unreserve_bw)
+ {
+ log_client_error_message(sockfd, "Cannot reserve and unreserve bandwidth at the same time");
+ usage(sockfd);
+ return -1;
+ }
+
+
+ if (input.reserve_bw)
+ {
+ if (input.max_frame_size == 0 || input.measurement_interval == 0 || input.max_frame_interval == 0 ||
+ (!input.class_a && !input.class_b))
+ {
+ log_client_error_message(sockfd, "class, max_frame_size, measurement_interval and max_frame_interval are mandatory inputs");
+ usage(sockfd);
+ return -1;
+ }
+
+ if (input.class_a && input.class_b)
+ {
+ log_client_error_message(sockfd, "Cannot reserve for both class A and class B");
+ usage(sockfd);
+ return -1;
+ }
+ }
+ if (input.unreserve_bw)
+ {
+ if (input.stream_da == 0)
+ {
+ log_client_error_message(sockfd, "Stream Destination Address is required to unreserve bandwidth");
+ usage(sockfd);
+ return -1;
+ }
+ }
+ if ((input.quit==1 || input.delete_qdisc==1) &&(input.reserve_bw==1 || input.unreserve_bw==1))
+ {
+ log_client_error_message(sockfd, "Quit or Delete cannot be used with other commands");
+ usage(sockfd);
+ return -1;
+ }
+
+ if (input.quit == 1 || input.delete_qdisc == 1)
+ {
+ if (sr_classa != 0 || sr_classb != 0)
+ {
+ //delete all the Stream DAs in list
+ delete_streamda_list();
+ if (strlen(interface) != 0)
+ {
+ //delete qdisc
+ sprintf(tc_command, "tc qdisc del dev %s root handle 1:", interface);
+ log_client_debug_message(sockfd, "tc command: \"%s\"", tc_command);
+ if (system(tc_command) < 0)
+ {
+ log_client_error_message(sockfd, "command(\"%s\") failed", tc_command);
+ }
+ }
+ sr_classa = sr_classb = 0;
+ classa_48 = classa_44 = classb_48 = classb_44 = 0;
+ classa_bw_48 = classa_bw_44 = classb_bw_48 = classb_bw_44 = 0;
+ }
+
+ if (input.quit == 1)
+ {
+ return 0;
+ }
+ }
+
+ if (sr_classa == 0 && sr_classb == 0)
+ {
+ //Initializing qdisc
+ if (strlen(input.interface)==0)
+ {
+ if (input.unreserve_bw || input.reserve_bw)
+ {
+ log_client_error_message(sockfd, "Interface is mandatory for the first command");
+ }
+ usage(sockfd);
+ return -1;
+ }
+ sprintf(tc_command, "tc qdisc add dev %s root handle 1: mqprio num_tc 4 map 3 3 1 0 2 2 2 2 2 2 2 2 2 2 2 2 queues 1@0 1@1 1@2 1@3 hw 0", input.interface);
+ log_client_debug_message(sockfd, "tc command: \"%s\"", tc_command);
+ if (system(tc_command) < 0)
+ {
+ log_client_error_message(sockfd, "command(\"%s\") failed", tc_command);
+ return -1;
+ }
+ strcpy(interface,input.interface);
+ }
+
+ if (input.unreserve_bw || input.reserve_bw)
+ {
+ bandwidth = ceil(((1/(input.measurement_interval*pow(10,-6))) * (input.max_frame_size*8) * input.max_frame_interval) / 8);
+ maxburst = input.max_frame_size*input.max_frame_interval*2;
+ }
+
+ if (input.reserve_bw == 1)
+ {
+ if (check_stream_da(sockfd, input.stream_da))
+ {
+ return 1;
+ }
+ if (input.class_a)
+ {
+ if (sr_classa == 0)
+ {
+ sr_classa = 1;
+ //Create qdisc for Class A traffic
+ sprintf(tc_command, "tc qdisc add dev %s handle %d: parent 1:5 htb", interface, classa_parent);
+ log_client_debug_message(sockfd, "tc command: \"%s\"", tc_command);
+ if (system(tc_command) < 0)
+ {
+ log_client_error_message(sockfd, "command(\"%s\") failed", tc_command);
+ return -1;
+ }
+ }
+
+ if (input.measurement_interval == 125)
+ {
+ classa_bw_48 = classa_bw_48 + bandwidth;
+ if (classa_48 == 0)
+ {
+ classa_48 = 1;
+ tc_class_command(sockfd, "add", classid_a_48, interface, classa_bw_48, maxburst);
+ }
+ else
+ {
+ tc_class_command(sockfd, "change", classid_a_48, interface, classa_bw_48, maxburst);
+ }
+
+ add_filter(sockfd, interface, classa_parent, filterhandle_classa, classid_a_48, input.stream_da);
+ insert_stream_da(sockfd, input.stream_da, bandwidth, classid_a_48, filterhandle_classa );
+ filterhandle_classa++;
+ }
+ else if (input.measurement_interval == 136)
+ {
+ classa_bw_44 = classa_bw_44 + bandwidth;
+ if (classa_44 == 0)
+ {
+ classa_44 = 1;
+ tc_class_command(sockfd, "add", classid_a_44, interface, classa_bw_44, maxburst);
+ }
+ else
+ {
+ tc_class_command(sockfd, "change", classid_a_44, interface, classa_bw_44, maxburst);
+ }
+
+ add_filter(sockfd, interface, classa_parent, filterhandle_classa, classid_a_44, input.stream_da);
+ insert_stream_da(sockfd, input.stream_da, bandwidth, classid_a_44, filterhandle_classa);
+ filterhandle_classa++;
+ }
+ else
+ {
+ log_client_error_message(sockfd, "Measurement Interval (%d) doesn't match that of Class A (125 or 136) traffic. "
+ "Enter a valid measurement interval",
+ input.measurement_interval);
+ return -1;
+ }
+ }
+ else
+ {
+ if (sr_classb == 0)
+ {
+ sr_classb = 1;
+ //Create qdisc for Class B traffic
+ sprintf(tc_command, "tc qdisc add dev %s handle %d: parent 1:6 htb", interface, classb_parent);
+ log_client_debug_message(sockfd, "tc command: \"%s\"", tc_command);
+ if (system(tc_command) < 0)
+ {
+ log_client_error_message(sockfd, "command(\"%s\") failed", tc_command);
+ return -1;
+ }
+ }
+
+ if (input.measurement_interval == 250)
+ {
+ classb_bw_48 = classb_bw_48 + bandwidth;
+ if (classb_48 == 0)
+ {
+ classb_48 = 1;
+ tc_class_command(sockfd, "add", classid_b_48, interface, classb_bw_48, maxburst);
+ }
+ else
+ {
+ tc_class_command(sockfd, "change", classid_b_48, interface, classb_bw_48, maxburst);
+ }
+ add_filter(sockfd, interface, classb_parent, filterhandle_classb, classid_b_48, input.stream_da);
+ insert_stream_da(sockfd, input.stream_da, bandwidth, classid_b_48, filterhandle_classb);
+ filterhandle_classb++;
+ }
+ else if (input.measurement_interval == 272)
+ {
+ classb_bw_44 = classb_bw_44 + bandwidth;
+ if (classb_44 == 0)
+ {
+ classb_44 = 1;
+ tc_class_command(sockfd, "add", classid_b_44, interface, classb_bw_44, maxburst);
+ }
+ else
+ {
+ tc_class_command(sockfd, "change", classid_b_44, interface, classb_bw_44, maxburst);
+ }
+ add_filter(sockfd, interface, classb_parent, filterhandle_classb, classid_b_44, input.stream_da);
+ insert_stream_da(sockfd, input.stream_da, bandwidth, classid_b_44, filterhandle_classb);
+ filterhandle_classb++;
+ }
+ else
+ {
+ log_client_error_message(sockfd, "Measurement Interval (%d) doesn't match that of Class B (250 or 272) traffic. "
+ "Enter a valid measurement interval",
+ input.measurement_interval);
+ return -1;
+ }
+ }
+ }
+ else if (input.unreserve_bw==1)
+ {
+ stream_da *remove_stream = get_stream_da(sockfd, input.stream_da);
+ if (remove_stream != NULL)
+ {
+ int class_bw = 0;
+ if (!strcmp(remove_stream->class_id, classid_a_48))
+ {
+ classa_bw_48 = classa_bw_48 - remove_stream->bandwidth;
+ class_bw = classa_bw_48;
+ }
+ else if (!strcmp(remove_stream->class_id, classid_a_44))
+ {
+ classa_bw_44 = classa_bw_44 - remove_stream->bandwidth;
+ class_bw = classa_bw_44;
+ }
+ else if (!strcmp(remove_stream->class_id, classid_b_48))
+ {
+ classb_bw_48 = classb_bw_48 - remove_stream->bandwidth;
+ class_bw = classb_bw_48;
+ }
+ else if (!strcmp(remove_stream->class_id, classid_b_44))
+ {
+ classb_bw_44 = classb_bw_44 - remove_stream->bandwidth;
+ class_bw = classb_bw_44;
+ }
+ if (class_bw == 0)
+ {
+ class_bw = 1;
+ }
+ tc_class_command(sockfd, "change", remove_stream->class_id, interface, class_bw, maxburst);
+ char parent[3] = {0};
+ strncpy(parent,remove_stream->class_id,2);
+ sprintf(tc_command, "tc filter del dev %s parent %s handle 800::%d prio 1 protocol all u32",
+ interface, parent, remove_stream->filter_handle);
+ log_client_debug_message(sockfd, "tc command: \"%s\"", tc_command);
+ if (system(tc_command) < 0)
+ {
+ log_client_error_message(sockfd, "command(\"%s\") failed", tc_command);
+ return -1;
+ }
+ remove_stream_da(sockfd, remove_stream->dest_addr);
+ }
+ }
+
+ return 1;
+}
+
+int init_socket()
+{
+ int socketfd = 0;
+ struct sockaddr_in serv_addr;
+ int yes=1;
+ if ((socketfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
+ {
+ SHAPER_LOGF_ERROR("Could not open socket %d. Error %d (%s)", socketfd, errno, strerror(errno));
+ return -1;
+ }
+ if (fcntl(socketfd, F_SETFL, O_NONBLOCK) < 0)
+ {
+ SHAPER_LOGF_ERROR("Could not set the socket to non-blocking. Error %d (%s)", errno, strerror(errno));
+ close(socketfd);
+ return -1;
+ }
+
+
+ memset(&serv_addr, '0', sizeof(serv_addr));
+
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ serv_addr.sin_port = htons(SHAPER_PORT);
+ setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
+
+ if (bind(socketfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr))<0)
+ {
+ SHAPER_LOGF_ERROR("bind() error %d (%s)", errno, strerror(errno));
+ return -1;
+ }
+ if (listen(socketfd, 10)<0)
+ {
+ SHAPER_LOGF_ERROR("listen() error %d (%s)", errno, strerror(errno));
+ return -1;
+ }
+
+ return socketfd;
+
+}
+
+int main (int argc, char *argv[])
+{
+ char command[100];
+ int socketfd = 0,newfd = 0;
+ int clientfd[MAX_CLIENT_CONNECTIONS];
+ int i, nextclientindex;
+ fd_set read_fds;
+ int fdmax;
+ int recvbytes;
+
+ shaperLogInit();
+
+ while((c = getopt(argc,argv,"d"))>=0)
+ {
+ switch(c)
+ {
+ case 'd':
+ daemonize = 1;
+ break;
+ }
+ }
+
+ if (daemonize == 1 && daemon(1,0) < 0)
+ {
+ SHAPER_LOGF_ERROR("Error %d (%s) starting the daemon", errno, strerror(errno));
+ shaperLogExit();
+ return 1;
+ }
+
+ if ((socketfd = init_socket())<0)
+ {
+ shaperLogExit();
+ return 1;
+ }
+
+ // Setup signal handler
+ // We catch SIGINT and shutdown cleanly
+ int err;
+ struct sigaction sa;
+ sa.sa_handler = signal_handler;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ err = sigaction(SIGINT, &sa, NULL);
+ if (err)
+ {
+ SHAPER_LOG_ERROR("Failed to setup SIGINT handler");
+ shaperLogExit();
+ return 1;
+ }
+ err = sigaction(SIGTERM, &sa, NULL);
+ if (err)
+ {
+ SHAPER_LOG_ERROR("Failed to setup SIGTERM handler");
+ shaperLogExit();
+ return 1;
+ }
+ err = sigaction(SIGUSR1, &sa, NULL);
+ if (err)
+ {
+ SHAPER_LOG_ERROR("Failed to setup SIGUSR1 handler");
+ shaperLogExit();
+ return 1;
+ }
+
+ // Ignore SIGPIPE signals.
+ signal(SIGPIPE, SIG_IGN);
+
+ for (i = 0; i < MAX_CLIENT_CONNECTIONS; ++i)
+ {
+ clientfd[i] = -1;
+ }
+ nextclientindex = 0;
+
+ fputs(USER_COMMAND_PROMPT, stdout);
+ fflush(stdout);
+
+ while (!exit_received)
+ {
+ FD_ZERO(&read_fds);
+ if (!daemonize)
+ {
+ FD_SET(STDIN_FILENO, &read_fds);
+ }
+ FD_SET(socketfd, &read_fds);
+ fdmax = socketfd;
+ for (i = 0; i < MAX_CLIENT_CONNECTIONS; ++i)
+ {
+ if (clientfd[i] > 0)
+ {
+ FD_SET(clientfd[i], &read_fds);
+ if (clientfd[i] > fdmax)
+ {
+ fdmax = clientfd[i];
+ }
+ }
+ }
+ int n = select(fdmax+1, &read_fds, NULL, NULL, NULL);
+ if(n == -1)
+ {
+ if (exit_received)
+ {
+ // Assume the app received a signal to quit.
+ // Process the quit command.
+ process_command(-1, "-q");
+ }
+ else
+ {
+ SHAPER_LOGF_ERROR("select() error %d (%s)", errno, strerror(errno));
+ break;
+ }
+ }
+ else
+ {
+ /* Handle any commands received via stdin. */
+ if (FD_ISSET(STDIN_FILENO, &read_fds))
+ {
+ recvbytes = read(STDIN_FILENO, command, sizeof(command) - 1);
+ if (recvbytes <= 0)
+ {
+ SHAPER_LOGF_ERROR("Error %d reading from stdin (%s)", errno, strerror(errno));
+ }
+ else
+ {
+ command[recvbytes] = '\0';
+
+ /* Process the command data. */
+ int ret = process_command(-1, command);
+ if (!ret)
+ {
+ /* Received a command to exit. */
+ exit_received = 1;
+ }
+ else
+ {
+ /* Prompt the user again. */
+ shaperLogDisplayAll();
+ fputs(USER_COMMAND_PROMPT, stdout);
+ fflush(stdout);
+ }
+ }
+ }
+
+ if (FD_ISSET(socketfd, &read_fds))
+ {
+ newfd = accept(socketfd, (struct sockaddr*)NULL, NULL);
+ if (clientfd[nextclientindex] != -1)
+ {
+ /* Find the next available index. */
+ for (i = (nextclientindex + 1) % MAX_CLIENT_CONNECTIONS; i != nextclientindex; i = (i + 1) % MAX_CLIENT_CONNECTIONS)
+ {
+ if (clientfd[nextclientindex] == -1)
+ {
+ /* Found an empty array slot. */
+ break;
+ }
+ }
+ if (i == nextclientindex)
+ {
+ /* No more client slots available. Connection rejected. */
+ SHAPER_LOG_WARNING("Out of client connection slots. Connection rejected.");
+ close(newfd);
+ newfd = -1;
+ }
+ }
+
+
+ if (newfd != -1)
+ {
+ clientfd[nextclientindex] = newfd;
+ nextclientindex = (nextclientindex + 1) % MAX_CLIENT_CONNECTIONS; /* Next slot used for the next try. */
+
+ /* Send a prompt to the user. */
+ send(newfd, USER_COMMAND_PROMPT, strlen(USER_COMMAND_PROMPT), 0);
+ }
+ }
+
+ for (i = 0; i < MAX_CLIENT_CONNECTIONS; ++i)
+ {
+ if (clientfd[i] != -1 && FD_ISSET(clientfd[i], &read_fds))
+ {
+ recvbytes = recv(clientfd[i], command, sizeof(command) - 1, 0);
+ if (recvbytes < 0)
+ {
+ SHAPER_LOGF_ERROR("Error %d reading from socket %d (%s). Connection closed.", errno, clientfd[i], strerror(errno));
+ close(clientfd[i]);
+ clientfd[i] = -1;
+ nextclientindex = i; /* We know this slot will be empty. */
+ continue;
+ }
+ if (recvbytes == 0)
+ {
+ SHAPER_LOGF_INFO("Socket %d closed", clientfd[i]);
+ close(clientfd[i]);
+ clientfd[i] = -1;
+ nextclientindex = i; /* We know this slot will be empty. */
+ continue;
+ }
+
+ command[recvbytes] = '\0';
+ while (recvbytes > 0 && isspace(command[recvbytes - 1]))
+ {
+ /* Remove trailing whitespace. */
+ command[--recvbytes] = '\0';
+ }
+ SHAPER_LOGF_INFO("The received command is \"%s\"",command);
+ int ret = process_command(clientfd[i], command);
+ if (!ret)
+ {
+ /* Received a command to exit. */
+ exit_received = 1;
+ }
+ else
+ {
+ /* Send another prompt to the user. */
+ send(clientfd[i], USER_COMMAND_PROMPT, strlen(USER_COMMAND_PROMPT), 0);
+ }
+ }
+ }
+ }
+ }//main while loop
+
+ close(socketfd);
+
+ /* Close any connected sockets. */
+ for (i = 0; i < MAX_CLIENT_CONNECTIONS; ++i) {
+ if (clientfd[i] != -1) {
+ SHAPER_LOGF_INFO("Socket %d closed", clientfd[i]);
+ close(clientfd[i]);
+ clientfd[i] = -1;
+ }
+ }
+
+ shaperLogExit();
+
+ return 0;
+}
diff --git a/daemons/shaper/src/shaper_helper_linux.h b/daemons/shaper/src/shaper_helper_linux.h
new file mode 100644
index 00000000..14ee7dbf
--- /dev/null
+++ b/daemons/shaper/src/shaper_helper_linux.h
@@ -0,0 +1,182 @@
+/*************************************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************************************/
+
+#ifndef SHAPER_HELPER_LINUX_H
+#define SHAPER_HELPER_LINUX_H
+
+#include <unistd.h>
+#include <pthread.h>
+#include <signal.h>
+#include <time.h>
+#include <semaphore.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <net/if.h>
+#include <dlfcn.h>
+
+// Uncomment to use manual data alignment adjustments. Not needed for Linux
+//#define DATA_ALIGNMENT_ADJUSTMENT 1
+
+/// Number of nanoseconds in second
+#define NANOSECONDS_PER_SECOND (1000000000ULL)
+/// Number of nanoseconds in millisecond
+#define NANOSECONDS_PER_MSEC (1000000L)
+/// Number of nanoseconds in microsecond
+#define NANOSECONDS_PER_USEC (1000L)
+/// Number of microseconds in second
+#define MICROSECONDS_PER_SECOND (1000000L)
+/// Number of microseconds in millisecond
+#define MICROSECONDS_PER_MSEC (1000L)
+
+#define SLEEP(sec) sleep(sec)
+#define SLEEP_MSEC(mSec) usleep(mSec * 1000)
+#define SLEEP_NSEC(nSec) usleep(nSec / 1000)
+#define SLEEP_UNTIL_NSEC(nSec) xSleepUntilNSec(nSec)
+inline static void xSleepUntilNSec(uint64_t nSec)
+{
+ struct timespec tmpTime;
+ tmpTime.tv_sec = nSec / NANOSECONDS_PER_SECOND;
+ tmpTime.tv_nsec = nSec % NANOSECONDS_PER_SECOND;
+ clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &tmpTime, NULL);
+}
+
+#define RAND() random()
+#define SRAND(seed) srandom(seed)
+
+#define PRAGMA_ALIGN_8
+
+#define SIGNAL_CALLBACK_SETUP(__NAM, __CB) \
+ struct sigaction __NAM; \
+ __NAM.sa_handler = __CB
+
+#define SIGNAL_SIGNAL_SETUP(__SIG, __NAM, __CB, __ERR) \
+ sigemptyset(&__NAM.sa_mask); \
+ __NAM.sa_flags = 0; \
+ __ERR = sigaction(__SIG, &__NAM, NULL)
+
+
+// the following macros define thread related items
+#define THREAD_TYPE(thread) \
+typedef struct \
+{ \
+ pthread_t pthread; \
+ int err; \
+} thread##_type;
+
+#define THREAD_DEFINITON(thread) \
+thread##_type thread##_ThreadData
+
+#define THREAD_CREATE(threadName, threadhandle, thread_attr_name, thread_function, thread_function_arg) \
+ { \
+ pthread_attr_t thread_attr; \
+ do { \
+ threadhandle##_ThreadData.err = pthread_attr_init(&thread_attr); \
+ if (threadhandle##_ThreadData.err) break; \
+ threadhandle##_ThreadData.err = pthread_attr_setstacksize(&thread_attr, threadName##_THREAD_STK_SIZE); \
+ if (threadhandle##_ThreadData.err) break; \
+ threadhandle##_ThreadData.err = pthread_create( \
+ (pthread_t*)&threadhandle##_ThreadData.pthread, \
+ &thread_attr, \
+ thread_function, \
+ (void*)thread_function_arg); \
+ } while (0); \
+ pthread_attr_destroy(&thread_attr); \
+ }
+
+#define THREAD_SET_RT_PRIORITY(threadhandle, priority) \
+ { \
+ struct sched_param param; \
+ param.__sched_priority = priority; \
+ pthread_setschedparam(threadhandle##_ThreadData.pthread, SCHED_RR, &param); \
+ }
+
+#define THREAD_PIN(threadhandle, affinity) \
+ { \
+ cpu_set_t cpuset; \
+ int i1; \
+ CPU_ZERO(&cpuset); \
+ for (i1 = 0; i1 < 32; i1++) { \
+ if (affinity & (1 << i1)) CPU_SET(i1, &cpuset); \
+ } \
+ pthread_setaffinity_np(threadhandle##_ThreadData.pthread, sizeof(cpu_set_t), &cpuset); \
+ }
+
+#define THREAD_CHECK_ERROR(threadhandle, message, error) \
+ do { \
+ error=FALSE; \
+ if (threadhandle##_ThreadData.err != 0) \
+ { \
+ SHAPER_LOGF_ERROR("Thread error: %s code: %d", message, threadhandle##_ThreadData.err); \
+ error=TRUE; \
+ break; \
+ } \
+ } while (0)
+
+#define THREAD_STARTTHREAD(err)
+#define THREAD_KILL(threadhandle, signal) pthread_kill(threadhandle##_ThreadData.pthread, signal)
+#define THREAD_JOINABLE(threadhandle)
+#define THREAD_JOIN(threadhandle, signal) pthread_join(threadhandle##_ThreadData.pthread, (void**)signal)
+#define THREAD_SLEEP(threadhandle, secs) sleep(secs)
+
+#define THREAD_SELF() pthread_self()
+#define GET_PID() getpid()
+
+#define SEM_T(sem) sem_t sem;
+#define SEM_ERR_T(err) int err;
+#define SEM_INIT(sem, init, err) err = sem_init(&sem, 0, init);
+#define SEM_WAIT(sem, err) err = sem_wait(&sem);
+#define SEM_POST(sem, err) err = sem_post(&sem);
+#define SEM_DESTROY(sem, err) err = sem_destroy(&sem);
+#define SEM_IS_ERR_NONE(err) (0 == err)
+#define SEM_IS_ERR_TIMEOUT(err) (ETIMEDOUT == err || -1 == err)
+#define SEM_LOG_ERR(err) if (0 != err) SHAPER_LOGF_ERROR("Semaphore error code: %d", err);
+
+#define MUTEX_ATTR_TYPE_DEFAULT PTHREAD_MUTEX_DEFAULT
+#define MUTEX_ATTR_TYPE_RECURSIVE PTHREAD_MUTEX_RECURSIVE
+#define MUTEX_HANDLE(mutex_handle) pthread_mutex_t mutex_handle
+#define MUTEX_ATTR_HANDLE(mutex_attr_name) pthread_mutexattr_t mutex_attr_name
+#define MUTEX_ATTR_CREATE_ERR() static mutex_err
+#define MUTEX_ATTR_INIT(mutex_attr_name) pthread_mutexattr_init(&mutex_attr_name)
+#define MUTEX_ATTR_SET_TYPE(mutex_attr_name,type) pthread_mutexattr_settype(&mutex_attr_name, type)
+#define MUTEX_ATTR_SET_NAME(mutex_attr_name, name)
+#define MUTEX_CREATE_ERR() int mutex_err
+#define MUTEX_CREATE(mutex_handle,mutex_attr_name) mutex_err=pthread_mutex_init(&mutex_handle, &mutex_attr_name)
+#define MUTEX_LOCK(mutex_handle) mutex_err=pthread_mutex_lock(&mutex_handle)
+#define MUTEX_UNLOCK(mutex_handle) mutex_err=pthread_mutex_unlock(&mutex_handle)
+#define MUTEX_DESTROY(mutex_handle) mutex_err=pthread_mutex_destroy(&mutex_handle)
+#define MUTEX_LOG_ERR(message) if (mutex_err) SHAPER_LOG_ERROR(message);
+#define MUTEX_IS_ERR (mutex_err != 0)
+
+// Alternate simplified mutex mapping
+#define MUTEX_HANDLE_ALT(mutex_handle) pthread_mutex_t mutex_handle
+#define MUTEX_CREATE_ALT(mutex_handle) pthread_mutex_init(&mutex_handle, NULL)
+#define MUTEX_LOCK_ALT(mutex_handle) pthread_mutex_lock(&mutex_handle)
+#define MUTEX_UNLOCK_ALT(mutex_handle) pthread_mutex_unlock(&mutex_handle)
+#define MUTEX_DESTROY_ALT(mutex_handle) pthread_mutex_destroy(&mutex_handle)
+
+#endif // SHAPER_HELPER_LINUX_H
diff --git a/daemons/shaper/src/shaper_log.h b/daemons/shaper/src/shaper_log.h
new file mode 100644
index 00000000..0db3dc36
--- /dev/null
+++ b/daemons/shaper/src/shaper_log.h
@@ -0,0 +1,267 @@
+/*************************************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************************************/
+
+/*
+* MODULE SUMMARY : A simple logging facility for use during
+* development.
+*/
+
+#ifndef SHAPER_LOG_H
+#define SHAPER_LOG_H 1
+
+// ********
+// Merge Issue
+// TODO: Restructure to remove #ifdef code.
+// ********
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+// Uncomment SHAPER_LOG_ON to enable logging.
+#define SHAPER_LOG_ON 1
+
+// Uncomment SHAPER_LOG_ON_OVERRIDE to override all SHAPER_LOG_ON usage in the app to ensure all logs are off.
+//#define SHAPER_LOG_ON_OVERRIDE 1
+
+#ifdef SHAPER_LOG_ON_OVERRIDE
+#ifdef SHAPER_LOG_ON
+#undef SHAPER_LOG_ON
+#endif
+#endif
+
+#define SHAPER_LOG_LEVEL_NONE 0
+#define SHAPER_LOG_LEVEL_ERROR 1
+#define SHAPER_LOG_LEVEL_WARNING 2
+#define SHAPER_LOG_LEVEL_INFO 3
+#define SHAPER_LOG_LEVEL_STATUS 4
+#define SHAPER_LOG_LEVEL_DEBUG 5
+#define SHAPER_LOG_LEVEL_VERBOSE 6
+
+// Special case development logging levels for use with SHAPER_LOGF_DEV and SHAPER_LOG_DEV
+#define SHAPER_LOG_LEVEL_DEV_ON SHAPER_LOG_LEVEL_NONE
+#define SHAPER_LOG_LEVEL_DEV_OFF SHAPER_LOG_LEVEL_VERBOSE + 1
+
+// Default log level, can override in source files
+#ifndef SHAPER_LOG_LEVEL
+//#define SHAPER_LOG_LEVEL SHAPER_LOG_LEVEL_ERROR
+//#define SHAPER_LOG_LEVEL SHAPER_LOG_LEVEL_INFO
+#define SHAPER_LOG_LEVEL SHAPER_LOG_LEVEL_STATUS
+//#define SHAPER_LOG_LEVEL SHAPER_LOG_LEVEL_DEBUG
+//#define SHAPER_LOG_LEVEL SHAPER_LOG_LEVEL_VERBOSE
+#endif
+
+#ifndef SHAPER_LOG_COMPANY
+#define SHAPER_LOG_COMPANY "SHAPER"
+#endif
+
+#ifndef SHAPER_LOG_COMPONENT
+#define SHAPER_LOG_COMPONENT "SHAPER"
+#endif
+
+// Log format options and sizes. Uncomment to include the formatted info.
+#define LOG_MSG_LEN 1024
+
+// The length of the full message
+#define LOG_FULL_MSG_LEN 1024
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+static const int SHAPER_LOG_TIME_INFO = FALSE;
+#define LOG_TIME_LEN 9
+//#define LOG_TIME_LEN 1
+
+static const int SHAPER_LOG_TIMESTAMP_INFO = TRUE;
+#define LOG_TIMESTAMP_LEN 32
+//#define LOG_TIMESTAMP_LEN 1
+
+static const int SHAPER_LOG_FILE_INFO = FALSE;
+//#define LOG_FILE_LEN 256
+#define LOG_FILE_LEN 1
+
+static const int SHAPER_LOG_PROC_INFO = FALSE;
+//#define LOG_PROC_LEN 64
+#define LOG_PROC_LEN 1
+
+static const int SHAPER_LOG_THREAD_INFO = FALSE;
+//#define LOG_THREAD_LEN 64
+#define LOG_THREAD_LEN 1
+
+#define LOG_RT_MSG_LEN 256
+//#define LOG_RT_MSG_LEN 1
+
+#define SHAPER_LOG_OUTPUT_FD stderr
+//#define SHAPER_LOG_OUTPUT_FD stdout
+
+#define SHAPER_LOG_STDOUT_CONSOLE_WIDTH 80
+
+static const int SHAPER_LOG_EXTRA_NEWLINE = TRUE;
+
+// When SHAPER_LOG_FROM_THREAD the message output will be output from a separate thread/task
+// Primary intended use is for debugging.
+// It is expected that SHAPER_LOG_PULL_MODE will not be used at the same time as this option.
+static const int SHAPER_LOG_FROM_THREAD = TRUE;
+
+// When SHAPER_LOG_PULL_MODE the messages will be queued and can be pulled using the
+// shaperLogGetMsg() call. This could be from an logger interface module or host application.
+// It is expected that SHAPER_LOG_FROM_THREAD will not be used at the same time as this option.
+static const int SHAPER_LOG_PULL_MODE = FALSE;
+
+// When using the SHAPER_LOG_FROM_THREAD option. These defines control the behavior of the msg queue
+#define LOG_QUEUE_MSG_LEN 256
+#define LOG_QUEUE_MSG_SIZE (LOG_QUEUE_MSG_LEN + 1)
+#define LOG_QUEUE_MSG_CNT 82
+#define LOG_QUEUE_SLEEP_MSEC 100
+
+// RT (RealTime logging) related defines
+#define LOG_RT_QUEUE_CNT 128
+#define LOG_RT_BEGIN TRUE
+#define LOG_RT_ITEM TRUE
+#define LOG_RT_END TRUE
+typedef enum {
+ LOG_RT_DATATYPE_NONE,
+ LOG_RT_DATATYPE_CONST_STR,
+ LOG_RT_DATATYPE_NOW_TS,
+ LOG_RT_DATATYPE_U16,
+ LOG_RT_DATATYPE_S16,
+ LOG_RT_DATATYPE_U32,
+ LOG_RT_DATATYPE_S32,
+ LOG_RT_DATATYPE_U64,
+ LOG_RT_DATATYPE_S64,
+ LOG_RT_DATATYPE_FLOAT
+} log_rt_datatype_t;
+
+
+#define LOG_VARX(x, y) x ## y
+#define LOG_VAR(x, y) LOG_VARX(x, y)
+
+// Log a message once. Technically once every 4.2 billion attempts. Usage: IF_LOG_ONCE() SHAPER_LOG_INFO(...)
+#define IF_LOG_ONCE() static uint32_t LOG_VAR(logOnce,__LINE__) = 0; if (!LOG_VAR(logOnce,__LINE__)++)
+
+// Log a message at an interval. Usage: IF_LOG_INTERVAL(100) SHAPER_LOG_INFO(...)
+#define IF_LOG_INTERVAL(x) static uint32_t LOG_VAR(logOnce,__LINE__) = 0; if (!(LOG_VAR(logOnce,__LINE__)++ % (x)))
+
+
+#define ETH_FORMAT "%02x:%02x:%02x:%02x:%02x:%02x"
+#define ETH_OCTETS(a) (a)[0],(a)[1],(a)[2],(a)[3],(a)[4],(a)[5]
+
+
+void shaperLogInit(void);
+
+void shaperLogDisplayAll(void);
+
+void shaperLogExit(void);
+
+void shaperLogFn(
+ int level,
+ const char *tag,
+ const char *company,
+ const char *component,
+ const char *path,
+ int line,
+ const char *fmt,
+ ...);
+
+void shaperLogRT(int level, int bBegin, int bItem, int bEnd, char *pFormat, log_rt_datatype_t dataType, void *pVar);
+
+void shaperLogBuffer(
+ int level,
+ const uint8_t *pData,
+ int dataLen,
+ int lineLen,
+ const char *company,
+ const char *component,
+ const char *path,
+ int line);
+
+
+#define shaperLogFn2(level, tag, company, component, path, line, fmt, ...) \
+ {\
+ if (level <= SHAPER_LOG_LEVEL) \
+ shaperLogFn(0, tag, company, component, path, line, fmt, __VA_ARGS__); \
+ }
+
+#define shaperLogBuffer2(level, pData, dataLen, lineLen, company, component, path, line) \
+ {\
+ if (level <= AVB_LOG_LEVEL) \
+ shaperLogBuffer(0, pData, dataLen, lineLen, company, component, path, line); \
+ }
+
+#ifdef SHAPER_LOG_ON
+#define SHAPER_LOGF_DEV(LEVEL, FMT, ...) shaperLogFn2(LEVEL, "DEV", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
+#define SHAPER_LOGF_ERROR(FMT, ...) shaperLogFn2(SHAPER_LOG_LEVEL_ERROR, "ERROR", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
+#define SHAPER_LOGF_WARNING(FMT, ...) shaperLogFn2(SHAPER_LOG_LEVEL_WARNING, "WARNING", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
+#define SHAPER_LOGF_INFO(FMT, ...) shaperLogFn2(SHAPER_LOG_LEVEL_INFO, "INFO", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
+#define SHAPER_LOGF_STATUS(FMT, ...) shaperLogFn2(SHAPER_LOG_LEVEL_STATUS, "STATUS", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
+#define SHAPER_LOGF_DEBUG(FMT, ...) shaperLogFn2(SHAPER_LOG_LEVEL_DEBUG, "DEBUG", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
+#define SHAPER_LOGF_VERBOSE(FMT, ...) shaperLogFn2(SHAPER_LOG_LEVEL_VERBOSE, "VERBOSE", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
+#define SHAPER_LOG_DEV(LEVEL, MSG) shaperLogFn2(LEVEL, "DEV", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
+#define SHAPER_LOG_ERROR(MSG) shaperLogFn2(SHAPER_LOG_LEVEL_ERROR, "ERROR", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
+#define SHAPER_LOG_WARNING(MSG) shaperLogFn2(SHAPER_LOG_LEVEL_WARNING, "WARNING", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
+#define SHAPER_LOG_INFO(MSG) shaperLogFn2(SHAPER_LOG_LEVEL_INFO, "INFO", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
+#define SHAPER_LOG_STATUS(MSG) shaperLogFn2(SHAPER_LOG_LEVEL_STATUS, "STATUS", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
+#define SHAPER_LOG_DEBUG(MSG) shaperLogFn2(SHAPER_LOG_LEVEL_DEBUG, "DEBUG", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
+#define SHAPER_LOG_VERBOSE(MSG) shaperLogFn2(SHAPER_LOG_LEVEL_VERBOSE, "VERBOSE", SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
+#define SHAPER_LOGRT_ERROR(BEGIN, ITEM, END, FMT, TYPE, VAL) shaperLogRT(SHAPER_LOG_LEVEL_ERROR, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define SHAPER_LOGRT_WARNING(BEGIN, ITEM, END, FMT, TYPE, VAL) shaperLogRT(SHAPER_LOG_LEVEL_WARNING, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define SHAPER_LOGRT_INFO(BEGIN, ITEM, END, FMT, TYPE, VAL) shaperLogRT(SHAPER_LOG_LEVEL_INFO, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define SHAPER_LOGRT_STATUS(BEGIN, ITEM, END, FMT, TYPE, VAL) shaperLogRT(SHAPER_LOG_LEVEL_STATUS, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define SHAPER_LOGRT_DEBUG(BEGIN, ITEM, END, FMT, TYPE, VAL) shaperLogRT(SHAPER_LOG_LEVEL_DEBUG, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define SHAPER_LOGRT_VERBOSE(BEGIN, ITEM, END, FMT, TYPE, VAL) shaperLogRT(SHAPER_LOG_LEVEL_VERBOSE, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define SHAPER_LOG_BUFFER(LEVEL, DATA, DATALEN, LINELINE) shaperLogBuffer2(LEVEL, DATA, DATALEN, LINELINE, SHAPER_LOG_COMPANY, SHAPER_LOG_COMPONENT, __FILE__, __LINE__)
+#else
+#define SHAPER_LOGF_DEV(LEVEL, FMT, ...)
+#define SHAPER_LOGF_ERROR(FMT, ...)
+#define SHAPER_LOGF_WARNING(FMT, ...)
+#define SHAPER_LOGF_INFO(FMT, ...)
+#define SHAPER_LOGF_STATUS(FMT, ...)
+#define SHAPER_LOGF_DEBUG(FMT, ...)
+#define SHAPER_LOGF_VERBOSE(FMT, ...)
+#define SHAPER_LOG_DEV(LEVEL, FMT, ...)
+#define SHAPER_LOG_ERROR(MSG)
+#define SHAPER_LOG_WARNING(MSG)
+#define SHAPER_LOG_INFO(MSG)
+#define SHAPER_LOG_STATUS(MSG)
+#define SHAPER_LOG_DEBUG(MSG)
+#define SHAPER_LOG_VERBOSE(MSG)
+#define SHAPER_LOGRT_ERROR(BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define SHAPER_LOGRT_WARNING(BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define SHAPER_LOGRT_INFO(BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define SHAPER_LOGRT_STATUS(BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define SHAPER_LOGRT_DEBUG(BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define SHAPER_LOGRT_VERBOSE(BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define SHAPER_LOG_BUFFER(LEVEL, DATA, DATALEN, LINELINE)
+#endif // SHAPER_LOG_ON
+
+// Get a queued log message. Intended to be used with the SHAPER_LOG_PULL_MODE option.
+// Message will not be null terminated.
+uint32_t shaperLogGetMsg(uint8_t *pBuf, uint32_t bufSize);
+
+#endif // SHAPER_LOG_H
diff --git a/daemons/shaper/src/shaper_log_linux.c b/daemons/shaper/src/shaper_log_linux.c
new file mode 100644
index 00000000..d68a79a2
--- /dev/null
+++ b/daemons/shaper/src/shaper_log_linux.c
@@ -0,0 +1,445 @@
+/*************************************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************************************/
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "platform.h"
+#include "shaper_log_queue.h"
+#include "shaper_helper_linux.h"
+
+#define SHAPER_LOG_COMPONENT "Log"
+#include "shaper_log.h"
+
+typedef struct {
+ uint8_t msg[LOG_QUEUE_MSG_SIZE];
+ int bRT; // TRUE = Details are in RT queue
+} log_queue_item_t;
+
+typedef struct {
+ char *pFormat;
+ log_rt_datatype_t dataType;
+ union {
+ struct timespec nowTS;
+ uint16_t unsignedShortVar;
+ int16_t signedShortVar;
+ uint32_t unsignedLongVar;
+ int32_t signedLongVar;
+ uint64_t unsignedLongLongVar;
+ int64_t signedLongLongVar;
+ float floatVar;
+ } data;
+ int bEnd;
+} log_rt_queue_item_t;
+
+static shaper_log_queue_t logQueue;
+static shaper_log_queue_t logRTQueue;
+
+static char msg[LOG_MSG_LEN] = "";
+static char time_msg[LOG_TIME_LEN] = "";
+static char timestamp_msg[LOG_TIMESTAMP_LEN] = "";
+static char file_msg[LOG_FILE_LEN] = "";
+static char proc_msg[LOG_PROC_LEN] = "";
+static char thread_msg[LOG_THREAD_LEN] = "";
+static char full_msg[LOG_FULL_MSG_LEN] = "";
+
+static char rt_msg[LOG_RT_MSG_LEN] = "";
+
+static int loggingThreadRunning = FALSE;
+extern void *loggingThreadFn(void *pv);
+THREAD_TYPE(loggingThread);
+THREAD_DEFINITON(loggingThread);
+
+#define THREAD_STACK_SIZE 65536
+#define loggingThread_THREAD_STK_SIZE THREAD_STACK_SIZE
+
+static MUTEX_HANDLE_ALT(gLogMutex);
+#define LOG_LOCK() MUTEX_LOCK_ALT(gLogMutex)
+#define LOG_UNLOCK() MUTEX_UNLOCK_ALT(gLogMutex)
+
+void shaperLogRTRender(log_queue_item_t *pLogItem)
+{
+ if (logRTQueue) {
+ pLogItem->msg[0] = 0x00;
+ int bMore = TRUE;
+ while (bMore) {
+ shaper_log_queue_elem_t elem = shaperLogQueueTailLock(logRTQueue);
+ if (elem) {
+ log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)shaperLogQueueData(elem);
+
+ switch (pLogRTItem->dataType) {
+ case LOG_RT_DATATYPE_CONST_STR:
+ strcat((char *)pLogItem->msg, pLogRTItem->pFormat);
+ break;
+ case LOG_RT_DATATYPE_NOW_TS:
+ sprintf(rt_msg, "[%lu:%09lu] ", pLogRTItem->data.nowTS.tv_sec, pLogRTItem->data.nowTS.tv_nsec);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_U16:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.unsignedShortVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_S16:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.signedShortVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_U32:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.unsignedLongVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_S32:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.signedLongVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_U64:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.unsignedLongLongVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_S64:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.signedLongLongVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ case LOG_RT_DATATYPE_FLOAT:
+ sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.floatVar);
+ strcat((char *)pLogItem->msg, rt_msg);
+ break;
+ default:
+ break;
+ }
+
+ if (pLogRTItem->bEnd) {
+ if (SHAPER_LOG_EXTRA_NEWLINE)
+ strcat((char *)pLogItem->msg, "\n");
+ bMore = FALSE;
+ }
+ shaperLogQueueTailPull(logRTQueue);
+ }
+ }
+ }
+}
+
+uint32_t shaperLogGetMsg(uint8_t *pBuf, uint32_t bufSize)
+{
+ uint32_t dataLen = 0;
+ if (logQueue) {
+ shaper_log_queue_elem_t elem = shaperLogQueueTailLock(logQueue);
+ if (elem) {
+ log_queue_item_t *pLogItem = (log_queue_item_t *)shaperLogQueueData(elem);
+
+ if (pLogItem->bRT)
+ shaperLogRTRender(pLogItem);
+
+ dataLen = strlen((const char *)pLogItem->msg);
+ if (dataLen <= bufSize)
+ memcpy(pBuf, (uint8_t *)pLogItem->msg, dataLen);
+ else
+ memcpy(pBuf, (uint8_t *)pLogItem->msg, bufSize);
+ shaperLogQueueTailPull(logQueue);
+ return dataLen;
+ }
+ }
+ return dataLen;
+}
+
+void *loggingThreadFn(void *pv)
+{
+ (void) pv;
+
+ while (loggingThreadRunning) {
+ SLEEP_MSEC(LOG_QUEUE_SLEEP_MSEC);
+ shaperLogDisplayAll();
+ }
+
+ return NULL;
+}
+
+void shaperLogDisplayAll(void)
+{
+ int more = TRUE;
+
+ while (more) {
+ more = FALSE;
+ shaper_log_queue_elem_t elem = shaperLogQueueTailLock(logQueue);
+ if (elem) {
+ log_queue_item_t *pLogItem = (log_queue_item_t *)shaperLogQueueData(elem);
+
+ if (pLogItem->bRT)
+ shaperLogRTRender(pLogItem);
+
+ fputs((const char *)pLogItem->msg, SHAPER_LOG_OUTPUT_FD);
+ shaperLogQueueTailPull(logQueue);
+ more = TRUE;
+ }
+ }
+}
+
+void shaperLogInit(void)
+{
+ MUTEX_CREATE_ALT(gLogMutex);
+
+ logQueue = shaperLogQueueNewQueue(sizeof(log_queue_item_t), LOG_QUEUE_MSG_CNT);
+ if (!logQueue) {
+ printf("Failed to initialize logging facility\n");
+ }
+
+ logRTQueue = shaperLogQueueNewQueue(sizeof(log_rt_queue_item_t), LOG_RT_QUEUE_CNT);
+ if (!logRTQueue) {
+ printf("Failed to initialize logging RT facility\n");
+ }
+
+ // Start the logging task
+ if (SHAPER_LOG_FROM_THREAD) {
+ int errResult;
+ loggingThreadRunning = TRUE;
+ THREAD_CREATE(loggingThread, loggingThread, NULL, loggingThreadFn, NULL);
+ THREAD_CHECK_ERROR(loggingThread, "Thread / task creation failed", errResult);
+ if (errResult) {} // Already reported
+ }
+}
+
+void shaperLogExit()
+{
+ if (SHAPER_LOG_FROM_THREAD) {
+ loggingThreadRunning = FALSE;
+ THREAD_JOIN(loggingThread, NULL);
+ }
+}
+
+void shaperLogFn(
+ int level,
+ const char *tag,
+ const char *company,
+ const char *component,
+ const char *path,
+ int line,
+ const char *fmt,
+ ...)
+{
+ if (level <= SHAPER_LOG_LEVEL) {
+ va_list args;
+ va_start(args, fmt);
+
+ LOG_LOCK();
+
+ vsprintf(msg, fmt, args);
+
+ if (SHAPER_LOG_FILE_INFO && path) {
+ char* file = strrchr(path, '/');
+ if (!file)
+ file = strrchr(path, '\\');
+ if (file)
+ file += 1;
+ else
+ file = (char*)path;
+ sprintf(file_msg, " %s:%d", file, line);
+ }
+ if (SHAPER_LOG_PROC_INFO) {
+ sprintf(proc_msg, " P:%5.5d", GET_PID());
+ }
+ if (SHAPER_LOG_THREAD_INFO) {
+ sprintf(thread_msg, " T:%lu", THREAD_SELF());
+ }
+ if (SHAPER_LOG_TIME_INFO) {
+ time_t tNow = time(NULL);
+ struct tm tmNow;
+ localtime_r(&tNow, &tmNow);
+
+ sprintf(time_msg, "%2.2d:%2.2d:%2.2d", tmNow.tm_hour, tmNow.tm_min, tmNow.tm_sec);
+ }
+ if (SHAPER_LOG_TIMESTAMP_INFO) {
+ struct timespec nowTS;
+ clock_gettime(CLOCK_REALTIME, &nowTS);
+
+ sprintf(timestamp_msg, "%lu:%09lu", nowTS.tv_sec, nowTS.tv_nsec);
+ }
+
+ // using sprintf and puts allows using static buffers rather than heap.
+ if (SHAPER_LOG_EXTRA_NEWLINE)
+ /* int32_t full_msg_len = */ sprintf(full_msg, "[%s%s%s%s %s %s%s] %s: %s\n", time_msg, timestamp_msg, proc_msg, thread_msg, company, component, file_msg, tag, msg);
+ else
+ /* int32_t full_msg_len = */ sprintf(full_msg, "[%s%s%s%s %s %s%s] %s: %s", time_msg, timestamp_msg, proc_msg, thread_msg, company, component, file_msg, tag, msg);
+
+ if (!SHAPER_LOG_FROM_THREAD && !SHAPER_LOG_PULL_MODE) {
+ fputs(full_msg, SHAPER_LOG_OUTPUT_FD);
+ }
+ else {
+ if (logQueue) {
+ shaper_log_queue_elem_t elem = shaperLogQueueHeadLock(logQueue);
+ if (elem) {
+ log_queue_item_t *pLogItem = (log_queue_item_t *)shaperLogQueueData(elem);
+ pLogItem->bRT = FALSE;
+ strncpy((char *)pLogItem->msg, full_msg, LOG_QUEUE_MSG_LEN);
+ shaperLogQueueHeadPush(logQueue);
+ }
+ }
+ }
+
+ va_end(args);
+
+ LOG_UNLOCK();
+ }
+}
+
+void shaperLogRT(int level, int bBegin, int bItem, int bEnd, char *pFormat, log_rt_datatype_t dataType, void *pVar)
+{
+ if (level <= SHAPER_LOG_LEVEL) {
+ if (logRTQueue) {
+ if (bBegin) {
+ LOG_LOCK();
+
+ shaper_log_queue_elem_t elem = shaperLogQueueHeadLock(logRTQueue);
+ if (elem) {
+ log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)shaperLogQueueData(elem);
+ pLogRTItem->bEnd = FALSE;
+ pLogRTItem->pFormat = NULL;
+ pLogRTItem->dataType = LOG_RT_DATATYPE_NOW_TS;
+ clock_gettime(CLOCK_REALTIME, &pLogRTItem->data.nowTS);
+ shaperLogQueueHeadPush(logRTQueue);
+ }
+ }
+
+ if (bItem) {
+ shaper_log_queue_elem_t elem = shaperLogQueueHeadLock(logRTQueue);
+ if (elem) {
+ log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)shaperLogQueueData(elem);
+ if (bEnd)
+ pLogRTItem->bEnd = TRUE;
+ else
+ pLogRTItem->bEnd = FALSE;
+ pLogRTItem->pFormat = pFormat;
+ pLogRTItem->dataType = dataType;
+
+ switch (pLogRTItem->dataType) {
+ case LOG_RT_DATATYPE_CONST_STR:
+ break;
+ case LOG_RT_DATATYPE_U16:
+ pLogRTItem->data.unsignedLongVar = *(uint16_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_S16:
+ pLogRTItem->data.signedLongVar = *(int16_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_U32:
+ pLogRTItem->data.unsignedLongVar = *(uint32_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_S32:
+ pLogRTItem->data.signedLongVar = *(int32_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_U64:
+ pLogRTItem->data.unsignedLongLongVar = *(uint64_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_S64:
+ pLogRTItem->data.signedLongLongVar = *(int64_t *)pVar;
+ break;
+ case LOG_RT_DATATYPE_FLOAT:
+ pLogRTItem->data.floatVar = *(float *)pVar;
+ break;
+ default:
+ break;
+ }
+ shaperLogQueueHeadPush(logRTQueue);
+ }
+ }
+
+ if (!bItem && bEnd) {
+ shaper_log_queue_elem_t elem = shaperLogQueueHeadLock(logRTQueue);
+ if (elem) {
+ log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)shaperLogQueueData(elem);
+ pLogRTItem->bEnd = TRUE;
+ pLogRTItem->pFormat = NULL;
+ pLogRTItem->dataType = LOG_RT_DATATYPE_NONE;
+ shaperLogQueueHeadPush(logRTQueue);
+ }
+ }
+
+ if (bEnd) {
+ if (logQueue) {
+ shaper_log_queue_elem_t elem = shaperLogQueueHeadLock(logQueue);
+ if (elem) {
+ log_queue_item_t *pLogItem = (log_queue_item_t *)shaperLogQueueData(elem);
+ pLogItem->bRT = TRUE;
+ if (SHAPER_LOG_FROM_THREAD) {
+ shaperLogQueueHeadPush(logQueue);
+ } else {
+ shaperLogRTRender(pLogItem);
+ fputs((const char *)pLogItem->msg, SHAPER_LOG_OUTPUT_FD);
+ shaperLogQueueHeadUnlock(logQueue);
+ }
+ }
+ }
+
+ LOG_UNLOCK();
+ }
+ }
+ }
+}
+
+void shaperLogBuffer(
+ int level,
+ const uint8_t *pData,
+ int dataLen,
+ int lineLen,
+ const char *company,
+ const char *component,
+ const char *path,
+ int line)
+{
+ char szDataLine[ 400 ];
+ char *pszOut;
+ int i, j;
+
+ if (level > SHAPER_LOG_LEVEL) { return; }
+
+ for (i = 0; i < dataLen; i += lineLen) {
+ /* Create the hexadecimal output for the buffer. */
+ pszOut = szDataLine;
+ *pszOut++ = '\t';
+ for (j = i; j < i + lineLen; ++j) {
+ if (j < dataLen) {
+ sprintf(pszOut, "%02x ", pData[j]);
+ } else {
+ strcpy(pszOut, " ");
+ }
+ pszOut += 3;
+ }
+
+ *pszOut++ = ' ';
+ *pszOut++ = ' ';
+
+ /* Append the ASCII equivalent of each character. */
+ for (j = i; j < dataLen && j < i + lineLen; ++j) {
+ if (pData[j] >= 0x20 && pData[j] < 0x7f) {
+ *pszOut++ = (char) pData[j];
+ } else {
+ *pszOut++ = '.';
+ }
+ }
+
+ /* Display this line of text. */
+ *pszOut = '\0';
+ shaperLogFn(level, "BUFFER", company, component, path, line, "%s", szDataLine);
+ }
+}
diff --git a/daemons/shaper/src/shaper_log_queue.c b/daemons/shaper/src/shaper_log_queue.c
new file mode 100644
index 00000000..52c6eb5e
--- /dev/null
+++ b/daemons/shaper/src/shaper_log_queue.c
@@ -0,0 +1,200 @@
+/*************************************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "shaper_log_queue.h"
+
+#define SHAPER_LOG_COMPONENT "Queue"
+#include "shaper_log.h"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+struct shaper_log_queue_elem {
+ int setFlg;
+ void *data;
+};
+
+struct shaper_log_queue {
+ // Size of each element
+ uint32_t elemSize;
+
+ // Number of queue element slots
+ uint32_t queueSize;
+
+ // Next element to be filled
+ uint32_t head;
+
+ // Next element to be pulled
+ uint32_t tail;
+
+ shaper_log_queue_elem_t elemArray;
+};
+
+shaper_log_queue_t shaperLogQueueNewQueue(uint32_t elemSize, uint32_t queueSize)
+{
+ if (elemSize < 1 || queueSize < 1)
+ return NULL;
+
+ shaper_log_queue_t retQueue = calloc(1, sizeof(struct shaper_log_queue));
+ if (retQueue) {
+ retQueue->elemArray = calloc(queueSize, sizeof(struct shaper_log_queue_elem));
+ if (retQueue->elemArray) {
+ uint32_t i1;
+ for (i1 = 0; i1 < queueSize; i1++) {
+ retQueue->elemArray[i1].data = calloc(1, elemSize);
+ if (!retQueue->elemArray[i1].data) {
+ shaperLogQueueDeleteQueue(retQueue);
+ return NULL;
+ }
+ }
+ }
+ else {
+ shaperLogQueueDeleteQueue(retQueue);
+ return NULL;
+ }
+
+ retQueue->elemSize = elemSize;
+ retQueue->queueSize = queueSize;
+ retQueue->head = 0;
+ retQueue->tail = 0;
+ }
+
+ return retQueue;
+}
+
+void shaperLogQueueDeleteQueue(shaper_log_queue_t queue)
+{
+ if (queue) {
+ uint32_t i1;
+ for (i1 = 0; i1 < queue->queueSize; i1++) {
+ free(queue->elemArray[i1].data);
+ queue->elemArray[i1].data = NULL;
+ }
+ free(queue->elemArray);
+ queue->elemArray = NULL;
+ free(queue);
+ }
+}
+
+uint32_t shaperLogQueueGetQueueSize(shaper_log_queue_t queue)
+{
+ if (queue) {
+ return queue->queueSize;
+ }
+ return 0;
+}
+
+uint32_t shaperLogQueueGetElemCount(shaper_log_queue_t queue)
+{
+ uint32_t cnt = 0;
+ if (queue) {
+ if (queue->head > queue->tail) {
+ cnt += queue->head - queue->tail - 1;
+ }
+ else if (queue->head < queue->tail) {
+ cnt += queue->head + ((queue->queueSize - 1) - queue->tail);
+ }
+
+ if (queue->elemArray[queue->tail].setFlg) {
+ cnt++;
+ }
+ }
+ return cnt;
+}
+
+uint32_t shaperLogQueueGetElemSize(shaper_log_queue_t queue)
+{
+ if (queue) {
+ return queue->elemSize;
+ }
+ return 0;
+}
+
+void *shaperLogQueueData(shaper_log_queue_elem_t elem)
+{
+ if (elem) {
+ return elem->data;
+ }
+ return NULL;
+}
+
+shaper_log_queue_elem_t shaperLogQueueHeadLock(shaper_log_queue_t queue)
+{
+ if (queue) {
+ if (!queue->elemArray[queue->head].setFlg) {
+ return &queue->elemArray[queue->head];
+ }
+ }
+ return NULL;
+}
+
+void shaperLogQueueHeadUnlock(shaper_log_queue_t queue)
+{
+ (void) queue;
+}
+
+void shaperLogQueueHeadPush(shaper_log_queue_t queue)
+{
+ if (queue) {
+ queue->elemArray[queue->head++].setFlg = TRUE;
+ if (queue->head >= queue->queueSize) {
+ queue->head = 0;
+ }
+ }
+}
+
+shaper_log_queue_elem_t shaperLogQueueTailLock(shaper_log_queue_t queue)
+{
+ if (queue) {
+ if (queue->elemArray[queue->tail].setFlg) {
+ return &queue->elemArray[queue->tail];
+ }
+ }
+ return NULL;
+}
+
+void shaperLogQueueTailUnlock(shaper_log_queue_t queue)
+{
+ (void) queue;
+}
+
+void shaperLogQueueTailPull(shaper_log_queue_t queue)
+{
+ if (queue) {
+ queue->elemArray[queue->tail++].setFlg = FALSE;
+ if (queue->tail >= queue->queueSize) {
+ queue->tail = 0;
+ }
+ }
+}
diff --git a/daemons/shaper/src/shaper_log_queue.h b/daemons/shaper/src/shaper_log_queue.h
new file mode 100644
index 00000000..5453fa8c
--- /dev/null
+++ b/daemons/shaper/src/shaper_log_queue.h
@@ -0,0 +1,78 @@
+/*************************************************************************************************************
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*************************************************************************************************************/
+
+/*
+* MODULE SUMMARY : Interface for a basic dynamic array abstraction.
+*
+* - Fixed size queue.
+* - Only head and tail access possible.
+* - Head and Tail locking.
+* - If there is a single task accessing head and a single task accessing tail no synchronization is needed.
+* - If synchronization is needed the Pull and Push functions should be protected before calling.
+*/
+
+#ifndef SHAPER_LOG_QUEUE_H
+#define SHAPER_LOG_QUEUE_H 1
+
+typedef struct shaper_log_queue_elem * shaper_log_queue_elem_t;
+typedef struct shaper_log_queue * shaper_log_queue_t;
+
+// Create an queue. Returns NULL on failure.
+shaper_log_queue_t shaperLogQueueNewQueue(uint32_t elemSize, uint32_t queueSize);
+
+// Delete an array.
+void shaperLogQueueDeleteQueue(shaper_log_queue_t queue);
+
+// Get number of queue slots
+uint32_t shaperLogQueueGetQueueSize(shaper_log_queue_t queue);
+
+// Get number of element
+uint32_t shaperLogQueueGetElemCount(shaper_log_queue_t queue);
+
+// Get element size
+uint32_t shaperLogQueueGetElemSize(shaper_log_queue_t queue);
+
+// Get data of the element. Returns NULL on failure.
+void *shaperLogQueueData(shaper_log_queue_elem_t elem);
+
+// Lock the head element.
+shaper_log_queue_elem_t shaperLogQueueHeadLock(shaper_log_queue_t queue);
+
+// Unlock the head element.
+void shaperLogQueueHeadUnlock(shaper_log_queue_t queue);
+
+// Push the head element making it available for tail access.
+void shaperLogQueueHeadPush(shaper_log_queue_t queue);
+
+// Lock the tail element.
+shaper_log_queue_elem_t shaperLogQueueTailLock(shaper_log_queue_t queue);
+
+// Unlock the tail element.
+void shaperLogQueueTailUnlock(shaper_log_queue_t queue);
+
+// Pull (remove) the tail element
+void shaperLogQueueTailPull(shaper_log_queue_t queue);
+
+#endif // SHAPER_LOG_QUEUE_H
diff --git a/examples/common/Makefile b/examples/common/Makefile
index 5e42ddbd..68a313fd 100644
--- a/examples/common/Makefile
+++ b/examples/common/Makefile
@@ -1,14 +1,16 @@
+DAEMONS_DIR = ../../daemons
+
CC ?= gcc
OPT = -O2 -g
-CFLAGS = $(OPT) -Wall -Wextra -Wno-parentheses
+WARN = -Wall -Wextra -Wno-parentheses
+CFLAGS = $(OPT) $(WARN)
+CPPFLAGS = -I$(DAEMONS_DIR)/mrpd -I$(DAEMONS_DIR)/common
all: talker_mrp_client.o listener_mrp_client.o
talker_mrp_client.o: talker_mrp_client.c talker_mrp_client.h
- $(CC) $(CFLAGS) -I../../daemons/mrpd -I../../daemons/common -c talker_mrp_client.c
listener_mrp_client.o: listener_mrp_client.c listener_mrp_client.h
- $(CC) $(CFLAGS) -I../../daemons/mrpd -I../../daemons/common -c listener_mrp_client.c
clean:
$(RM) talker_mrp_client.o listener_mrp_client.o
diff --git a/examples/gstreamer-avb-plugins/gst-plugin/src/gstavbsink.c b/examples/gstreamer-avb-plugins/gst-plugin/src/gstavbsink.c
index 90a2a03f..f893aebc 100644
--- a/examples/gstreamer-avb-plugins/gst-plugin/src/gstavbsink.c
+++ b/examples/gstreamer-avb-plugins/gst-plugin/src/gstavbsink.c
@@ -270,7 +270,7 @@ void * read_start_feed(void *arg)
if (n > 0) {
sscanf(buf, "%d", &g_start_feeding);
printf("\nTransmitter status: %d", g_start_feeding);
- if (g_start_feed_socket == 2) {
+ if (g_start_feeding == 2) {
listeners = 0;
halt_tx = 1;
/* disable Qav */
diff --git a/examples/jackd-listener/Makefile b/examples/jackd-listener/Makefile
index b0208530..4a526b91 100644
--- a/examples/jackd-listener/Makefile
+++ b/examples/jackd-listener/Makefile
@@ -1,18 +1,24 @@
+MRPCLIENT_DIR = ../common
+MRPLISTENER_OBJS = listener_mrp_client.o
+MRPLISTENER_TARGETS = $(addprefix $(MRPCLIENT_DIR)/,$(MRPLISTENER_OBJS))
+
+DAEMONS_DIR = ../../daemons
+
CC ?= gcc
OPT = -O2 -g
-CFLAGS = $(OPT) -Wall -Wextra -Wno-parentheses -std=gnu99
-INCFLAGS = -I../../daemons/mrpd -I../common -I../../daemons/common
+WARN = -Wall -Wextra -Wno-parentheses
+CFLAGS = $(OPT) $(WARN) -std=gnu99
+CPPFLAGS = -I$(DAEMONS_DIR)/mrpd -I$(MRPCLIENT_DIR) -I$(DAEMONS_DIR)/common
LDLIBS = -lpcap -lsndfile -ljack -lpthread
all: jack_listener
-jack_listener: jack_listener.o ../common/listener_mrp_client.o
+jack_listener: jack_listener.o $(MRPLISTENER_TARGETS)
jack_listener.o: jack_listener.c
- $(CC) $(CFLAGS) $(INCFLAGS) -c jack_listener.c
-../common/listener_mrp_client.o:
- make -C ../common/ listener_mrp_client.o
+$(MRPCLIENT_DIR)/%.o: $(MRPCLIENT_DIR)/%.c $(MRPCLIENT_DIR)/%.h
+ make -C $(MRPCLIENT_DIR) $@
%: %.o
$(CC) $^ $(LDLIBS) -o $@
diff --git a/examples/jackd-talker/Makefile b/examples/jackd-talker/Makefile
index f76bf2e0..9a6187e2 100644
--- a/examples/jackd-talker/Makefile
+++ b/examples/jackd-talker/Makefile
@@ -1,25 +1,37 @@
+AVBLIB_DIR = ../../lib/common
+AVBLIB_OBJS = avb_avtp.o avb_gptp.o avb_igb.o
+AVBLIB_TARGETS = $(addprefix $(AVBLIB_DIR)/,$(AVBLIB_OBJS))
+
+MRPCLIENT_DIR = ../common
+MRPTALKER_OBJS = talker_mrp_client.o
+MRPTALKER_TARGETS = $(addprefix $(MRPCLIENT_DIR)/,$(MRPTALKER_OBJS))
+
+IGBLIB_DIR = ../../lib/igb
+DAEMONS_DIR = ../../daemons
+
CC ?= gcc
OPT = -O2 -g
-CFLAGS = $(OPT) $(INCFLAGS) -Wall -Wextra -Wno-parentheses -std=gnu99
-INCFLAGS = -I../../lib/igb -I../../daemons/mrpd -I../common -I../../lib/common -I../../daemons/common
+WARN = -Wall -Wextra -Wno-parentheses
+CFLAGS = $(OPT) $(WARN) -std=gnu99
+CPPFLAGS = -I$(IGBLIB_DIR) -I$(DAEMONS_DIR)/mrpd -I$(MRPCLIENT_DIR) -I$(AVBLIB_DIR) -I$(DAEMONS_DIR)/common
LDLIBS = -ligb -lpci -lrt -pthread -ljack
-LDFLAGS = -L../../lib/igb
+LDFLAGS = -L$(IGBLIB_DIR)
+
+.PHONY: all clean
all: jackd_talker
-jackd_talker: jackd_talker.o jack.o ../common/talker_mrp_client.o ../../lib/common/avb.o
+jackd_talker: jackd_talker.o jack.o $(MRPTALKER_TARGETS) $(AVBLIB_TARGETS)
jack.o: jack.c jack.h defines.h
- $(CC) $(CFLAGS) -c jack.c
jackd_talker.o: jackd_talker.c defines.h jack.h
- $(CC) -c $(INCFLAGS) -I../../daemons/mrpd $(CFLAGS) jackd_talker.c
-../../lib/common/avb.o: ../../lib/common/avb.c ../../lib/common/avb.h
- make -C ../../lib/common/ avb.o
+$(AVBLIB_DIR)/%.o: $(AVBLIB_DIR)/%.h $(AVBLIB_DIR)/%.c
+ make -C $(AVBLIB_DIR) $@
-../common/talker_mrp_client.o:
- make -C ../common/ talker_mrp_client.o
+$(MRPCLIENT_DIR)/%.o: $(MRPCLIENT_DIR)/%.c $(MRPCLIENT_DIR)/%.h
+ make -C $(MRPCLIENT_DIR) $@
%: %.o
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
diff --git a/examples/live_stream/Makefile b/examples/live_stream/Makefile
index 4eb4feed..b5c96957 100644
--- a/examples/live_stream/Makefile
+++ b/examples/live_stream/Makefile
@@ -1,30 +1,41 @@
+AVBLIB_DIR = ../../lib/common
+AVBLIB_OBJS = avb_avtp.o avb_gptp.o avb_igb.o
+AVBLIB_TARGETS = $(addprefix $(AVBLIB_DIR)/,$(AVBLIB_OBJS))
+
+MRPCLIENT_DIR = ../common
+MRPTALKER_OBJS = talker_mrp_client.o
+MRPTALKER_TARGETS = $(addprefix $(MRPCLIENT_DIR)/,$(MRPTALKER_OBJS))
+MRPLISTENER_OBJS = listener_mrp_client.o
+MRPLISTENER_TARGETS = $(addprefix $(MRPCLIENT_DIR)/,$(MRPLISTENER_OBJS))
+
+IGBLIB_DIR = ../../lib/igb
+DAEMONS_DIR = ../../daemons
+
CC?=gcc
OPT=-O2 -g
-CFLAGS=$(OPT) -Wall -Wextra -Wno-parentheses
-INCFLAGS=-I ../../lib/igb/ -I../../daemons/mrpd -I../common -I../../lib/common -I../../daemons/common
+WARN=-Wall -Wextra -Wno-parentheses
+CFLAGS=$(OPT) $(WARN)
+CPPFLAGS=-I$(IGBLIB_DIR) -I$(DAEMONS_DIR)/mrpd -I$(MRPCLIENT_DIR) -I$(AVBLIB_DIR) -I$(DAEMONS_DIR)/common
LDLIBS=-ligb -lpci -lrt -lpthread
-LDFLAGS=-L ../../lib/igb/
+LDFLAGS=-L$(IGBLIB_DIR)
+
+.PHONY: all clean
all: talker listener
-talker: talker.o ../../lib/common/avb.o ../common/talker_mrp_client.o
+talker: talker.o $(MRPTALKER_TARGETS) $(AVBLIB_TARGETS)
talker.o: talker.c
- $(CC) $(CFLAGS) $(INCFLAGS) $(EXTRA_FLAGS) -c talker.c
-
-../common/talker_mrp_client.o: ../common/talker_mrp_client.c ../common/talker_mrp_client.h
- make -C ../common/ talker_mrp_client.o
-listener: listener.o ../../lib/common/avb.o ../common/listener_mrp_client.o
+listener: listener.o $(MRPLISTENER_TARGETS) $(AVBLIB_TARGETS)
listener.o: listener.c
- $(CC) $(CFLAGS) $(INCFLAGS) $(EXTRA_FLAGS) -c listener.c
-../common/listener_mrp_client.o: ../common/listener_mrp_client.c ../common/listener_mrp_client.h
- make -C ../common/ listener_mrp_client.o
+$(AVBLIB_DIR)/%.o: $(AVBLIB_DIR)/%.h $(AVBLIB_DIR)/%.c
+ make -C $(AVBLIB_DIR) $@
-../../lib/common/avb.o: ../../lib/common/avb.c ../../lib/common/avb.h
- make -C ../../lib/common/ avb.o
+$(MRPCLIENT_DIR)/%.o: $(MRPCLIENT_DIR)/%.c $(MRPCLIENT_DIR)/%.h
+ make -C $(MRPCLIENT_DIR) $@
%: %.o
$(CC) $(LDFLAGS) $^ $(LDLIBS) $(EXTRA_FLAGS) -o $@
diff --git a/examples/live_stream/listener.c b/examples/live_stream/listener.c
index 7ce12000..8f469e2f 100644
--- a/examples/live_stream/listener.c
+++ b/examples/live_stream/listener.c
@@ -198,8 +198,11 @@ int main(int argc, char *argv[ ])
fprintf(stderr,"frame sequence = %lld\n", frame_sequence++);
h1722 = (seventeen22_header *)((uint8_t*)frame + sizeof(eth_header));
length = ntohs(h1722->length) - sizeof(six1883_header);
- write(1, (uint8_t *)((uint8_t*)frame + sizeof(eth_header) + sizeof(seventeen22_header) +
+ rc = write(1, (uint8_t *)((uint8_t*)frame + sizeof(eth_header) + sizeof(seventeen22_header) +
sizeof(six1883_header)), length);
+ if (rc == -1) {
+ fprintf(stderr, "Failed to write %d bytes: %s (%d)\n", length, strerror(errno), errno);
+ }
} else {
fprintf(stderr,"recvfrom() error for frame sequence = %lld\n", frame_sequence++);
}
diff --git a/examples/simple_listener/Makefile b/examples/simple_listener/Makefile
index 9a4b33a6..02d66fa8 100644
--- a/examples/simple_listener/Makefile
+++ b/examples/simple_listener/Makefile
@@ -1,18 +1,24 @@
+MRPCLIENT_DIR = ../common
+MRPLISTENER_OBJS = listener_mrp_client.o
+MRPLISTENER_TARGETS = $(addprefix $(MRPCLIENT_DIR)/,$(MRPLISTENER_OBJS))
+
+DAEMONS_DIR = ../../daemons
+
CC ?= gcc
OPT = -O2 -g
-CFLAGS = $(OPT) -Wall -Wextra -Wno-parentheses
-INCFLAGS = -I../../daemons/mrpd -I../common -I../../daemons/common
+WARN=-Wall -Wextra -Wno-parentheses
+CFLAGS=$(OPT) $(WARN)
+CPPFLAGS = -I$(DAEMONS_DIR)/mrpd -I$(MRPCLIENT_DIR) -I$(DAEMONS_DIR)/common
LDLIBS = -lpcap -lsndfile -pthread
all: simple_listener
-simple_listener: simple_listener.o ../common/listener_mrp_client.o
+simple_listener: simple_listener.o $(MRPLISTENER_TARGETS)
simple_listener.o: simple_listener.c
- $(CC) $(CFLAGS) $(INCFLAGS) -c simple_listener.c
-../common/listener_mrp_client.o: ../common/listener_mrp_client.c ../common/listener_mrp_client.h
- make -C ../common/ listener_mrp_client.o
+$(MRPCLIENT_DIR)/%.o: $(MRPCLIENT_DIR)/%.c $(MRPCLIENT_DIR)/%.h
+ make -C $(MRPCLIENT_DIR) $@
%: %.o
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
diff --git a/examples/simple_listener/simple_listener.c b/examples/simple_listener/simple_listener.c
index bd1c1cab..aecd74aa 100644
--- a/examples/simple_listener/simple_listener.c
+++ b/examples/simple_listener/simple_listener.c
@@ -45,8 +45,10 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ STREAM_ID_SIZE \
+ SEVENTEEN22_HEADER_PART2_SIZE \
+ SIX1883_HEADER_SIZE)
+#define HEADER_SIZE_AAF (36)
#define SAMPLES_PER_SECOND (48000)
#define SAMPLES_PER_FRAME (6)
+#define SAMPLES_PER_FRAME_AAF (64)
#define CHANNELS (2)
struct mrp_listener_ctx *ctx_sig;//Context pointer for signal handler
@@ -63,9 +65,17 @@ struct ethernet_header{
static const char *version_str = "simple_listener v" VERSION_STR "\n"
"Copyright (c) 2012, Intel Corporation\n";
+static const char *static_dest_mac = "91:E0:F0:00:FE:01";
+static u_char static_stream_id[] = { 0x91, 0xE0, 0xF0, 0x00, 0xFE, 0x00, 0x00, 0x01 };
+
pcap_t* glob_pcap_handle;
+
u_char glob_ether_type[] = { 0x22, 0xf0 };
-SNDFILE* glob_snd_file;
+SNDFILE* glob_snd_file = NULL;
+u_char* glob_target_stream_id = NULL;
+
+u_char glob_no_srp = 0;
+u_char glob_use_aaf = 0;
static void help()
{
@@ -75,6 +85,8 @@ static void help()
"Options:\n"
" -h show this message\n"
" -i specify interface for AVB connection\n"
+ " -n no SRP\n"
+ " -a use AAF\n"
" -f set the name of the output wav-file\n"
"\n" "%s" "\n", version_str);
exit(EXIT_FAILURE);
@@ -84,10 +96,11 @@ void pcap_callback(u_char* args, const struct pcap_pkthdr* packet_header, const
{
unsigned char* test_stream_id;
struct ethernet_header* eth_header;
- uint32_t *buf;
+ uint32_t* buf;
uint32_t frame[2] = { 0 , 0 };
+
int i;
- struct mrp_listener_ctx *ctx = (struct mrp_listener_ctx*) args;
+ (void) args; /* unused */
(void) packet_header; /* unused */
#if DEBUG
@@ -112,13 +125,13 @@ void pcap_callback(u_char* args, const struct pcap_pkthdr* packet_header, const
test_stream_id[6], test_stream_id[7]);
#endif /* DEBUG*/
- if (0 == memcmp(test_stream_id, ctx->stream_id, sizeof(STREAM_ID_SIZE)))
+ if (0 == memcmp(test_stream_id, glob_target_stream_id, sizeof(STREAM_ID_SIZE)))
{
#if DEBUG
fprintf(stdout,"Stream ids matched.\n");
#endif /* DEBUG*/
- buf = (uint32_t*) (packet + HEADER_SIZE);
+ buf = (uint32_t*)(packet + HEADER_SIZE);
for(i = 0; i < SAMPLES_PER_FRAME * CHANNELS; i += 2)
{
memcpy(&frame[0], &buf[i], sizeof(frame));
@@ -136,6 +149,58 @@ void pcap_callback(u_char* args, const struct pcap_pkthdr* packet_header, const
}
}
+void pcap_aaf_callback(u_char* args, const struct pcap_pkthdr* packet_header, const u_char* packet)
+{
+ unsigned char* test_stream_id;
+ struct ethernet_header* eth_header;
+ uint16_t* buf;
+ uint16_t frame[2] = { 0 , 0 };
+
+ int i;
+ (void) args; /* unused */
+ (void) packet_header; /* unused */
+
+#if DEBUG
+ fprintf(stdout,"Got packet.\n");
+#endif /* DEBUG*/
+
+ eth_header = (struct ethernet_header*)(packet);
+
+#if DEBUG
+ fprintf(stdout,"Ether Type: 0x%02x%02x\n", eth_header->type[0], eth_header->type[1]);
+#endif /* DEBUG*/
+
+ if (0 == memcmp(glob_ether_type,eth_header->type,sizeof(eth_header->type)))
+ {
+ test_stream_id = (unsigned char*)(packet + ETHERNET_HEADER_SIZE + SEVENTEEN22_HEADER_PART1_SIZE);
+
+#if DEBUG
+ fprintf(stderr, "Received stream id: %02x%02x%02x%02x%02x%02x%02x%02x\n ",
+ test_stream_id[0], test_stream_id[1],
+ test_stream_id[2], test_stream_id[3],
+ test_stream_id[4], test_stream_id[5],
+ test_stream_id[6], test_stream_id[7]);
+#endif /* DEBUG*/
+
+ if (0 == memcmp(test_stream_id, glob_target_stream_id, sizeof(STREAM_ID_SIZE)))
+ {
+
+#if DEBUG
+ fprintf(stdout,"Stream ids matched.\n");
+#endif /* DEBUG*/
+ buf = (uint16_t*)(packet + HEADER_SIZE_AAF);
+ for(i = 0; i < SAMPLES_PER_FRAME_AAF * CHANNELS; i += 2)
+ {
+ memcpy(&frame[0], &buf[i], sizeof(frame));
+ frame[0] = ntohs(frame[0]); /* convert to host-byte order */
+ frame[1] = ntohs(frame[1]);
+
+ sf_writef_short(glob_snd_file, (const short *)frame, 1);
+ }
+ }
+ }
+}
+
void sigint_handler(int signum)
{
int ret;
@@ -170,65 +235,34 @@ void sigint_handler(int signum)
#endif /* LIBSND */
}
-int main(int argc, char *argv[])
+int init_mrp(struct mrp_listener_ctx *ctx, struct mrp_domain_attr *class_a, struct mrp_domain_attr *class_b)// struct mrp_domain_attr *class_a, struct mrp_domain_attr *class_a)
{
- char* file_name = NULL;
- char* dev = NULL;
- char errbuf[PCAP_ERRBUF_SIZE];
- struct bpf_program comp_filter_exp; /* The compiled filter expression */
- char filter_exp[100]; /* The filter expression */
- struct mrp_listener_ctx *ctx = malloc(sizeof(struct mrp_listener_ctx));
- struct mrp_domain_attr *class_a = malloc(sizeof(struct mrp_domain_attr));
- struct mrp_domain_attr *class_b = malloc(sizeof(struct mrp_domain_attr));
- ctx_sig = ctx;
- signal(SIGINT, sigint_handler);
-
- int c,rc;
- while((c = getopt(argc, argv, "hi:f:")) > 0)
- {
- switch (c)
- {
- case 'h':
- help();
- break;
- case 'i':
- dev = strdup(optarg);
- break;
- case 'f':
- file_name = strdup(optarg);
- break;
- default:
- fprintf(stderr, "Unrecognized option!\n");
- }
- }
-
- if ((NULL == dev) || (NULL == file_name))
- help();
+ int rc;
rc = mrp_listener_client_init(ctx);
if (rc)
{
printf("failed to initialize global variables\n");
- return EXIT_FAILURE;
+ return -1;
}
if (create_socket(ctx))
{
fprintf(stderr, "Socket creation failed.\n");
- return errno;
+ return -1;
}
rc = mrp_monitor(ctx);
if (rc)
{
printf("failed creating MRP monitor thread\n");
- return EXIT_FAILURE;
+ return -1;
}
- rc=mrp_get_domain(ctx, class_a, class_b);
+ rc = mrp_get_domain(ctx, class_a, class_b);
if (rc)
{
printf("failed calling mrp_get_domain()\n");
- return EXIT_FAILURE;
+ return -1;
}
printf("detected domain Class A PRIO=%d VID=%04x...\n",class_a->priority,class_a->vid);
@@ -236,24 +270,95 @@ int main(int argc, char *argv[])
rc = report_domain_status(class_a,ctx);
if (rc) {
printf("report_domain_status failed\n");
- return EXIT_FAILURE;
+ return -1;
}
rc = join_vlan(class_a, ctx);
if (rc) {
printf("join_vlan failed\n");
- return EXIT_FAILURE;
+ return -1;
+ }
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ char* file_name = NULL;
+ char* dev = NULL;
+ int sf_pcm_format = SF_FORMAT_PCM_24;
+ char errbuf[PCAP_ERRBUF_SIZE];
+ struct bpf_program comp_filter_exp; /* The compiled filter expression */
+ char filter_exp[100]; /* The filter expression */
+ char dest_mac[30];
+ pcap_handler callback = pcap_callback;
+ struct mrp_listener_ctx *ctx = malloc(sizeof(struct mrp_listener_ctx));
+ struct mrp_domain_attr *class_a = malloc(sizeof(struct mrp_domain_attr));
+ struct mrp_domain_attr *class_b = malloc(sizeof(struct mrp_domain_attr));
+ ctx_sig = ctx;
+ signal(SIGINT, sigint_handler);
+
+ int c, rc;
+ while((c = getopt(argc, argv, "anhi:f:")) > 0)
+ {
+ switch (c)
+ {
+ case 'h':
+ help();
+ break;
+ case 'i':
+ dev = strdup(optarg);
+ break;
+ case 'f':
+ file_name = strdup(optarg);
+ break;
+ case 'n':
+ glob_no_srp = 1;
+ sprintf(dest_mac,"%s", static_dest_mac);
+ glob_target_stream_id = static_stream_id;
+ break;
+ case 'a':
+ glob_use_aaf = 1;
+ sf_pcm_format = SF_FORMAT_PCM_16;
+ callback = pcap_aaf_callback;
+ break;
+ default:
+ fprintf(stderr, "Unrecognized option!\n");
+ }
}
- fprintf(stdout,"Waiting for talker...\n");
- await_talker(ctx);
+ if ((NULL == dev) || (NULL == file_name))
+ help();
+
+ if (0 == glob_no_srp)
+ {
+ if (-1 == init_mrp(ctx, class_a, class_b))
+ {
+ printf("init_mrp failed\n");
+ return EXIT_FAILURE;
+ }
+
+ fprintf(stdout,"Waiting for talker...\n");
+ await_talker(ctx);
#if DEBUG
- fprintf(stdout,"Send ready-msg...\n");
+ fprintf(stdout,"Send ready-msg...\n");
#endif /* DEBUG */
- rc = send_ready(ctx);
- if (rc) {
- printf("send_ready failed\n");
+ rc = send_ready(ctx);
+ if (rc) {
+ printf("send_ready failed\n");
+ return EXIT_FAILURE;
+ }
+
+ glob_target_stream_id = ctx->stream_id;
+ sprintf(dest_mac,"%02x:%02x:%02x:%02x:%02x:%02x",
+ ctx->dst_mac[0], ctx->dst_mac[1], ctx->dst_mac[2],
+ ctx->dst_mac[3], ctx->dst_mac[4], ctx->dst_mac[5]);
+ }
+
+ if (NULL == glob_target_stream_id)
+ {
+ fprintf(stderr, "Target Stream ID not set");
return EXIT_FAILURE;
}
@@ -264,7 +369,7 @@ int main(int argc, char *argv[])
sf_info->samplerate = SAMPLES_PER_SECOND;
sf_info->channels = CHANNELS;
- sf_info->format = SF_FORMAT_WAV | SF_FORMAT_PCM_24;
+ sf_info->format = SF_FORMAT_WAV | sf_pcm_format;
if (0 == sf_format_check(sf_info))
{
@@ -272,11 +377,14 @@ int main(int argc, char *argv[])
return EXIT_FAILURE;
}
+ fprintf(stdout,"Output SampleRate:%d, Channels:%d, Format0x%X\n",
+ sf_info->samplerate, sf_info->channels, sf_info->format);
if (NULL == (glob_snd_file = sf_open(file_name, SFM_WRITE, sf_info)))
{
fprintf(stderr, "Could not create file.");
return EXIT_FAILURE;
}
+
fprintf(stdout,"Created file called %s\n", file_name);
#endif /* LIBSND */
@@ -293,8 +401,10 @@ int main(int argc, char *argv[])
#if DEBUG
fprintf(stdout,"Got session pcap handler.\n");
#endif /* DEBUG */
+
/* compile and apply filter */
- sprintf(filter_exp,"ether dst %02x:%02x:%02x:%02x:%02x:%02x",ctx->dst_mac[0],ctx->dst_mac[1],ctx->dst_mac[2],ctx->dst_mac[3],ctx->dst_mac[4],ctx->dst_mac[5]);
+ fprintf(stdout,"Create packet filter ether dst %s\n", dest_mac);
+ sprintf(filter_exp,"ether dst %s", dest_mac);
if (-1 == pcap_compile(glob_pcap_handle, &comp_filter_exp, filter_exp, 0, PCAP_NETMASK_UNKNOWN))
{
fprintf(stderr, "Could not parse filter %s: %s\n", filter_exp, pcap_geterr(glob_pcap_handle));
@@ -310,9 +420,11 @@ int main(int argc, char *argv[])
#if DEBUG
fprintf(stdout,"Compiled and applied filter.\n");
#endif /* DEBUG */
-
+ printf("Target Stream ID: 0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ glob_target_stream_id[0], glob_target_stream_id[1], glob_target_stream_id[2], glob_target_stream_id[3],
+ glob_target_stream_id[4], glob_target_stream_id[5], glob_target_stream_id[6], glob_target_stream_id[7]);
/** loop forever and call callback-function for every received packet */
- pcap_loop(glob_pcap_handle, -1, pcap_callback, (u_char*)ctx);
+ pcap_loop(glob_pcap_handle, -1, callback, (u_char*)ctx);
#endif /* PCAP */
free(ctx);
free(class_a);
diff --git a/examples/simple_rx/Makefile b/examples/simple_rx/Makefile
index 7ca14365..c27e811b 100644
--- a/examples/simple_rx/Makefile
+++ b/examples/simple_rx/Makefile
@@ -1,27 +1,37 @@
+
+MRPCLIENT_DIR = ../common
+MRPLISTENER_OBJS = listener_mrp_client.o
+MRPLISTENER_TARGETS = $(addprefix $(MRPCLIENT_DIR)/,$(MRPLISTENER_OBJS))
+
+IGBLIB_DIR = ../../lib/igb
+IGBLIB_OBJS = igb.o
+IGBLIB_TARGETS = $(addprefix $(IGBLIB_DIR)/,$(IGBLIB_OBJS))
+
+DAEMONS_DIR = ../../daemons
+
CC ?= gcc
OPT = -O2 -g
-CFLAGS = $(OPT) -Wall -Wextra -Wno-parentheses
-IGBDIR = ../../lib/igb
-INCFLAGS = -I../../daemons/mrpd -I../common -I../../daemons/common -I$(IGBDIR)
+WARN=-Wall -Wextra -Wno-parentheses
+CFLAGS=$(OPT) $(WARN)
+CPPFLAGS = -I$(DAEMONS_DIR)/mrpd -I$(MRPCLIENT_DIR) -I$(DAEMONS_DIR)/common -I$(IGBLIB_DIR)
# GLIBC versions starting with 2.17 don't need -lrt anymore
LDLIBS = -lpcap -lsndfile -pthread -lpci -lrt
all: simple_rx
-simple_rx: simple_rx.o ../common/listener_mrp_client.o $(IGBDIR)/igb.o
+simple_rx: simple_rx.o $(MRPLISTENER_TARGETS) $(IGBLIB_TARGETS)
simple_rx.o: simple_rx.c
- $(CC) $(CFLAGS) $(INCFLAGS) -c simple_rx.c
-../common/listener_mrp_client.o: ../common/listener_mrp_client.c ../common/listener_mrp_client.h
- make -C ../common/ listener_mrp_client.o
+$(MRPCLIENT_DIR)/%.o: $(MRPCLIENT_DIR)/%.c $(MRPCLIENT_DIR)/%.h
+ make -C $(MRPCLIENT_DIR) $@
-$(IGBDIR)/igb.o: $(IGBDIR)/igb.c
- make -C $(IGBDIR) igb.o
+$(IGBLIB_DIR)/%.o: $(IGBLIB_DIR)/%.c $(IGBLIB_DIR)/%.h
+ make -C $(IGBLIB_DIR) $@
%: %.o
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
clean:
- $(RM) simple_listener
+ $(RM) simple_rx
$(RM) `find . -name "*~" -o -name "*.[oa]" -o -name "\#*\#" -o -name TAGS -o -name core -o -name "*.orig"`
diff --git a/examples/simple_rx/simple_rx.c b/examples/simple_rx/simple_rx.c
index 8d90f81a..64216f78 100644
--- a/examples/simple_rx/simple_rx.c
+++ b/examples/simple_rx/simple_rx.c
@@ -355,6 +355,7 @@ int igb_start_rx(device_t *igb_dev, struct mrp_listener_ctx *ctx)
uint8_t test_filter[128];
uint8_t filter_mask[64];
+ uint32_t filter_len = 0;
struct ethhdr *ethhdr = NULL;
uint16_t *ethtype = NULL;
@@ -452,11 +453,12 @@ int igb_start_rx(device_t *igb_dev, struct mrp_listener_ctx *ctx)
filter_mask[1] = 0x30; /* 00110000b = ethtype */
filter_mask[2] = 0x03; /* 00000011b = ethtype after a vlan tag */
+ /* length must be 8 byte-aligned */
+ filter_len = ((ETHERNET_HEADER_SIZE + (8u - 1u)) / 8u) * 8u;
+
/* install the filter on queue0 */
- igb_setup_flex_filter(igb_dev, IGB_QUEUE_0, 0, ETHERNET_HEADER_SIZE,
+ rc = igb_setup_flex_filter(igb_dev, IGB_QUEUE_0, 0, filter_len,
test_filter, filter_mask);
-
- rc = 0;
out:
if (rc != 0)
igb_stop_rx(igb_dev);
diff --git a/examples/simple_talker/Makefile b/examples/simple_talker/Makefile
index bba47b03..aef9c541 100644
--- a/examples/simple_talker/Makefile
+++ b/examples/simple_talker/Makefile
@@ -1,22 +1,35 @@
+AVBLIB_DIR = ../../lib/common
+AVBLIB_OBJS = avb_avtp.o avb_gptp.o avb_igb.o
+AVBLIB_TARGETS = $(addprefix $(AVBLIB_DIR)/,$(AVBLIB_OBJS))
+
+MRPCLIENT_DIR = ../common
+MRPTALKER_OBJS = talker_mrp_client.o
+MRPTALKER_TARGETS = $(addprefix $(MRPCLIENT_DIR)/,$(MRPTALKER_OBJS))
+
+IGBLIB_DIR = ../../lib/igb
+DAEMONS_DIR = ../../daemons
+
CC?=gcc
OPT=-O2 -g
-CFLAGS=$(OPT) -Wall -Wextra -Wno-parentheses
-INCFLAGS=-I../../lib/igb -I../../daemons/mrpd -I../common -I../../lib/common -I../../daemons/common
+WARN=-Wall -Wextra -Wno-parentheses
+CFLAGS=$(OPT) $(WARN)
+CPPFLAGS=-I$(IGBLIB_DIR) -I$(DAEMONS_DIR)/mrpd -I$(MRPCLIENT_DIR) -I$(AVBLIB_DIR) -I$(DAEMONS_DIR)/common
LDLIBS=-ligb -lpci -lrt -lm -pthread
-LDFLAGS=-L../../lib/igb
+LDFLAGS=-L$(IGBLIB_DIR)
+
+.PHONY: all clean
all: simple_talker
-simple_talker: simple_talker.o ../common/talker_mrp_client.o ../../lib/common/avb.o
+simple_talker: simple_talker.o $(MRPTALKER_TARGETS) $(AVBLIB_TARGETS)
simple_talker.o: simple_talker.c
- $(CC) $(CFLAGS) $(INCFLAGS) -c simple_talker.c
-../../lib/common/avb.o: ../../lib/common/avb.h ../../lib/common/avb.c
- make -C ../../lib/common/ avb.o
+$(AVBLIB_DIR)/%.o: $(AVBLIB_DIR)/%.h $(AVBLIB_DIR)/%.c
+ make -C $(AVBLIB_DIR) $@
-../common/talker_mrp_client.o: ../common/talker_mrp_client.c ../common/talker_mrp_client.h
- make -C ../common/ talker_mrp_client.o
+$(MRPCLIENT_DIR)/%.o: $(MRPCLIENT_DIR)/%.c $(MRPCLIENT_DIR)/%.h
+ make -C $(MRPCLIENT_DIR) $@
%: %.o
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
diff --git a/kmod/igb/Makefile b/kmod/igb/Makefile
index 69086786..70ebea8c 100644
--- a/kmod/igb/Makefile
+++ b/kmod/igb/Makefile
@@ -41,6 +41,11 @@ endif
# PTP is required for AVB support
CFLAGS_EXTRA += -DIGB_PTP
+# Add 32 bit ioctl support
+ifeq ($(32BIT_IOCTL_SUPPORT),y)
+CFLAGS_EXTRA += -DSUPPORT_32BIT_IOCTL
+endif
+
# Use IGB_PTP compile flag to enable IEEE-1588 PTP (documented in README)
ifeq ($(filter %IGB_PTP,$(CFLAGS_EXTRA)),-DIGB_PTP)
CFILES += igb_ptp.c
@@ -48,6 +53,12 @@ endif
DRIVER_NAME=igb_avb
+####I2C enablement####
+ifeq ($(I2C_ENABLED), 1)
+$(info CFLAGS_EXTRA += -DI2C_ENABLED)
+CFLAGS_EXTRA += -DI2C_ENABLED
+endif
+
###########################################################################
# Environment tests
diff --git a/kmod/igb/e1000_82575.c b/kmod/igb/e1000_82575.c
index 5b933ca2..f8abc3e5 100644
--- a/kmod/igb/e1000_82575.c
+++ b/kmod/igb/e1000_82575.c
@@ -64,7 +64,9 @@ static s32 e1000_set_d0_lplu_state_82575(struct e1000_hw *hw,
static s32 e1000_setup_copper_link_82575(struct e1000_hw *hw);
static s32 e1000_setup_serdes_link_82575(struct e1000_hw *hw);
static s32 e1000_get_media_type_82575(struct e1000_hw *hw);
+#ifdef I2C_ENABLED
static s32 e1000_set_sfp_media_type_82575(struct e1000_hw *hw);
+#endif
static s32 e1000_valid_led_default_82575(struct e1000_hw *hw, u16 *data);
static s32 e1000_write_phy_reg_sgmii_82575(struct e1000_hw *hw,
u32 offset, u16 data);
@@ -1797,7 +1799,13 @@ static s32 e1000_get_media_type_82575(struct e1000_hw *hw)
/* fall through for I2C based SGMII */
case E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES:
/* read media type from SFP EEPROM */
+#ifdef I2C_ENABLED
+ printk(KERN_INFO "igb_avb I2C enabled - set_sfp_media_type_82575() called");
ret_val = e1000_set_sfp_media_type_82575(hw);
+#else
+ printk(KERN_INFO "igb_avb I2C disabled - set_sfp_media_type_82575() not necessary");
+ hw->phy.media_type = e1000_media_type_unknown;
+#endif
if ((ret_val != E1000_SUCCESS) ||
(hw->phy.media_type == e1000_media_type_unknown)) {
/*
@@ -1841,6 +1849,7 @@ static s32 e1000_get_media_type_82575(struct e1000_hw *hw)
* The media type is chosen based on SFP module.
* compatibility flags retrieved from SFP ID EEPROM.
**/
+#ifdef I2C_ENABLED
static s32 e1000_set_sfp_media_type_82575(struct e1000_hw *hw)
{
s32 ret_val = E1000_ERR_CONFIG;
@@ -1902,7 +1911,7 @@ out:
E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
return ret_val;
}
-
+#endif
/**
* e1000_valid_led_default_82575 - Verify a valid default LED config
* @hw: pointer to the HW structure
diff --git a/kmod/igb/e1000_defines.h b/kmod/igb/e1000_defines.h
index 4dce56b9..4022e22b 100644
--- a/kmod/igb/e1000_defines.h
+++ b/kmod/igb/e1000_defines.h
@@ -58,8 +58,10 @@
#define E1000_CTRL_EXT_LPCD 0x00000004 /* LCD Power Cycle Done */
#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* SW Definable Pin 4 data */
#define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* SW Definable Pin 6 data */
+#define E1000_CTRL_EXT_SDP2_DATA 0x00000040 /* SW Definable Pin 2 data */
#define E1000_CTRL_EXT_SDP3_DATA 0x00000080 /* SW Definable Pin 3 data */
#define E1000_CTRL_EXT_SDP6_DIR 0x00000400 /* Direction of SDP6 0=in 1=out */
+#define E1000_CTRL_EXT_SDP2_DIR 0x00000400 /* Direction of SDP2 0=in 1=out */
#define E1000_CTRL_EXT_SDP3_DIR 0x00000800 /* Direction of SDP3 0=in 1=out */
#define E1000_CTRL_EXT_FORCE_SMBUS 0x00000800 /* Force SMBus mode */
#define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */
@@ -258,6 +260,8 @@
#define E1000_CTRL_ADVD3WUC 0x00100000 /* D3 WUC */
#define E1000_CTRL_SWDPIN3 0x00200000 /* SWDPIN 3 value */
#define E1000_CTRL_SWDPIO0 0x00400000 /* SWDPIN 0 Input or output */
+#define E1000_CTRL_SDP0_DIR 0x00400000 /* SDP0 Data direction */
+#define E1000_CTRL_SDP1_DIR 0x00800000 /* SDP1 Data direction */
#define E1000_CTRL_RST 0x04000000 /* Global reset */
#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */
#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */
@@ -719,8 +723,67 @@
#define E1000_TIMINCA_INCPERIOD_SHIFT 24
#define E1000_TIMINCA_INCVALUE_MASK 0x00FFFFFF
-#define E1000_TSICR_TXTS 0x00000002
-#define E1000_TSIM_TXTS 0x00000002
+/* Time Sync Interrupt Cause/Mask Register Bits */
+
+#define TSINTR_SYS_WRAP (1 << 0) /* SYSTIM Wrap around. */
+#define TSINTR_TXTS (1 << 1) /* Transmit Timestamp. */
+#define TSINTR_RXTS (1 << 2) /* Receive Timestamp. */
+#define TSINTR_TT0 (1 << 3) /* Target Time 0 Trigger. */
+#define TSINTR_TT1 (1 << 4) /* Target Time 1 Trigger. */
+#define TSINTR_AUTT0 (1 << 5) /* Auxiliary Timestamp 0 Taken. */
+#define TSINTR_AUTT1 (1 << 6) /* Auxiliary Timestamp 1 Taken. */
+#define TSINTR_TADJ (1 << 7) /* Time Adjust Done. */
+
+#define TSYNC_INTERRUPTS TSINTR_TXTS
+#define E1000_TSICR_TXTS TSINTR_TXTS
+
+/* TSAUXC Configuration Bits */
+#define TSAUXC_EN_TT0 (1 << 0) /* Enable target time 0. */
+#define TSAUXC_EN_TT1 (1 << 1) /* Enable target time 1. */
+#define TSAUXC_EN_CLK0 (1 << 2) /* Enable Configurable Frequency Clock 0. */
+#define TSAUXC_SAMP_AUT0 (1 << 3) /* Latch SYSTIML/H into AUXSTMPL/0. */
+#define TSAUXC_ST0 (1 << 4) /* Start Clock 0 Toggle on Target Time 0. */
+#define TSAUXC_EN_CLK1 (1 << 5) /* Enable Configurable Frequency Clock 1. */
+#define TSAUXC_SAMP_AUT1 (1 << 6) /* Latch SYSTIML/H into AUXSTMPL/1. */
+#define TSAUXC_ST1 (1 << 7) /* Start Clock 1 Toggle on Target Time 1. */
+#define TSAUXC_EN_TS0 (1 << 8) /* Enable hardware timestamp 0. */
+#define TSAUXC_AUTT0 (1 << 9) /* Auxiliary Timestamp Taken. */
+#define TSAUXC_EN_TS1 (1 << 10) /* Enable hardware timestamp 0. */
+#define TSAUXC_AUTT1 (1 << 11) /* Auxiliary Timestamp Taken. */
+#define TSAUXC_PLSG (1 << 17) /* Generate a pulse. */
+#define TSAUXC_DISABLE (1 << 31) /* Disable SYSTIM Count Operation. */
+
+/* SDP Configuration Bits */
+#define AUX0_SEL_SDP0 (0 << 0) /* Assign SDP0 to auxiliary time stamp 0. */
+#define AUX0_SEL_SDP1 (1 << 0) /* Assign SDP1 to auxiliary time stamp 0. */
+#define AUX0_SEL_SDP2 (2 << 0) /* Assign SDP2 to auxiliary time stamp 0. */
+#define AUX0_SEL_SDP3 (3 << 0) /* Assign SDP3 to auxiliary time stamp 0. */
+#define AUX0_TS_SDP_EN (1 << 2) /* Enable auxiliary time stamp trigger 0. */
+#define AUX1_SEL_SDP0 (0 << 3) /* Assign SDP0 to auxiliary time stamp 1. */
+#define AUX1_SEL_SDP1 (1 << 3) /* Assign SDP1 to auxiliary time stamp 1. */
+#define AUX1_SEL_SDP2 (2 << 3) /* Assign SDP2 to auxiliary time stamp 1. */
+#define AUX1_SEL_SDP3 (3 << 3) /* Assign SDP3 to auxiliary time stamp 1. */
+#define AUX1_TS_SDP_EN (1 << 5) /* Enable auxiliary time stamp trigger 1. */
+#define TS_SDP0_SEL_TT0 (0 << 6) /* Target time 0 is output on SDP0. */
+#define TS_SDP0_SEL_TT1 (1 << 6) /* Target time 1 is output on SDP0. */
+#define TS_SDP0_SEL_FC0 (2 << 6) /* Freq clock 0 is output on SDP0. */
+#define TS_SDP0_SEL_FC1 (3 << 6) /* Freq clock 1 is output on SDP0. */
+#define TS_SDP0_EN (1 << 8) /* SDP0 is assigned to Tsync. */
+#define TS_SDP1_SEL_TT0 (0 << 9) /* Target time 0 is output on SDP1. */
+#define TS_SDP1_SEL_TT1 (1 << 9) /* Target time 1 is output on SDP1. */
+#define TS_SDP1_SEL_FC0 (2 << 9) /* Freq clock 0 is output on SDP1. */
+#define TS_SDP1_SEL_FC1 (3 << 9) /* Freq clock 1 is output on SDP1. */
+#define TS_SDP1_EN (1 << 11) /* SDP1 is assigned to Tsync. */
+#define TS_SDP2_SEL_TT0 (0 << 12) /* Target time 0 is output on SDP2. */
+#define TS_SDP2_SEL_TT1 (1 << 12) /* Target time 1 is output on SDP2. */
+#define TS_SDP2_SEL_FC0 (2 << 12) /* Freq clock 0 is output on SDP2. */
+#define TS_SDP2_SEL_FC1 (3 << 12) /* Freq clock 1 is output on SDP2. */
+#define TS_SDP2_EN (1 << 14) /* SDP2 is assigned to Tsync. */
+#define TS_SDP3_SEL_TT0 (0 << 15) /* Target time 0 is output on SDP3. */
+#define TS_SDP3_SEL_TT1 (1 << 15) /* Target time 1 is output on SDP3. */
+#define TS_SDP3_SEL_FC0 (2 << 15) /* Freq clock 0 is output on SDP3. */
+#define TS_SDP3_SEL_FC1 (3 << 15) /* Freq clock 1 is output on SDP3. */
+#define TS_SDP3_EN (1 << 17) /* SDP3 is assigned to Tsync. */
/* TUPLE Filtering Configuration */
#define E1000_TTQF_DISABLE_MASK 0xF0008000 /* TTQF Disable Mask */
#define E1000_TTQF_QUEUE_ENABLE 0x100 /* TTQF Queue Enable Bit */
diff --git a/kmod/igb/e1000_regs.h b/kmod/igb/e1000_regs.h
index da373a97..caf1d04d 100644
--- a/kmod/igb/e1000_regs.h
+++ b/kmod/igb/e1000_regs.h
@@ -51,6 +51,7 @@
#define E1000_FCT 0x00030 /* Flow Control Type - RW */
#define E1000_CONNSW 0x00034 /* Copper/Fiber switch control - RW */
#define E1000_VET 0x00038 /* VLAN Ether Type - RW */
+#define E1000_TSSDP 0x0003C /* Time Sync SDP Configuration Register - RW */
#define E1000_ICR 0x000C0 /* Interrupt Cause Read - R/clr */
#define E1000_ITR 0x000C4 /* Interrupt Throttling Rate - RW */
#define E1000_ICS 0x000C8 /* Interrupt Cause Set - WO */
@@ -529,11 +530,19 @@
#define E1000_TIMADJL 0x0B60C /* Time sync time adjustment offset Low - RW */
#define E1000_TIMADJH 0x0B610 /* Time sync time adjustment offset High - RW */
#define E1000_TSAUXC 0x0B640 /* Timesync Auxiliary Control register */
+#define E1000_TRGTTIML0 0x0B644 /* Target Time Register 0 Low - RW */
+#define E1000_TRGTTIMH0 0x0B648 /* Target Time Register 0 High - RW */
+#define E1000_TRGTTIML1 0x0B64C /* Target Time Register 1 Low - RW */
+#define E1000_TRGTTIMH1 0x0B650 /* Target Time Register 1 High - RW */
+#define E1000_FREQOUT0 0x0B654 /* Frequency Out 0 Control Register - RW */
+#define E1000_FREQOUT1 0x0B658 /* Frequency Out 1 Control Register - RW */
+#define E1000_AUXSTMPL0 0x0B65C /* Auxiliary Time Stamp 0 Register Low - RO */
+#define E1000_AUXSTMPH0 0x0B660 /* Auxiliary Time Stamp 0 Register High - RO */
+#define E1000_AUXSTMPL1 0x0B664 /* Auxiliary Time Stamp 1 Register Low - RO */
+#define E1000_AUXSTMPH1 0x0B668 /* Auxiliary Time Stamp 1 Register High - RO */
#define E1000_SYSTIMR 0x0B6F8 /* System time register Residue */
#define E1000_TSICR 0x0B66C /* Interrupt Cause Register */
#define E1000_TSIM 0x0B674 /* Interrupt Mask Register */
-#define E1000_AUXSTMPL0 0x0B65C /* Auxiliary Time Stamp 0 Reg - Low */
-#define E1000_AUXSTMPH0 0x0B660 /* Auxiliary Time Stamp 0 Reg - Low */
/* Filtering Registers */
#define E1000_SAQF(_n) (0x05980 + (4 * (_n))) /* Source Address Queue Fltr */
diff --git a/kmod/igb/igb.h b/kmod/igb/igb.h
index 1da12050..7fb3e53a 100644
--- a/kmod/igb/igb.h
+++ b/kmod/igb/igb.h
@@ -514,6 +514,9 @@ struct hwmon_buff {
unsigned int n_hwmon;
};
#endif /* IGB_HWMON */
+#define IGB_N_EXTTS 2
+#define IGB_N_PEROUT 2
+#define IGB_N_SDP 4
#ifdef ETHTOOL_GRXFHINDIR
#define IGB_RETA_SIZE 128
#endif /* ETHTOOL_GRXFHINDIR */
@@ -659,6 +662,14 @@ struct igb_adapter {
struct timecounter tc;
u32 tx_hwtstamp_timeouts;
u32 rx_hwtstamp_cleared;
+
+#ifdef HAVE_PTP_1588_CLOCK_PINS
+ struct ptp_pin_desc sdp_config[IGB_N_SDP];
+#endif /* HAVE_PTP_1588_CLOCK_PINS */
+ struct {
+ struct timespec64 start;
+ struct timespec64 period;
+ } perout[IGB_N_PEROUT];
#endif /* HAVE_PTP_1588_CLOCK */
#ifdef HAVE_I2C_SUPPORT
diff --git a/kmod/igb/igb_ethtool.c b/kmod/igb/igb_ethtool.c
index d1237e44..51ccf3a0 100644
--- a/kmod/igb/igb_ethtool.c
+++ b/kmod/igb/igb_ethtool.c
@@ -41,6 +41,11 @@
#include <linux/mdio.h>
#endif
+static int tx_size_ethtool = 256; /*default value*/
+module_param(tx_size_ethtool, int, 0);
+MODULE_PARM_DESC(tx_size_ethtool, "Tx ring size passed in insmod parameter");
+
+
#ifdef ETHTOOL_OPS_COMPAT
#include "kcompat_ethtool.c"
#endif
@@ -1307,7 +1312,8 @@ static int igb_setup_desc_rings(struct igb_adapter *adapter)
int ret_val;
/* Setup Tx descriptor ring and Tx buffers */
- tx_ring->count = IGB_DEFAULT_TXD;
+ tx_ring->count = tx_size_ethtool;
+ printk(KERN_INFO "igb_avb ethtool::tx_ring->count = %d", tx_ring->count);
tx_ring->dev = pci_dev_to_dev(adapter->pdev);
tx_ring->netdev = adapter->netdev;
tx_ring->reg_idx = adapter->vfs_allocated_count;
diff --git a/kmod/igb/igb_main.c b/kmod/igb/igb_main.c
index 79dead8f..3310680d 100644
--- a/kmod/igb/igb_main.c
+++ b/kmod/igb/igb_main.c
@@ -361,6 +361,10 @@ static int debug = NETIF_MSG_DRV | NETIF_MSG_PROBE;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0=none, ..., 16=all)");
+
+static int tx_size = 256; /*default value*/
+module_param(tx_size, int, 0);
+MODULE_PARM_DESC(tx_size, "Tx Ring size passed in insmod parameter");
/**
* igb_init_module - Driver Registration Routine
*
@@ -889,7 +893,7 @@ static void igb_disable_mdd(struct igb_adapter *adapter)
struct e1000_hw *hw = &adapter->hw;
u32 reg;
- if ((hw->mac.type != e1000_i350) ||
+ if ((hw->mac.type != e1000_i350) &&
(hw->mac.type != e1000_i354))
return;
@@ -3237,7 +3241,8 @@ static int igb_sw_init(struct igb_adapter *adapter)
pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
/* set default ring sizes */
- adapter->tx_ring_count = IGB_DEFAULT_TXD;
+ adapter->tx_ring_count = tx_size;
+ printk(KERN_INFO "igb_avb adapter->tx_ring_size %d", tx_size);
adapter->rx_ring_count = IGB_DEFAULT_RXD;
/* set default work limits */
@@ -3313,15 +3318,17 @@ static int __igb_open(struct net_device *netdev, bool resuming)
netif_carrier_off(netdev);
- /* allocate transmit descriptors */
- err = igb_setup_all_tx_resources(adapter);
- if (err)
- goto err_setup_tx;
+ if(!resuming){
+ /* allocate transmit descriptors */
+ err = igb_setup_all_tx_resources(adapter);
+ if (err)
+ goto err_setup_tx;
- /* allocate receive descriptors */
- err = igb_setup_all_rx_resources(adapter);
- if (err)
- goto err_setup_rx;
+ /* allocate receive descriptors */
+ err = igb_setup_all_rx_resources(adapter);
+ if (err)
+ goto err_setup_rx;
+ }
igb_power_up_link(adapter);
@@ -3433,8 +3440,10 @@ static int __igb_close(struct net_device *netdev, bool suspending)
igb_free_irq(adapter);
- igb_free_all_tx_resources(adapter);
- igb_free_all_rx_resources(adapter);
+ if(!suspending || (system_state != SYSTEM_RUNNING)){
+ igb_free_all_tx_resources(adapter);
+ igb_free_all_rx_resources(adapter);
+ }
#ifdef CONFIG_PM_RUNTIME
if (!suspending)
@@ -6049,6 +6058,81 @@ void igb_update_stats(struct igb_adapter *adapter)
}
}
+static void igb_tsync_interrupt(struct igb_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct ptp_clock_event event;
+ struct timespec64 ts;
+ u32 ack = 0, tsauxc, sec, nsec, tsicr = E1000_READ_REG(hw, E1000_TSICR);
+
+ if (tsicr & TSINTR_SYS_WRAP) {
+ event.type = PTP_CLOCK_PPS;
+ if (adapter->ptp_caps.pps)
+ ptp_clock_event(adapter->ptp_clock, &event);
+ else
+ dev_err(&adapter->pdev->dev, "unexpected SYS WRAP");
+ ack |= TSINTR_SYS_WRAP;
+ }
+
+ if (tsicr & E1000_TSICR_TXTS) {
+ /* retrieve hardware timestamp */
+ schedule_work(&adapter->ptp_tx_work);
+ ack |= E1000_TSICR_TXTS;
+ }
+
+ if (tsicr & TSINTR_TT0) {
+ spin_lock(&adapter->tmreg_lock);
+ ts = timespec64_add(adapter->perout[0].start,
+ adapter->perout[0].period);
+ /* u32 conversion of tv_sec is safe until y2106 */
+ E1000_WRITE_REG(hw, E1000_TRGTTIML0, ts.tv_nsec);
+ E1000_WRITE_REG(hw, E1000_TRGTTIMH0, (u32)ts.tv_sec);
+ tsauxc = E1000_READ_REG(hw, E1000_TSAUXC);
+ tsauxc |= TSAUXC_EN_TT0;
+ E1000_WRITE_REG(hw, E1000_TSAUXC, tsauxc);
+ adapter->perout[0].start = ts;
+ spin_unlock(&adapter->tmreg_lock);
+ ack |= TSINTR_TT0;
+ }
+
+ if (tsicr & TSINTR_TT1) {
+ spin_lock(&adapter->tmreg_lock);
+ ts = timespec64_add(adapter->perout[1].start,
+ adapter->perout[1].period);
+ E1000_WRITE_REG(hw, E1000_TRGTTIML1, ts.tv_nsec);
+ E1000_WRITE_REG(hw, E1000_TRGTTIMH1, (u32)ts.tv_sec);
+ tsauxc = E1000_READ_REG(hw, E1000_TSAUXC);
+ tsauxc |= TSAUXC_EN_TT1;
+ E1000_WRITE_REG(hw, E1000_TSAUXC, tsauxc);
+ adapter->perout[1].start = ts;
+ spin_unlock(&adapter->tmreg_lock);
+ ack |= TSINTR_TT1;
+ }
+
+ if (tsicr & TSINTR_AUTT0) {
+ nsec = E1000_READ_REG(hw, E1000_AUXSTMPL0);
+ sec = E1000_READ_REG(hw, E1000_AUXSTMPH0);
+ event.type = PTP_CLOCK_EXTTS;
+ event.index = 0;
+ event.timestamp = sec * 1000000000ULL + nsec;
+ ptp_clock_event(adapter->ptp_clock, &event);
+ ack |= TSINTR_AUTT0;
+ }
+
+ if (tsicr & TSINTR_AUTT1) {
+ nsec = E1000_READ_REG(hw, E1000_AUXSTMPL1);
+ sec = E1000_READ_REG(hw, E1000_AUXSTMPH1);
+ event.type = PTP_CLOCK_EXTTS;
+ event.index = 1;
+ event.timestamp = sec * 1000000000ULL + nsec;
+ ptp_clock_event(adapter->ptp_clock, &event);
+ ack |= TSINTR_AUTT1;
+ }
+
+ /* acknowledge the interrupts */
+ E1000_WRITE_REG(hw, E1000_TSICR, ack);
+}
+
static irqreturn_t igb_msix_other(int irq, void *data)
{
struct igb_adapter *adapter = data;
@@ -6081,16 +6165,8 @@ static irqreturn_t igb_msix_other(int irq, void *data)
}
#ifdef HAVE_PTP_1588_CLOCK
- if (icr & E1000_ICR_TS) {
- u32 tsicr = E1000_READ_REG(hw, E1000_TSICR);
-
- if (tsicr & E1000_TSICR_TXTS) {
- /* acknowledge the interrupt */
- E1000_WRITE_REG(hw, E1000_TSICR, E1000_TSICR_TXTS);
- /* retrieve hardware timestamp */
- schedule_work(&adapter->ptp_tx_work);
- }
- }
+ if (icr & E1000_ICR_TS)
+ igb_tsync_interrupt(adapter);
#endif /* HAVE_PTP_1588_CLOCK */
/* Check for MDD event */
@@ -6999,16 +7075,8 @@ static irqreturn_t igb_intr_msi(int irq, void *data)
}
#ifdef HAVE_PTP_1588_CLOCK
- if (icr & E1000_ICR_TS) {
- u32 tsicr = E1000_READ_REG(hw, E1000_TSICR);
-
- if (tsicr & E1000_TSICR_TXTS) {
- /* acknowledge the interrupt */
- E1000_WRITE_REG(hw, E1000_TSICR, E1000_TSICR_TXTS);
- /* retrieve hardware timestamp */
- schedule_work(&adapter->ptp_tx_work);
- }
- }
+ if (icr & E1000_ICR_TS)
+ igb_tsync_interrupt(adapter);
#endif /* HAVE_PTP_1588_CLOCK */
napi_schedule(&q_vector->napi);
@@ -7055,16 +7123,8 @@ static irqreturn_t igb_intr(int irq, void *data)
}
#ifdef HAVE_PTP_1588_CLOCK
- if (icr & E1000_ICR_TS) {
- u32 tsicr = E1000_READ_REG(hw, E1000_TSICR);
-
- if (tsicr & E1000_TSICR_TXTS) {
- /* acknowledge the interrupt */
- E1000_WRITE_REG(hw, E1000_TSICR, E1000_TSICR_TXTS);
- /* retrieve hardware timestamp */
- schedule_work(&adapter->ptp_tx_work);
- }
- }
+ if (icr & E1000_ICR_TS)
+ igb_tsync_interrupt(adapter);
#endif /* HAVE_PTP_1588_CLOCK */
napi_schedule(&q_vector->napi);
@@ -9132,7 +9192,8 @@ static int __igb_shutdown(struct pci_dev *pdev, bool *enable_wake,
if (netif_running(netdev))
__igb_close(netdev, true);
- igb_clear_interrupt_scheme(adapter);
+ if(system_state != SYSTEM_RUNNING)
+ igb_clear_interrupt_scheme(adapter);
#ifdef CONFIG_PM
retval = pci_save_state(pdev);
@@ -9239,12 +9300,6 @@ static int igb_resume(struct pci_dev *pdev)
pci_enable_wake(pdev, PCI_D3hot, 0);
pci_enable_wake(pdev, PCI_D3cold, 0);
- if (igb_init_interrupt_scheme(adapter, true)) {
- dev_err(pci_dev_to_dev(pdev),
- "Unable to allocate memory for queues\n");
- return -ENOMEM;
- }
-
igb_reset(adapter);
/* let the f/w know that the h/w is now under the control of the driver.
@@ -10352,6 +10407,11 @@ static long igb_mapbuf(struct file *file, void __user *arg, int ring)
req.queue);
return -EINVAL;
}
+
+ if(!adapter->num_tx_queues) {
+ printk("igb_avb igb_mapbuf:tx ring freed %s\n", adapter->netdev->name);
+ return -EINVAL;
+ }
mutex_lock(&adapter->lock);
if (adapter->uring_tx_init & (1 << req.queue)) {
@@ -10373,6 +10433,11 @@ static long igb_mapbuf(struct file *file, void __user *arg, int ring)
return -EINVAL;
}
+ if(!adapter->num_rx_queues) {
+ printk("igb_avb igb_mapbuf:rx ring freed %s \n", adapter->netdev->name);
+ return -EINVAL;
+ }
+
mutex_lock(&adapter->lock);
if (adapter->uring_rx_init & (1 << req.queue)) {
mutex_unlock(&adapter->lock);
@@ -10542,7 +10607,7 @@ static int igb_open_file(struct inode *inode, struct file *file)
struct igb_private_data *igb_priv = NULL;
int ret = 0;
- igb_priv = kzalloc(sizeof(struct igb_private_data *), GFP_KERNEL);
+ igb_priv = kzalloc(sizeof(struct igb_private_data), GFP_KERNEL);
if (igb_priv == NULL) {
ret = -ENOMEM;
goto out;
@@ -10561,7 +10626,6 @@ static int igb_close_file(struct inode *inode, struct file *file)
struct igb_private_data *igb_priv = file->private_data;
struct igb_adapter *adapter = NULL;
int err = 0;
- int i;
struct igb_user_page *userpage;
if (igb_priv == NULL) {
@@ -10573,31 +10637,10 @@ static int igb_close_file(struct inode *inode, struct file *file)
if (adapter == NULL)
goto out;
- mutex_lock(&adapter->lock);
- /* free up any rings and user-mapped pages */
- for (i = 0; i < 3; i++) {
- if (igb_priv->uring_tx_init & (1 << i)) {
- if (adapter->uring_tx_init & (1 << i)) {
- igb_free_tx_resources(adapter->tx_ring[i]);
- } else {
- printk("Warning: invalid tx ring buffer state!\n");
- }
- adapter->uring_tx_init &= ~(1 << i);
- igb_priv->uring_tx_init &= ~(1 << i);
- }
- }
+ mutex_lock(&adapter->lock);
- for (i = 0; i < 3; i++) {
- if (igb_priv->uring_rx_init & (1 << i)) {
- if (adapter->uring_rx_init & (1 << i)) {
- igb_free_rx_resources(adapter->rx_ring[i]);
- } else {
- printk("Warning: invalid rx ring buffer state!\n");
- }
- adapter->uring_rx_init &= ~(1 << i);
- igb_priv->uring_rx_init &= ~(1 << i);
- }
- }
+ adapter->uring_tx_init &= ~igb_priv->uring_tx_init;
+ adapter->uring_rx_init &= ~igb_priv->uring_rx_init;
userpage = igb_priv->userpages;
diff --git a/kmod/igb/igb_ptp.c b/kmod/igb/igb_ptp.c
index 744fa654..e36d8a37 100644
--- a/kmod/igb/igb_ptp.c
+++ b/kmod/igb/igb_ptp.c
@@ -138,7 +138,8 @@ static cycle_t igb_ptp_read_82580(const struct cyclecounter *cc)
* SYSTIM read access for I210/I211
*/
-static void igb_ptp_read_i210(struct igb_adapter *adapter, struct timespec *ts)
+static void igb_ptp_read_i210(struct igb_adapter *adapter,
+ struct timespec64 *ts)
{
struct e1000_hw *hw = &adapter->hw;
u32 sec, nsec;
@@ -156,7 +157,7 @@ static void igb_ptp_read_i210(struct igb_adapter *adapter, struct timespec *ts)
}
static void igb_ptp_write_i210(struct igb_adapter *adapter,
- const struct timespec *ts)
+ const struct timespec64 *ts)
{
struct e1000_hw *hw = &adapter->hw;
@@ -165,7 +166,7 @@ static void igb_ptp_write_i210(struct igb_adapter *adapter,
* sub-nanosecond resolution.
*/
E1000_WRITE_REG(hw, E1000_SYSTIML, ts->tv_nsec);
- E1000_WRITE_REG(hw, E1000_SYSTIMH, ts->tv_sec);
+ E1000_WRITE_REG(hw, E1000_SYSTIMH, (u32)ts->tv_sec);
}
/**
@@ -314,13 +315,13 @@ static int igb_ptp_adjtime_i210(struct ptp_clock_info *ptp, s64 delta)
struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
ptp_caps);
unsigned long flags;
- struct timespec now, then = ns_to_timespec(delta);
+ struct timespec64 now, then = ns_to_timespec64(delta);
spin_lock_irqsave(&igb->tmreg_lock, flags);
igb_ptp_read_i210(igb, &now);
- now = timespec_add(now, then);
- igb_ptp_write_i210(igb, (const struct timespec *)&now);
+ now = timespec64_add(now, then);
+ igb_ptp_write_i210(igb, (const struct timespec64 *)&now);
spin_unlock_irqrestore(&igb->tmreg_lock, flags);
@@ -351,13 +352,11 @@ static int igb_ptp_gettime64_i210(struct ptp_clock_info *ptp,
{
struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
ptp_caps);
- struct timespec ts;
unsigned long flags;
spin_lock_irqsave(&igb->tmreg_lock, flags);
- igb_ptp_read_i210(igb, &ts);
- *ts64 = timespec_to_timespec64(ts);
+ igb_ptp_read_i210(igb, ts64);
spin_unlock_irqrestore(&igb->tmreg_lock, flags);
@@ -390,13 +389,11 @@ static int igb_ptp_settime64_i210(struct ptp_clock_info *ptp,
{
struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
ptp_caps);
- struct timespec ts;
unsigned long flags;
- ts = timespec64_to_timespec(*ts64);
spin_lock_irqsave(&igb->tmreg_lock, flags);
- igb_ptp_write_i210(igb, &ts);
+ igb_ptp_write_i210(igb, ts64);
spin_unlock_irqrestore(&igb->tmreg_lock, flags);
@@ -457,26 +454,287 @@ static int igb_ptp_settime_82576(struct ptp_clock_info *ptp,
static int igb_ptp_settime_i210(struct ptp_clock_info *ptp,
const struct timespec *ts)
{
- struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
- ptp_caps);
- unsigned long flags;
+ struct timespec64 ts64;
- spin_lock_irqsave(&igb->tmreg_lock, flags);
+ ts64 = timespec_to_timespec64(*ts);
- igb_ptp_write_i210(igb, ts);
+ return igb_ptp_settime64_i210(ptp, &ts64);
+}
- spin_unlock_irqrestore(&igb->tmreg_lock, flags);
+#endif
+#ifdef HAVE_PTP_1588_CLOCK_PINS
+static void igb_pin_direction(int pin, int input, u32 *ctrl, u32 *ctrl_ext)
+{
+ u32 *ptr = pin < 2 ? ctrl : ctrl_ext;
+ static const u32 mask[IGB_N_SDP] = {
+ E1000_CTRL_SDP0_DIR,
+ E1000_CTRL_SDP1_DIR,
+ E1000_CTRL_EXT_SDP2_DIR,
+ E1000_CTRL_EXT_SDP3_DIR,
+ };
+
+ if (input)
+ *ptr &= ~mask[pin];
+ else
+ *ptr |= mask[pin];
+}
- return 0;
+static void igb_pin_extts(struct igb_adapter *igb, int chan, int pin)
+{
+ static const u32 aux0_sel_sdp[IGB_N_SDP] = {
+ AUX0_SEL_SDP0, AUX0_SEL_SDP1, AUX0_SEL_SDP2, AUX0_SEL_SDP3,
+ };
+ static const u32 aux1_sel_sdp[IGB_N_SDP] = {
+ AUX1_SEL_SDP0, AUX1_SEL_SDP1, AUX1_SEL_SDP2, AUX1_SEL_SDP3,
+ };
+ static const u32 ts_sdp_en[IGB_N_SDP] = {
+ TS_SDP0_EN, TS_SDP1_EN, TS_SDP2_EN, TS_SDP3_EN,
+ };
+ struct e1000_hw *hw = &igb->hw;
+ u32 ctrl, ctrl_ext, tssdp = 0;
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ tssdp = E1000_READ_REG(hw, E1000_TSSDP);
+
+ igb_pin_direction(pin, 1, &ctrl, &ctrl_ext);
+
+ /* Make sure this pin is not enabled as an output. */
+ tssdp &= ~ts_sdp_en[pin];
+
+ if (chan == 1) {
+ tssdp &= ~AUX1_SEL_SDP3;
+ tssdp |= aux1_sel_sdp[pin] | AUX1_TS_SDP_EN;
+ } else {
+ tssdp &= ~AUX0_SEL_SDP3;
+ tssdp |= aux0_sel_sdp[pin] | AUX0_TS_SDP_EN;
+ }
+
+ E1000_WRITE_REG(hw, E1000_TSSDP, tssdp);
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
}
-#endif
-static int igb_ptp_enable(struct ptp_clock_info *ptp,
- struct ptp_clock_request *rq, int on)
+static void igb_pin_perout(struct igb_adapter *igb, int chan, int pin, int freq)
+{
+ static const u32 aux0_sel_sdp[IGB_N_SDP] = {
+ AUX0_SEL_SDP0, AUX0_SEL_SDP1, AUX0_SEL_SDP2, AUX0_SEL_SDP3,
+ };
+ static const u32 aux1_sel_sdp[IGB_N_SDP] = {
+ AUX1_SEL_SDP0, AUX1_SEL_SDP1, AUX1_SEL_SDP2, AUX1_SEL_SDP3,
+ };
+ static const u32 ts_sdp_en[IGB_N_SDP] = {
+ TS_SDP0_EN, TS_SDP1_EN, TS_SDP2_EN, TS_SDP3_EN,
+ };
+ static const u32 ts_sdp_sel_tt0[IGB_N_SDP] = {
+ TS_SDP0_SEL_TT0, TS_SDP1_SEL_TT0,
+ TS_SDP2_SEL_TT0, TS_SDP3_SEL_TT0,
+ };
+ static const u32 ts_sdp_sel_tt1[IGB_N_SDP] = {
+ TS_SDP0_SEL_TT1, TS_SDP1_SEL_TT1,
+ TS_SDP2_SEL_TT1, TS_SDP3_SEL_TT1,
+ };
+ static const u32 ts_sdp_sel_fc0[IGB_N_SDP] = {
+ TS_SDP0_SEL_FC0, TS_SDP1_SEL_FC0,
+ TS_SDP2_SEL_FC0, TS_SDP3_SEL_FC0,
+ };
+ static const u32 ts_sdp_sel_fc1[IGB_N_SDP] = {
+ TS_SDP0_SEL_FC1, TS_SDP1_SEL_FC1,
+ TS_SDP2_SEL_FC1, TS_SDP3_SEL_FC1,
+ };
+ static const u32 ts_sdp_sel_clr[IGB_N_SDP] = {
+ TS_SDP0_SEL_FC1, TS_SDP1_SEL_FC1,
+ TS_SDP2_SEL_FC1, TS_SDP3_SEL_FC1,
+ };
+ struct e1000_hw *hw = &igb->hw;
+ u32 ctrl, ctrl_ext, tssdp = 0;
+
+ ctrl = E1000_READ_REG(hw, E1000_CTRL);
+ ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
+ tssdp = E1000_READ_REG(hw, E1000_TSSDP);
+
+ igb_pin_direction(pin, 0, &ctrl, &ctrl_ext);
+
+ /* Make sure this pin is not enabled as an input. */
+ if ((tssdp & AUX0_SEL_SDP3) == aux0_sel_sdp[pin])
+ tssdp &= ~AUX0_TS_SDP_EN;
+
+ if ((tssdp & AUX1_SEL_SDP3) == aux1_sel_sdp[pin])
+ tssdp &= ~AUX1_TS_SDP_EN;
+
+ tssdp &= ~ts_sdp_sel_clr[pin];
+ if (freq)
+ tssdp |= (chan == 1) ? ts_sdp_sel_fc1[pin] : ts_sdp_sel_fc0[pin];
+ else
+ tssdp |= (chan == 1) ? ts_sdp_sel_tt1[pin] : ts_sdp_sel_tt0[pin];
+ tssdp |= ts_sdp_en[pin];
+
+ E1000_WRITE_REG(hw, E1000_TSSDP, tssdp);
+ E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
+ E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
+}
+#endif /* HAVE_PTP_1588_CLOCK_PINS */
+
+static int igb_ptp_feature_enable_i210(struct ptp_clock_info *ptp,
+ struct ptp_clock_request *rq, int on)
+{
+ struct igb_adapter *igb =
+ container_of(ptp, struct igb_adapter, ptp_caps);
+ struct e1000_hw *hw = &igb->hw;
+ unsigned long flags;
+ u32 tsim;
+#ifdef HAVE_PTP_1588_CLOCK_PINS
+ u32 tsauxc, tsauxc_mask, tsim_mask, trgttiml, trgttimh, freqout;
+ struct timespec64 ts;
+ int use_freq = 0, pin = -1;
+ s64 ns;
+#endif /* HAVE_PTP_1588_CLOCK_PINS */
+
+ switch (rq->type) {
+#ifdef HAVE_PTP_1588_CLOCK_PINS
+ case PTP_CLK_REQ_EXTTS:
+ if (on) {
+ pin = ptp_find_pin(igb->ptp_clock, PTP_PF_EXTTS,
+ rq->extts.index);
+ if (pin < 0)
+ return -EBUSY;
+ }
+ if (rq->extts.index == 1) {
+ tsauxc_mask = TSAUXC_EN_TS1;
+ tsim_mask = TSINTR_AUTT1;
+ } else {
+ tsauxc_mask = TSAUXC_EN_TS0;
+ tsim_mask = TSINTR_AUTT0;
+ }
+ spin_lock_irqsave(&igb->tmreg_lock, flags);
+ tsauxc = E1000_READ_REG(hw, E1000_TSAUXC);
+ tsim = E1000_READ_REG(hw, E1000_TSIM);
+ if (on) {
+ igb_pin_extts(igb, rq->extts.index, pin);
+ tsauxc |= tsauxc_mask;
+ tsim |= tsim_mask;
+ } else {
+ tsauxc &= ~tsauxc_mask;
+ tsim &= ~tsim_mask;
+ }
+ E1000_WRITE_REG(hw, E1000_TSAUXC, tsauxc);
+ E1000_WRITE_REG(hw, E1000_TSIM, tsim);
+ spin_unlock_irqrestore(&igb->tmreg_lock, flags);
+ return 0;
+
+ case PTP_CLK_REQ_PEROUT:
+ if (on) {
+ pin = ptp_find_pin(igb->ptp_clock, PTP_PF_PEROUT,
+ rq->perout.index);
+ if (pin < 0)
+ return -EBUSY;
+ }
+ ts.tv_sec = rq->perout.period.sec;
+ ts.tv_nsec = rq->perout.period.nsec;
+ ns = timespec64_to_ns(&ts);
+ ns = ns >> 1;
+ if (on && ((ns <= 70000000LL) || (ns == 125000000LL) ||
+ (ns == 250000000LL) || (ns == 500000000LL))) {
+ if (ns < 8LL)
+ return -EINVAL;
+ use_freq = 1;
+ }
+ ts = ns_to_timespec64(ns);
+ if (rq->perout.index == 1) {
+ if (use_freq) {
+ tsauxc_mask = TSAUXC_EN_CLK1 | TSAUXC_ST1;
+ tsim_mask = 0;
+ } else {
+ tsauxc_mask = TSAUXC_EN_TT1;
+ tsim_mask = TSINTR_TT1;
+ }
+ trgttiml = E1000_TRGTTIML1;
+ trgttimh = E1000_TRGTTIMH1;
+ freqout = E1000_FREQOUT1;
+ } else {
+ if (use_freq) {
+ tsauxc_mask = TSAUXC_EN_CLK0 | TSAUXC_ST0;
+ tsim_mask = 0;
+ } else {
+ tsauxc_mask = TSAUXC_EN_TT0;
+ tsim_mask = TSINTR_TT0;
+ }
+ trgttiml = E1000_TRGTTIML0;
+ trgttimh = E1000_TRGTTIMH0;
+ freqout = E1000_FREQOUT0;
+ }
+ spin_lock_irqsave(&igb->tmreg_lock, flags);
+ tsauxc = E1000_READ_REG(hw, E1000_TSAUXC);
+ tsim = E1000_READ_REG(hw, E1000_TSIM);
+ if (rq->perout.index == 1) {
+ tsauxc &= ~(TSAUXC_EN_TT1 | TSAUXC_EN_CLK1 | TSAUXC_ST1);
+ tsim &= ~TSINTR_TT1;
+ } else {
+ tsauxc &= ~(TSAUXC_EN_TT0 | TSAUXC_EN_CLK0 | TSAUXC_ST0);
+ tsim &= ~TSINTR_TT0;
+ }
+ if (on) {
+ int i = rq->perout.index;
+ igb_pin_perout(igb, i, pin, use_freq);
+ igb->perout[i].start.tv_sec = rq->perout.start.sec;
+ igb->perout[i].start.tv_nsec = rq->perout.start.nsec;
+ igb->perout[i].period.tv_sec = ts.tv_sec;
+ igb->perout[i].period.tv_nsec = ts.tv_nsec;
+ E1000_WRITE_REG(hw, trgttimh, rq->perout.start.sec);
+ E1000_WRITE_REG(hw, trgttiml, rq->perout.start.nsec);
+ if (use_freq)
+ E1000_WRITE_REG(hw, freqout, ns);
+ tsauxc |= tsauxc_mask;
+ tsim |= tsim_mask;
+ }
+ E1000_WRITE_REG(hw, E1000_TSAUXC, tsauxc);
+ E1000_WRITE_REG(hw, E1000_TSIM, tsim);
+ spin_unlock_irqrestore(&igb->tmreg_lock, flags);
+ return 0;
+#endif /* HAVE_PTP_1588_CLOCK_PINS */
+
+ case PTP_CLK_REQ_PPS:
+ spin_lock_irqsave(&igb->tmreg_lock, flags);
+ tsim = E1000_READ_REG(hw, E1000_TSIM);
+ if (on)
+ tsim |= TSINTR_SYS_WRAP;
+ else
+ tsim &= ~TSINTR_SYS_WRAP;
+ E1000_WRITE_REG(hw, E1000_TSIM, tsim);
+ spin_unlock_irqrestore(&igb->tmreg_lock, flags);
+ return 0;
+
+#ifndef HAVE_PTP_1588_CLOCK_PINS
+ default:
+ break;
+#endif /* HAVE_PTP_1588_CLOCK_PINS */
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static int igb_ptp_feature_enable(struct ptp_clock_info *ptp,
+ struct ptp_clock_request *rq, int on)
{
return -EOPNOTSUPP;
}
+#ifdef HAVE_PTP_1588_CLOCK_PINS
+static int igb_ptp_verify_pin(struct ptp_clock_info *ptp, unsigned int pin,
+ enum ptp_pin_function func, unsigned int chan)
+{
+ switch (func) {
+ case PTP_PF_NONE:
+ case PTP_PF_EXTTS:
+ case PTP_PF_PEROUT:
+ break;
+ case PTP_PF_PHYSYNC:
+ return -1;
+ }
+ return 0;
+}
+#endif /* HAVE_PTP_1588_CLOCK_PINS */
+
/**
* igb_ptp_tx_work
* @work: pointer to work struct
@@ -873,6 +1131,9 @@ void igb_ptp_init(struct igb_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
struct net_device *netdev = adapter->netdev;
+#ifdef HAVE_PTP_1588_CLOCK_PINS
+ int i;
+#endif /* HAVE_PTP_1588_CLOCK_PINS */
switch (hw->mac.type) {
case e1000_82576:
@@ -890,7 +1151,7 @@ void igb_ptp_init(struct igb_adapter *adapter)
adapter->ptp_caps.gettime = igb_ptp_gettime_82576;
adapter->ptp_caps.settime = igb_ptp_settime_82576;
#endif
- adapter->ptp_caps.enable = igb_ptp_enable;
+ adapter->ptp_caps.enable = igb_ptp_feature_enable;
adapter->cc.read = igb_ptp_read_82576;
adapter->cc.mask = CLOCKSOURCE_MASK(64);
adapter->cc.mult = 1;
@@ -916,7 +1177,7 @@ void igb_ptp_init(struct igb_adapter *adapter)
adapter->ptp_caps.gettime = igb_ptp_gettime_82576;
adapter->ptp_caps.settime = igb_ptp_settime_82576;
#endif
- adapter->ptp_caps.enable = igb_ptp_enable;
+ adapter->ptp_caps.enable = igb_ptp_feature_enable;
adapter->cc.read = igb_ptp_read_82580;
adapter->cc.mask = CLOCKSOURCE_MASK(IGB_NBITS_82580);
adapter->cc.mult = 1;
@@ -926,11 +1187,27 @@ void igb_ptp_init(struct igb_adapter *adapter)
break;
case e1000_i210:
case e1000_i211:
+#ifdef HAVE_PTP_1588_CLOCK_PINS
+ for (i = 0; i < IGB_N_SDP; i++) {
+ struct ptp_pin_desc *ppd = &adapter->sdp_config[i];
+
+ snprintf(ppd->name, sizeof(ppd->name), "SDP%d", i);
+ ppd->index = i;
+ ppd->func = PTP_PF_NONE;
+ }
+#endif /* HAVE_PTP_1588_CLOCK_PINS */
snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr);
adapter->ptp_caps.owner = THIS_MODULE;
adapter->ptp_caps.max_adj = 62499999;
- adapter->ptp_caps.n_ext_ts = 0;
- adapter->ptp_caps.pps = 0;
+ adapter->ptp_caps.n_ext_ts = IGB_N_EXTTS;
+ adapter->ptp_caps.n_per_out = IGB_N_PEROUT;
+#ifdef HAVE_PTP_1588_CLOCK_PINS
+ adapter->ptp_caps.n_pins = IGB_N_SDP;
+#endif /* HAVE_PTP_1588_CLOCK_PINS */
+ adapter->ptp_caps.pps = 1;
+#ifdef HAVE_PTP_1588_CLOCK_PINS
+ adapter->ptp_caps.pin_config = adapter->sdp_config;
+#endif /* HAVE_PTP_1588_CLOCK_PINS */
adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82580;
adapter->ptp_caps.adjtime = igb_ptp_adjtime_i210;
#ifdef HAVE_PTP_CLOCK_INFO_GETTIME64
@@ -940,7 +1217,10 @@ void igb_ptp_init(struct igb_adapter *adapter)
adapter->ptp_caps.gettime = igb_ptp_gettime_i210;
adapter->ptp_caps.settime = igb_ptp_settime_i210;
#endif
- adapter->ptp_caps.enable = igb_ptp_enable;
+ adapter->ptp_caps.enable = igb_ptp_feature_enable_i210;
+#ifdef HAVE_PTP_1588_CLOCK_PINS
+ adapter->ptp_caps.verify = igb_ptp_verify_pin;
+#endif /* HAVE_PTP_1588_CLOCK_PINS */
/* Enable the timer functions by clearing bit 31. */
E1000_WRITE_REG(hw, E1000_TSAUXC, 0x0);
break;
@@ -972,7 +1252,7 @@ void igb_ptp_init(struct igb_adapter *adapter)
/* Initialize the time sync interrupts for devices that support it. */
if (hw->mac.type >= e1000_82580) {
- E1000_WRITE_REG(hw, E1000_TSIM, E1000_TSIM_TXTS);
+ E1000_WRITE_REG(hw, E1000_TSIM, TSYNC_INTERRUPTS);
E1000_WRITE_REG(hw, E1000_IMS, E1000_IMS_TS);
}
@@ -1038,6 +1318,7 @@ void igb_ptp_stop(struct igb_adapter *adapter)
void igb_ptp_reset(struct igb_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
+ unsigned long flags;
if (!(adapter->flags & IGB_FLAG_PTP))
return;
@@ -1045,6 +1326,8 @@ void igb_ptp_reset(struct igb_adapter *adapter)
/* reset the tstamp_config */
igb_ptp_set_timestamp_mode(adapter, &adapter->tstamp_config);
+ spin_lock_irqsave(&adapter->tmreg_lock, flags);
+
switch (adapter->hw.mac.type) {
case e1000_82576:
/* Dial the nominal frequency. */
@@ -1056,24 +1339,26 @@ void igb_ptp_reset(struct igb_adapter *adapter)
case e1000_i354:
case e1000_i210:
case e1000_i211:
- /* Enable the timer functions and interrupts. */
E1000_WRITE_REG(hw, E1000_TSAUXC, 0x0);
- E1000_WRITE_REG(hw, E1000_TSIM, E1000_TSIM_TXTS);
+ E1000_WRITE_REG(hw, E1000_TSSDP, 0x0);
+ E1000_WRITE_REG(hw, E1000_TSIM, TSYNC_INTERRUPTS);
E1000_WRITE_REG(hw, E1000_IMS, E1000_IMS_TS);
break;
default:
/* No work to do. */
- return;
+ goto out;
}
/* Re-initialize the timer. */
if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211)) {
struct timespec64 ts64 = ktime_to_timespec64(ktime_get_real());
- igb_ptp_settime64_i210(&adapter->ptp_caps, &ts64);
+ igb_ptp_write_i210(adapter, &ts64);
} else {
timecounter_init(&adapter->tc, &adapter->cc,
ktime_to_ns(ktime_get_real()));
}
+out:
+ spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
}
#endif /* HAVE_PTP_1588_CLOCK */
diff --git a/lib/avtp_pipeline/LICENSE b/lib/avtp_pipeline/LICENSE
index 71e4e44e..bce20a35 100644
--- a/lib/avtp_pipeline/LICENSE
+++ b/lib/avtp_pipeline/LICENSE
@@ -1,16 +1,17 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
+
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -21,10 +22,10 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
diff --git a/lib/avtp_pipeline/README.md b/lib/avtp_pipeline/README.md
index 315f8825..23e6e525 100644
--- a/lib/avtp_pipeline/README.md
+++ b/lib/avtp_pipeline/README.md
@@ -1,23 +1,22 @@
-# STC AVTP Pipeline Contribution Notes
+# STC/Harman AVTP Pipeline Contribution Notes
## General Status
- Consider the AVTP Pipeline a work in progress.
-- Integrated with OpenAVB:
+- Integrated with OpenAvnu:
- gPTP
+ - MAAP
- MSRP
- igb direct for packet TX.
- igb credit based shaper
- build system
-- Not yet integreated with OpenAVB:
- - MAAP
- Credit-based shaper algorithm is not used for individual streams.
- Testing of various mappings and benchmarking has been performed. Look at the end of this file for benchmark results.
- Documentation and doc generation has not been fully updated.
-## Building Current OpenAVB
+## Building Current OpenAvnu
### Tool chain and libraries
- Ubuntu 14.04
-- Install dependencies for OpenAVB ($ sudo apt-get install ...)
+- Install dependencies for OpenAvnu ($ sudo apt-get install ...)
- $ sudo apt-get install build-essential
- $ sudo apt-get install libpcap-dev
- $ sudo apt-get install libpci-dev
@@ -36,21 +35,30 @@
- Building from the repo root
- $ ARCH=I210 make all
-### Building just AVTP pipeline.
+### Building just AVTP pipeline
- $ make avtp_pipeline
Binaries will be installed in lib/avtp_pipeline/build/bin.
-### Building AVTP pipeline without SRP.
+### Building AVTP pipeline without SRP or MAAP support
- $ AVB_FEATURE_ENDPOINT=0 make avtp_pipeline
Make sure to call `make avtp_pipeline_clean` before.
-
### Building AVTP pipeline documentation
- $ make avtp_pipeline_doc
-## Running OpenAVB daemons
+### Building just AVTP AVDECC support
+- $ make avtp_avdecc
+
+Binaries will be installed in lib/avtp_pipeline/build_avdecc/bin.
+
+The openavb_avdecc binary needs to be run in addition to the AVTP pipeline binary (openavb_harness or openavb_host) for AVDECC to be supported.
+
+### Building AVTP AVDECC documentation
+- $ make avtp_avdecc_doc
+
+## Running OpenAvnu daemons
- Helper scripts in the repo root.
- `$ sudo ./run_igb.sh eth1`
- Load the igb driver. Supply the interface name (ethx) as parameter.
@@ -58,16 +66,18 @@ Make sure to call `make avtp_pipeline_clean` before.
- Start gptp daemon. Supply the interface name (ethx) as parameter.
- `$ sudo ./run_srp.sh eth1`
- Start msrp daemon. Supply the interface name (ethx) as parameter.
+- `$ sudo ./run_maap.sh eth1`
+ - Start maap daemon. Supply the interface name (ethx) as parameter.
-## Running OpenAVB simple talker example
+## Running OpenAvnu simple talker example
- `$ sudo ./run_simple_talker.sh eth1`
- - Run the current OpenAVB simple talker example. Supply the interface name (ethx) as parameter.
+ - Run the current OpenAvnu simple talker example. Supply the interface name (ethx) as parameter.
-## Running STC Echo Talker
+## Running OpenAvnu Echo Talker
- `$ sudo ./run_echo_talker.sh eth1`
- Run the AVTP Echo talker test stream. Supply the interface name (ethx) as parameter.
-## Running STC Echo Listener
+## Running OpenAvnu Echo Listener
- `$ sudo ./run_echo_listener.sh eth1`
- Run the AVTP Echo talker test stream. Supply the interface name (ethx) as parameter.
diff --git a/lib/avtp_pipeline/acmp/CMakeLists.txt b/lib/avtp_pipeline/acmp/CMakeLists.txt
new file mode 100644
index 00000000..41d67923
--- /dev/null
+++ b/lib/avtp_pipeline/acmp/CMakeLists.txt
@@ -0,0 +1,9 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/acmp/openavb_acmp.c
+ ${AVB_SRC_DIR}/acmp/openavb_acmp_message.c
+ ${AVB_SRC_DIR}/acmp/openavb_acmp_sm_listener.c
+ ${AVB_SRC_DIR}/acmp/openavb_acmp_sm_talker.c
+ ${AVB_SRC_DIR}/acmp/openavb_acmp_sm_controller.c
+ PARENT_SCOPE
+)
+
diff --git a/lib/avtp_pipeline/acmp/openavb_acmp.c b/lib/avtp_pipeline/acmp/openavb_acmp.c
new file mode 100644
index 00000000..9324c60d
--- /dev/null
+++ b/lib/avtp_pipeline/acmp/openavb_acmp.c
@@ -0,0 +1,147 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : ACMP - AVDECC Connection Management Protocol
+ * MODULE SUMMARY : Implements the 1722.1 (AVDECC) connection management protocol
+ ******************************************************************
+ */
+#include "openavb_platform.h"
+
+#include <signal.h>
+
+#define AVB_LOG_COMPONENT "ACMP"
+#include "openavb_log.h"
+
+#include "openavb_aem.h"
+#include "openavb_acmp.h"
+#include "openavb_acmp_sm_listener.h"
+#include "openavb_acmp_sm_talker.h"
+#include "openavb_acmp_sm_controller.h"
+#include "openavb_acmp_message.h"
+
+extern openavb_avdecc_cfg_t gAvdeccCfg;
+
+openavb_acmp_sm_global_vars_t openavbAcmpSMGlobalVars;
+
+MUTEX_HANDLE(openavbAcmpMutex);
+#define ACMP_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAcmpMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define ACMP_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAcmpMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+static bool bListenerStarted = FALSE;
+static bool bTalkerStarted = FALSE;
+
+openavbRC openavbAcmpStart()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ openavb_avdecc_entity_model_t *pAem = openavbAemGetModel();
+ if (!pAem) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_ENTITY_MODEL_MISSING), AVB_TRACE_ACMP);
+ }
+
+ {
+ MUTEX_ATTR_HANDLE(mta);
+ MUTEX_ATTR_INIT(mta);
+ MUTEX_ATTR_SET_TYPE(mta, MUTEX_ATTR_TYPE_DEFAULT);
+ MUTEX_ATTR_SET_NAME(mta, "openavbAcmpMutex");
+ MUTEX_CREATE_ERR();
+ MUTEX_CREATE(openavbAcmpMutex, mta);
+ MUTEX_LOG_ERR("Could not create/initialize 'openavbAcmpMutex' mutex");
+ }
+
+ ACMP_LOCK();
+ {
+ // Populate global ACMP vars
+ openavb_acmp_control_header_t *pHeader = &openavbAcmpSMGlobalVars.controlHeader;
+
+ pHeader->cd = 1;
+ pHeader->subtype = OPENAVB_ACMP_AVTP_SUBTYPE;
+ pHeader->sv = 0;
+ pHeader->version = 0;
+ //pHeader->message_type = 0; // Set later depending on message type
+ //pHeader->status = 0; // Set later depending on message
+ pHeader->control_data_length = 44;
+ //pHeader->stream_id; // Set later depending on stream
+ }
+
+ {
+ memcpy(openavbAcmpSMGlobalVars.my_id, pAem->pDescriptorEntity->entity_id, sizeof(openavbAcmpSMGlobalVars.my_id));
+ }
+ ACMP_UNLOCK();
+
+ openavbRC rc = openavbAcmpMessageHandlerStart();
+ if (IS_OPENAVB_FAILURE(rc)) {
+ openavbAcmpStop();
+ AVB_RC_TRACE_RET(rc, AVB_TRACE_ACMP);
+ }
+
+ if (gAvdeccCfg.bListener) {
+ if (!openavbAcmpSMListenerStart()) {
+ AVB_RC_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_GENERIC), AVB_TRACE_ACMP);
+ }
+ bListenerStarted = TRUE;
+ }
+
+ if (gAvdeccCfg.bTalker) {
+ if (!openavbAcmpSMTalkerStart()) {
+ AVB_RC_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_GENERIC), AVB_TRACE_ACMP);
+ }
+ bTalkerStarted = TRUE;
+ }
+
+ if (!openavbAcmpSMControllerStart()) {
+ AVB_RC_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_GENERIC), AVB_TRACE_ACMP);
+ }
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_ACMP);
+}
+
+void openavbAcmpStop()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ openavbAcmpSMControllerStop();
+
+ if (bTalkerStarted) {
+ openavbAcmpSMTalkerStop();
+ }
+
+ if (bListenerStarted) {
+ openavbAcmpSMListenerStop();
+ }
+
+ openavbAcmpMessageHandlerStop();
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
diff --git a/lib/avtp_pipeline/acmp/openavb_acmp.h b/lib/avtp_pipeline/acmp/openavb_acmp.h
new file mode 100644
index 00000000..0d124fe7
--- /dev/null
+++ b/lib/avtp_pipeline/acmp/openavb_acmp.h
@@ -0,0 +1,195 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : ACMP - AVDECC Connection Management Protocol
+ * MODULE SUMMARY : Interface for the 1722.1 (AVDECC) connection management protocol
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_ACMP_H
+#define OPENAVB_ACMP_H 1
+
+#include "openavb_tl.h"
+#include "openavb_array.h"
+#include "openavb_list.h"
+#include "openavb_avdecc.h"
+#include "openavb_acmp_pub.h"
+
+#define OPENAVB_ACMP_AVTP_SUBTYPE (0x7C)
+
+#define OPENAVB_ADP_MESSAGE_TYPE_ENTITY_AVAILABLE (0x00)
+
+// message_type field IEEE Std 1722.1-2013 clause 8.2.1.5
+#define OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND (0)
+#define OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE (1)
+#define OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND (2)
+#define OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_RESPONSE (3)
+#define OPENAVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_COMMAND (4)
+#define OPENAVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_RESPONSE (5)
+#define OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_RX_COMMAND (6)
+#define OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_RX_RESPONSE (7)
+#define OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_COMMAND (8)
+#define OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_RESPONSE (9)
+#define OPENAVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_COMMAND (10)
+#define OPENAVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_RESPONSE (11)
+#define OPENAVB_ACMP_MESSAGE_TYPE_GET_TX_CONNECTION_COMMAND (12)
+#define OPENAVB_ACMP_MESSAGE_TYPE_GET_TX_CONNECTION_RESPONSE (13)
+
+// status field field IEEE Std 1722.1-2013 clause 8.2.1.6
+#define OPENAVB_ACMP_STATUS_SUCCESS (0)
+#define OPENAVB_ACMP_STATUS_LISTENER_UNKNOWN_ID (1)
+#define OPENAVB_ACMP_STATUS_TALKER_UNKNOWN_ID (2)
+#define OPENAVB_ACMP_STATUS_TALKER_DEST_MAC_FAIL (3)
+#define OPENAVB_ACMP_STATUS_TALKER_NO_STREAM_INDEX (4)
+#define OPENAVB_ACMP_STATUS_TALKER_NO_BANDWIDTH (5)
+#define OPENAVB_ACMP_STATUS_TALKER_EXCLUSIVE (6)
+#define OPENAVB_ACMP_STATUS_LISTENER_TALKER_TIMEOUT (7)
+#define OPENAVB_ACMP_STATUS_LISTENER_EXCLUSIVE (8)
+#define OPENAVB_ACMP_STATUS_STATE_UNAVAILABLE (9)
+#define OPENAVB_ACMP_STATUS_NOT_CONNECTED (10)
+#define OPENAVB_ACMP_STATUS_NO_SUCH_CONNECTION (11)
+#define OPENAVB_ACMP_STATUS_COULD_NOT_SEND_MESSAGE (12)
+#define OPENAVB_ACMP_STATUS_TALKER_MISBEHAVING (13)
+#define OPENAVB_ACMP_STATUS_LISTENER_MISBEHAVING (14)
+#define OPENAVB_ACMP_STATUS_CONTROLLER_NOT_AUTHORIZED (16)
+#define OPENAVB_ACMP_STATUS_INCOMPATIBLE_REQUEST (17)
+#define OPENAVB_ACMP_STATUS_NOT_SUPPORTED (31)
+
+// flags field IEEE Std 1722.1-2013 clause 8.2.1.17
+#define OPENAVB_ACMP_FLAG_CLASS_B (0x0001)
+#define OPENAVB_ACMP_FLAG_FAST_CONNECT (0x0002)
+#define OPENAVB_ACMP_FLAG_SAVED_STATE (0x0004)
+#define OPENAVB_ACMP_FLAG_STREAMING_WAIT (0x0008)
+#define OPENAVB_ACMP_FLAG_SUPPORTS_ENCRYPTED (0x0010)
+#define OPENAVB_ACMP_FLAG_ENCRYPTED_PDU (0x0020)
+#define OPENAVB_ACMP_FLAG_TALKER_FAILED (0x0040)
+
+// ACMP command timeouts IEEE Std 1722.1-2013 Table 8.4
+#define OPENAVB_ACMP_COMMAND_TIMEOUT_CONNECT_TX_COMMAND (2000)
+#define OPENAVB_ACMP_COMMAND_TIMEOUT_DISCONNECT_TX_COMMAND (200)
+#define OPENAVB_ACMP_COMMAND_TIMEOUT_GET_TX_STATE_COMMAND (200)
+#define OPENAVB_ACMP_COMMAND_TIMEOUT_CONNECT_RX_COMMAND (4500)
+#define OPENAVB_ACMP_COMMAND_TIMEOUT_DISCONNECT_RX_COMMAND (500)
+#define OPENAVB_ACMP_COMMAND_TIMEOUT_GET_RX_STATE_COMMAND (200)
+#define OPENAVB_ACMP_COMMAND_TIMEOUT_GET_TX_CONNECTION_COMMAND (200)
+
+
+typedef struct {
+ U8 cd;
+ U8 subtype;
+ U8 sv;
+ U8 version;
+ U8 message_type; // Redefined from control data
+ U8 status;
+ U16 control_data_length;
+ U8 stream_id[8];
+} openavb_acmp_control_header_t;
+
+// ACMPCommandResponse type IEEE Std 1722.1-2013 clause 8.2.2.2.1
+typedef struct {
+ U8 message_type;
+ U8 status;
+ U8 stream_id[8];
+ U8 controller_entity_id[8];
+ U8 talker_entity_id[8];
+ U8 listener_entity_id[8];
+ U16 talker_unique_id;
+ U16 listener_unique_id;
+ U8 stream_dest_mac[6];
+ U16 connection_count;
+ U16 sequence_id;
+ U16 flags;
+ U16 stream_vlan_id;
+} openavb_acmp_ACMPCommandResponse_t;
+
+// ListenerStreamInfo type IEEE Std 1722.1-2013 clause 8.2.2.2.2
+typedef struct {
+ U8 talker_entity_id[8];
+ U16 talker_unique_id;
+ U8 connected; // Boolean
+ U8 stream_id[8];
+ U8 stream_dest_mac[6];
+ U8 controller_entity_id[8];
+ U16 flags;
+ U16 stream_vlan_id;
+} openavb_acmp_ListenerStreamInfo_t;
+
+// ListenerPair type IEEE Std 1722.1-2013 clause 8.2.2.2.3
+typedef struct {
+ U8 listener_entity_id[8];
+ U16 listener_unique_id;
+} openavb_acmp_ListenerPair_t;
+
+// TalkerStreamInfo type IEEE Std 1722.1-2013 clause 8.2.2.2.4
+typedef struct {
+ U8 stream_id[8];
+ U8 stream_dest_mac[6];
+ U16 connection_count;
+ openavb_list_t connected_listeners;
+ U16 stream_vlan_id;
+
+ // Extra information indicating a GET_TX_CONNECTION_RESPONSE command is needed.
+ openavb_acmp_ACMPCommandResponse_t *waiting_on_talker;
+} openavb_acmp_TalkerStreamInfo_t;
+
+// InflightCommand type IEEE Std 1722.1-2013 clause 8.2.2.2.5
+typedef struct {
+ struct timespec timer;
+ U8 retried;
+ openavb_acmp_ACMPCommandResponse_t command;
+ U16 original_sequence_id;
+} openavb_acmp_InflightCommand_t;
+
+// ACMPCommandParams type IEEE Std 1722.1-2013 clause 8.2.2.2.6
+typedef struct {
+ U8 message_type;
+ U8 talker_entity_id[8];
+ U8 listener_entity_id[8];
+ U16 talker_unique_id;
+ U16 listener_unique_id;
+ U16 connection_count;
+ U16 flags;
+ U16 stream_vlan_id;
+} openavb_acmp_ACMPCommandParams_t;
+
+// State machine global variables IEEE Std 1722.1-2013 clause 8.2.2.3
+typedef struct {
+ U8 my_id[8];
+ //openavb_acmp_ACMPCommandResponse_t rcvdCmdResp; // defined in spec but implemented such that the listener and talker state machines maintain their own.
+ openavb_acmp_control_header_t controlHeader;
+} openavb_acmp_sm_global_vars_t;
+
+openavbRC openavbAcmpStart(void);
+void openavbAcmpStop(void);
+
+#endif // OPENAVB_ACMP_H
diff --git a/lib/avtp_pipeline/acmp/openavb_acmp_message.c b/lib/avtp_pipeline/acmp/openavb_acmp_message.c
new file mode 100644
index 00000000..8969f9cd
--- /dev/null
+++ b/lib/avtp_pipeline/acmp/openavb_acmp_message.c
@@ -0,0 +1,424 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : ACMP - AVDECC Connection Management Protocol Message Handler
+ * MODULE SUMMARY : Implements the 1722.1 ACMP - AVDECC Connection Management Protocol message handlers
+ ******************************************************************
+ */
+
+#include "openavb_platform.h"
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#define AVB_LOG_COMPONENT "ACMP"
+#include "openavb_log.h"
+
+#include "openavb_debug.h"
+#include "openavb_rawsock.h"
+#include "openavb_avtp.h"
+#include "openavb_srp.h"
+#include "openavb_acmp.h"
+#include "openavb_acmp_sm_controller.h"
+#include "openavb_acmp_sm_listener.h"
+#include "openavb_acmp_sm_talker.h"
+
+#define INVALID_SOCKET (-1)
+
+// ACMP Multicast address
+#define ACMP_PROTOCOL_ADDR "91:E0:F0:01:00:00"
+
+// message length
+#define AVTP_HDR_LEN 12
+#define ACMP_DATA_LEN 44
+#define ACMP_FRAME_LEN (ETH_HDR_LEN_VLAN + AVTP_HDR_LEN + ACMP_DATA_LEN)
+
+// number of buffers
+#define ACMP_NUM_TX_BUFFERS 2
+#define ACMP_NUM_RX_BUFFERS 20
+
+// do cast from ether_addr to U8*
+#define ADDR_PTR(A) (U8*)(&((A)->ether_addr_octet))
+
+extern openavb_avdecc_cfg_t gAvdeccCfg;
+
+extern MUTEX_HANDLE(openavbAcmpMutex);
+#define ACMP_LOCK() MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAcmpMutex); MUTEX_LOG_ERR("Mutex lock failure");
+#define ACMP_UNLOCK() MUTEX_UNLOCK(openavbAcmpMutex);
+
+static void *rxSock = NULL;
+static void *txSock = NULL;
+static struct ether_addr intfAddr;
+static struct ether_addr acmpAddr;
+
+extern openavb_acmp_sm_global_vars_t openavbAcmpSMGlobalVars;
+
+THREAD_TYPE(openavbAcmpMessageRxThread);
+THREAD_DEFINITON(openavbAcmpMessageRxThread);
+
+static bool bRunning = FALSE;
+
+void openavbAcmpCloseSocket()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ if (rxSock) {
+ openavbRawsockClose(rxSock);
+ rxSock = NULL;
+ }
+ if (txSock) {
+ openavbRawsockClose(txSock);
+ txSock = NULL;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+bool openavbAcmpOpenSocket(const char* ifname, U16 vlanID, U8 vlanPCP)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ hdr_info_t hdr;
+
+ rxSock = openavbRawsockOpen(ifname, TRUE, FALSE, ETHERTYPE_AVTP, ACMP_FRAME_LEN, ACMP_NUM_RX_BUFFERS);
+ txSock = openavbRawsockOpen(ifname, FALSE, TRUE, ETHERTYPE_AVTP, ACMP_FRAME_LEN, ACMP_NUM_TX_BUFFERS);
+
+ if (txSock && rxSock
+ && openavbRawsockGetAddr(txSock, ADDR_PTR(&intfAddr))
+ && ether_aton_r(ACMP_PROTOCOL_ADDR, &acmpAddr)
+ && openavbRawsockRxMulticast(rxSock, TRUE, ADDR_PTR(&acmpAddr)))
+ {
+ if (!openavbRawsockRxAVTPSubtype(rxSock, OPENAVB_ACMP_AVTP_SUBTYPE | 0x80)) {
+ AVB_LOG_DEBUG("RX AVTP Subtype not supported");
+ }
+
+ memset(&hdr, 0, sizeof(hdr_info_t));
+ hdr.shost = ADDR_PTR(&intfAddr);
+ hdr.dhost = ADDR_PTR(&acmpAddr);
+ hdr.ethertype = ETHERTYPE_AVTP;
+ if (vlanID != 0 || vlanPCP != 0) {
+ hdr.vlan = TRUE;
+ hdr.vlan_pcp = vlanPCP;
+ hdr.vlan_vid = vlanID;
+ AVB_LOGF_DEBUG("VLAN pcp=%d vid=%d", hdr.vlan_pcp, hdr.vlan_vid);
+ }
+ if (!openavbRawsockTxSetHdr(txSock, &hdr)) {
+ AVB_LOG_ERROR("TX socket Header Failure");
+ openavbAcmpCloseSocket();
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return false;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return true;
+ }
+
+ AVB_LOG_ERROR("Invalid socket");
+ openavbAcmpCloseSocket();
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return false;
+}
+
+static void openavbAcmpMessageRxFrameParse(U8* payload, int payload_len, hdr_info_t *hdr)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ openavb_acmp_control_header_t acmpHeader;
+ openavb_acmp_ACMPCommandResponse_t acmpCommandResponse;
+
+#if 0
+ AVB_LOGF_DEBUG("openavbAcmpMessageRxFrameParse packet data (length %d):", payload_len);
+ AVB_LOG_BUFFER(AVB_LOG_LEVEL_DEBUG, payload, payload_len, 16);
+#endif
+
+ U8 *pSrc = payload;
+ {
+ openavb_acmp_control_header_t *pDst1 = &acmpHeader;
+ openavb_acmp_ACMPCommandResponse_t *pDst2 = &acmpCommandResponse;
+
+ memset(&acmpHeader, 0, sizeof(acmpHeader));
+ memset(&acmpCommandResponse, 0, sizeof(acmpCommandResponse));
+
+ // AVTP Control Header
+ BIT_B2DNTOHB(pDst1->cd, pSrc, 0x80, 7, 0);
+ BIT_B2DNTOHB(pDst1->subtype, pSrc, 0x7f, 0, 1);
+ BIT_B2DNTOHB(pDst1->sv, pSrc, 0x80, 7, 0);
+ BIT_B2DNTOHB(pDst1->version, pSrc, 0x70, 4, 0);
+ BIT_B2DNTOHB(pDst2->message_type, pSrc, 0x0f, 0, 1);
+ BIT_B2DNTOHB(pDst2->status, pSrc, 0xf800, 11, 0);
+ BIT_B2DNTOHS(pDst1->control_data_length, pSrc, 0x07ff, 0, 2);
+ OCT_B2DMEMCP(pDst2->stream_id, pSrc);
+
+ // ACMP PDU
+ OCT_B2DMEMCP(pDst2->controller_entity_id, pSrc);
+ OCT_B2DMEMCP(pDst2->talker_entity_id, pSrc);
+ OCT_B2DMEMCP(pDst2->listener_entity_id, pSrc);
+ OCT_B2DNTOHS(pDst2->talker_unique_id, pSrc);
+ OCT_B2DNTOHS(pDst2->listener_unique_id, pSrc);
+ OCT_B2DMEMCP(pDst2->stream_dest_mac, pSrc);
+ OCT_B2DNTOHS(pDst2->connection_count, pSrc);
+ OCT_B2DNTOHS(pDst2->sequence_id, pSrc);
+ OCT_B2DNTOHS(pDst2->flags, pSrc);
+ OCT_B2DNTOHS(pDst2->stream_vlan_id, pSrc);
+ }
+
+ // Update the state machine
+ switch (acmpCommandResponse.message_type) {
+ case OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND:
+ openavbAcmpSMTalkerSet_rcvdConnectTXCmd(&acmpCommandResponse);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE:
+ openavbAcmpSMListenerSet_rcvdConnectTXResp(&acmpCommandResponse);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND:
+ openavbAcmpSMTalkerSet_rcvdDisconnectTXCmd(&acmpCommandResponse);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_RESPONSE:
+ openavbAcmpSMListenerSet_rcvdDisconnectTXResp(&acmpCommandResponse);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_COMMAND:
+ openavbAcmpSMTalkerSet_rcvdGetTXState(&acmpCommandResponse);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_RESPONSE:
+ openavbAcmpSMControllerSet_rcvdResponse(&acmpCommandResponse);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_RX_COMMAND:
+ openavbAcmpSMListenerSet_rcvdConnectRXCmd(&acmpCommandResponse);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_RX_RESPONSE:
+ openavbAcmpSMControllerSet_rcvdResponse(&acmpCommandResponse);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_COMMAND:
+ openavbAcmpSMListenerSet_rcvdDisconnectRXCmd(&acmpCommandResponse);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_RESPONSE:
+ openavbAcmpSMControllerSet_rcvdResponse(&acmpCommandResponse);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_COMMAND:
+ openavbAcmpSMListenerSet_rcvdGetRXState(&acmpCommandResponse);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_RESPONSE:
+ openavbAcmpSMControllerSet_rcvdResponse(&acmpCommandResponse);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_GET_TX_CONNECTION_COMMAND:
+ openavbAcmpSMTalkerSet_rcvdGetTXConnectionCmd(&acmpCommandResponse);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_GET_TX_CONNECTION_RESPONSE:
+ openavbAcmpSMControllerSet_rcvdResponse(&acmpCommandResponse);
+ break;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+static void openavbAcmpMessageRxFrameReceive(U32 timeoutUsec)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ hdr_info_t hdrInfo;
+ unsigned int offset, len;
+ U8 *pBuf, *pFrame;
+
+ memset(&hdrInfo, 0, sizeof(hdr_info_t));
+
+ pBuf = (U8 *)openavbRawsockGetRxFrame(rxSock, timeoutUsec, &offset, &len);
+ if (pBuf) {
+ pFrame = pBuf + offset;
+
+ offset = openavbRawsockRxParseHdr(rxSock, pBuf, &hdrInfo);
+ {
+#ifndef UBUNTU
+ if (hdrInfo.ethertype == ETHERTYPE_8021Q) {
+ // Oh! Need to look past the VLAN tag
+ U16 vlan_bits = ntohs(*(U16 *)(pFrame + offset));
+ hdrInfo.vlan = TRUE;
+ hdrInfo.vlan_vid = vlan_bits & 0x0FFF;
+ hdrInfo.vlan_pcp = (vlan_bits >> 13) & 0x0007;
+ offset += 2;
+ hdrInfo.ethertype = ntohs(*(U16 *)(pFrame + offset));
+ offset += 2;
+ }
+#endif
+
+ // Make sure that this is an AVTP packet
+ // (Should always be AVTP if it's to our AVTP-specific multicast address)
+ if (hdrInfo.ethertype == ETHERTYPE_AVTP) {
+ // parse the PDU only for ACMP messages
+ if (*(pFrame + offset) == (0x80 | OPENAVB_ACMP_AVTP_SUBTYPE)) {
+ openavbAcmpMessageRxFrameParse(pFrame + offset, len - offset, &hdrInfo);
+ }
+ }
+ else {
+ AVB_LOG_WARNING("Received non-AVTP frame!");
+ AVB_LOGF_DEBUG("Unexpected packet data (length %d):", len);
+ AVB_LOG_BUFFER(AVB_LOG_LEVEL_DEBUG, pFrame, len, 16);
+ }
+ }
+
+ // Release the frame
+ openavbRawsockRelRxFrame(rxSock, pBuf);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpMessageTxFrame(U8 messageType, openavb_acmp_ACMPCommandResponse_t *pACMPCommandResponse, U8 status)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ U8 *pBuf;
+ U32 size;
+ unsigned int hdrlen = 0;
+
+ pBuf = openavbRawsockGetTxFrame(txSock, TRUE, &size);
+
+ if (!pBuf) {
+ AVB_LOG_ERROR("No TX buffer");
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return; // AVDECC_TODO - return error result
+ }
+
+ if (size < ACMP_FRAME_LEN) {
+ AVB_LOG_ERROR("TX buffer too small");
+ openavbRawsockRelTxFrame(txSock, pBuf);
+ pBuf = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return; // AVDECC_TODO - return error result
+ }
+
+ memset(pBuf, 0, ACMP_FRAME_LEN);
+ openavbRawsockTxFillHdr(txSock, pBuf, &hdrlen);
+
+ ACMP_LOCK();
+ U8 *pDst = pBuf + hdrlen;
+ {
+ openavb_acmp_control_header_t *pSrc1 = &openavbAcmpSMGlobalVars.controlHeader;
+ openavb_acmp_ACMPCommandResponse_t *pSrc2 = pACMPCommandResponse;
+
+ // AVTP Control Header
+ BIT_D2BHTONB(pDst, pSrc1->cd, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc1->subtype, 0, 1);
+ BIT_D2BHTONB(pDst, pSrc1->sv, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc1->version, 4, 0);
+ BIT_D2BHTONB(pDst, messageType, 0, 1);
+ BIT_D2BHTONS(pDst, status, 11, 0);
+ BIT_D2BHTONS(pDst, pSrc1->control_data_length, 0, 2);
+ OCT_D2BMEMCP(pDst, pSrc2->stream_id);
+
+ // ACMP PDU
+ OCT_D2BMEMCP(pDst, pSrc2->controller_entity_id);
+ OCT_D2BMEMCP(pDst, pSrc2->talker_entity_id);
+ OCT_D2BMEMCP(pDst, pSrc2->listener_entity_id);
+ OCT_D2BHTONS(pDst, pSrc2->talker_unique_id);
+ OCT_D2BHTONS(pDst, pSrc2->listener_unique_id);
+ OCT_D2BMEMCP(pDst, pSrc2->stream_dest_mac);
+ OCT_D2BHTONS(pDst, pSrc2->connection_count);
+ OCT_D2BHTONS(pDst, pSrc2->sequence_id);
+ OCT_D2BHTONS(pDst, pSrc2->flags);
+ OCT_D2BHTONS(pDst, pSrc2->stream_vlan_id);
+ }
+ ACMP_UNLOCK();
+
+#if 0
+ AVB_LOGF_DEBUG("openavbAcmpMessageTxFrame packet data (length %d):", hdrlen + AVTP_HDR_LEN + ACMP_DATA_LEN);
+ AVB_LOG_BUFFER(AVB_LOG_LEVEL_DEBUG, pBuf, hdrlen + AVTP_HDR_LEN + ACMP_DATA_LEN, 16);
+#endif
+
+ openavbRawsockTxFrameReady(txSock, pBuf, hdrlen + AVTP_HDR_LEN + ACMP_DATA_LEN, 0);
+ openavbRawsockSend(txSock);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void* openavbAcmpMessageRxThreadFn(void *pv)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ AVB_LOG_DEBUG("ACMP Thread Started");
+ while (bRunning) {
+ // Try to get and process an ACMP.
+ openavbAcmpMessageRxFrameReceive(MICROSECONDS_PER_SECOND);
+ }
+ AVB_LOG_DEBUG("ACMP Thread Done");
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return NULL;
+}
+
+openavbRC openavbAcmpMessageHandlerStart()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ bRunning = TRUE;
+
+ if (openavbAcmpOpenSocket((const char *)gAvdeccCfg.ifname, gAvdeccCfg.vlanID, gAvdeccCfg.vlanPCP)) {
+
+ // Start the RX thread
+ bool errResult;
+ THREAD_CREATE(openavbAcmpMessageRxThread, openavbAcmpMessageRxThread, NULL, openavbAcmpMessageRxThreadFn, NULL);
+ THREAD_CHECK_ERROR(openavbAcmpMessageRxThread, "Thread / task creation failed", errResult);
+ if (errResult) {
+ bRunning = FALSE;
+ openavbAcmpCloseSocket();
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_FAILURE, AVB_TRACE_ACMP);
+ }
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_ACMP);
+ }
+
+ bRunning = FALSE;
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_FAILURE, AVB_TRACE_ACMP);
+}
+
+void openavbAcmpMessageHandlerStop()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ if (bRunning) {
+ bRunning = FALSE;
+ THREAD_JOIN(openavbAcmpMessageRxThread, NULL);
+ openavbAcmpCloseSocket();
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+openavbRC openavbAcmpMessageSend(U8 messageType, openavb_acmp_ACMPCommandResponse_t *pACMPCommandResponse, U8 status)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ openavbAcmpMessageTxFrame(messageType, pACMPCommandResponse, status);
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_ACMP);
+}
+
diff --git a/lib/avtp_pipeline/acmp/openavb_acmp_message.h b/lib/avtp_pipeline/acmp/openavb_acmp_message.h
new file mode 100644
index 00000000..f54f7bfe
--- /dev/null
+++ b/lib/avtp_pipeline/acmp/openavb_acmp_message.h
@@ -0,0 +1,50 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : ACMP - AVDECC Connection Management Protocol Message Handler Interface
+ * MODULE SUMMARY : Interface for the 1722.1 ACMP - AVDECC Connection Management Protocol message handlers
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_ADP_MESSAGE_H
+#define OPENAVB_ADP_MESSAGE_H 1
+
+#include "openavb_avdecc.h"
+
+openavbRC openavbAcmpMessageHandlerStart(void);
+
+void openavbAcmpMessageHandlerStop(void);
+
+openavbRC openavbAcmpMessageSend(U8 messageType, openavb_acmp_ACMPCommandResponse_t *pACMPCommandResponse, U8 status);
+
+#endif // OPENAVB_ADP_MESSAGE_H
diff --git a/lib/avtp_pipeline/acmp/openavb_acmp_pub.h b/lib/avtp_pipeline/acmp/openavb_acmp_pub.h
new file mode 100644
index 00000000..82e6b3ed
--- /dev/null
+++ b/lib/avtp_pipeline/acmp/openavb_acmp_pub.h
@@ -0,0 +1,42 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : ACMP - AVDECC Connection Management Protocol Public Interface
+ * MODULE SUMMARY : Public interface for the 1722.1 ACMP - AVDECC Connection Management Protocol
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_ACMP_PUB_H
+#define OPENAVB_ACMP_PUB_H 1
+
+#endif // OPENAVB_ACMP_PUB_H
diff --git a/lib/avtp_pipeline/acmp/openavb_acmp_sm_controller.c b/lib/avtp_pipeline/acmp/openavb_acmp_sm_controller.c
new file mode 100644
index 00000000..e61522bb
--- /dev/null
+++ b/lib/avtp_pipeline/acmp/openavb_acmp_sm_controller.c
@@ -0,0 +1,435 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : ACMP - AVDECC Connection Management Protocol : Controller State Machine
+ * MODULE SUMMARY : Implements the ACMP - AVDECC Connection Management Protocol : Controller State Machine
+ * IEEE Std 1722.1-2013 clause 8.2.2.4
+ ******************************************************************
+ */
+
+#define AVB_LOG_COMPONENT "ACMP"
+#include "openavb_log.h"
+
+#include "openavb_debug.h"
+#include "openavb_time.h"
+#include "openavb_acmp_sm_controller.h"
+#include "openavb_acmp_message.h"
+#include "openavb_avdecc_pipeline_interaction_pub.h"
+
+typedef enum {
+ OPENAVB_ACMP_SM_CONTROLLER_STATE_WAITING,
+ OPENAVB_ACMP_SM_CONTROLLER_STATE_TIMEOUT,
+ OPENAVB_ACMP_SM_CONTROLLER_STATE_RESPONSE
+} openavb_acmp_sm_controller_state_t;
+
+extern openavb_acmp_sm_global_vars_t openavbAcmpSMGlobalVars;
+
+static openavb_acmp_ACMPCommandResponse_t rcvdCmdResp;
+static openavb_acmp_ACMPCommandResponse_t *pRcvdCmdResp = &rcvdCmdResp;
+static openavb_acmp_sm_controller_vars_t openavbAcmpSMControllerVars = {0};
+static bool bRunning = FALSE;
+
+extern MUTEX_HANDLE(openavbAcmpMutex);
+#define ACMP_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAcmpMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define ACMP_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAcmpMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+static MUTEX_HANDLE(openavbAcmpSMControllerMutex);
+#define ACMP_SM_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAcmpSMControllerMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define ACMP_SM_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAcmpSMControllerMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+SEM_T(openavbAcmpSMControllerSemaphore);
+THREAD_TYPE(openavbAcmpSmControllerThread);
+THREAD_DEFINITON(openavbAcmpSmControllerThread);
+
+
+static openavb_list_node_t openavbAcmpSMController_findInflightNodeFromCommand(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ openavb_list_node_t node = openavbListIterFirst(openavbAcmpSMControllerVars.inflight);
+ while (node) {
+ openavb_acmp_InflightCommand_t *pInFlightCommand = openavbListData(node);
+ if (pInFlightCommand) {
+ if (memcmp(pInFlightCommand->command.controller_entity_id, command->controller_entity_id, sizeof(pInFlightCommand->command.controller_entity_id)) == 0 &&
+ pInFlightCommand->command.sequence_id == command->sequence_id) {
+ break;
+ }
+ }
+ node = openavbListIterNext(openavbAcmpSMControllerVars.inflight);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return node;
+}
+
+
+void openavbAcmpSMController_txCommand(U8 messageType, openavb_acmp_ACMPCommandResponse_t *command, bool retry)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ openavb_list_node_t node = NULL;
+
+ openavbRC rc = openavbAcmpMessageSend(messageType, command, OPENAVB_ACMP_STATUS_SUCCESS);
+ if (IS_OPENAVB_SUCCESS(rc)) {
+ if (!retry) {
+ node = openavbListNew(openavbAcmpSMControllerVars.inflight, sizeof(openavb_acmp_InflightCommand_t));
+ if (node) {
+ openavb_acmp_InflightCommand_t *pInFlightCommand = openavbListData(node);
+ if (pInFlightCommand) {
+
+ memcpy(&pInFlightCommand->command, command, sizeof(pInFlightCommand->command));
+ pInFlightCommand->command.message_type = messageType;
+ pInFlightCommand->retried = FALSE;
+ pInFlightCommand->original_sequence_id = command->sequence_id; // AVDECC_TODO - is this correct?
+
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &pInFlightCommand->timer);
+ switch (messageType) {
+ case OPENAVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_RESPONSE:
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_GET_TX_STATE_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_RX_RESPONSE:
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_CONNECT_RX_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_RESPONSE:
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_DISCONNECT_RX_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_RESPONSE:
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_GET_RX_STATE_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_GET_TX_CONNECTION_RESPONSE:
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_GET_TX_CONNECTION_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ default:
+ AVB_LOGF_ERROR("Unsupported command %u in openavbAcmpSMController_txCommand", messageType);
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_CONNECT_RX_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ }
+ }
+ }
+ }
+ else {
+ // Retry case
+ node = openavbAcmpSMController_findInflightNodeFromCommand(command);
+ if (node) {
+ openavb_acmp_InflightCommand_t *pInFlightCommand = openavbListData(node);
+ if (pInFlightCommand) {
+ pInFlightCommand->retried = TRUE;
+
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &pInFlightCommand->timer);
+ switch (messageType) {
+ case OPENAVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_RESPONSE:
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_GET_TX_STATE_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_RX_RESPONSE:
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_CONNECT_RX_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_RESPONSE:
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_DISCONNECT_RX_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_RESPONSE:
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_GET_RX_STATE_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_GET_TX_CONNECTION_RESPONSE:
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_GET_TX_CONNECTION_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ default:
+ AVB_LOGF_ERROR("Unsupported command %u in openavbAcmpSMController_txCommand", messageType);
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_CONNECT_RX_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ }
+ }
+ }
+ }
+ }
+ else {
+ // Failed to send command
+ openavbAcmpMessageSend(messageType, command, OPENAVB_ACMP_STATUS_COULD_NOT_SEND_MESSAGE);
+ if (retry) {
+ node = openavbAcmpSMController_findInflightNodeFromCommand(command);
+ if (node) {
+ openavbListDelete(openavbAcmpSMControllerVars.inflight, node);
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMController_cancelTimeout(openavb_acmp_ACMPCommandResponse_t *commandResponse)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ // Nothing to do since the timer is reset during the wait state and the inFlight entry will have already been removed.
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMController_removeInflight(openavb_acmp_ACMPCommandResponse_t *commandResponse)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ openavb_list_node_t node = openavbAcmpSMController_findInflightNodeFromCommand(commandResponse);
+ if (node) {
+ openavbListDelete(openavbAcmpSMControllerVars.inflight, node);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMController_processResponse(openavb_acmp_ACMPCommandResponse_t *commandResponse)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ // AVDECC_TODO: Is there anything we need to do here, such as updating the saved state?
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMController_makeCommand(openavb_acmp_ACMPCommandParams_t *param)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ // AVDECC_TODO: Fill this in if implementing the doCommand support.
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMControllerStateMachine()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ openavb_acmp_InflightCommand_t *pInflightActive = NULL; // The inflight command for the current state
+ openavb_acmp_sm_controller_state_t state = OPENAVB_ACMP_SM_CONTROLLER_STATE_WAITING;
+
+ // Lock such that the mutex is held unless waiting for a semaphore. Synchronous processing of command responses.
+ ACMP_SM_LOCK();
+ while (bRunning) {
+ switch (state) {
+ case OPENAVB_ACMP_SM_CONTROLLER_STATE_WAITING:
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_CONTROLLER_STATE_WAITING");
+
+ openavbAcmpSMControllerVars.rcvdResponse = FALSE;
+
+ // Calculate timeout for inflight commands
+ // Start is a arbitrary large time out.
+ struct timespec timeout;
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &timeout);
+ timeout.tv_sec += 60; // At most will timeout after 60 seconds
+
+ // Look for soonest inflight command timeout
+ openavb_list_node_t node = openavbListIterFirst(openavbAcmpSMControllerVars.inflight);
+ while (node) {
+ openavb_acmp_InflightCommand_t *pInflight = openavbListData(node);
+ if ((openavbTimeTimespecCmp(&pInflight->timer, &timeout) < 0)) {
+ timeout.tv_sec = pInflight->timer.tv_sec;
+ timeout.tv_nsec = pInflight->timer.tv_nsec;
+ }
+ node = openavbListIterNext(openavbAcmpSMControllerVars.inflight);
+ }
+
+ ACMP_SM_UNLOCK();
+ U32 timeoutMSec = 0;
+ struct timespec now;
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &now);
+ timeoutMSec = openavbTimeUntilMSec(&now, &timeout);
+ SEM_ERR_T(err);
+ SEM_TIMEDWAIT(openavbAcmpSMControllerSemaphore, timeoutMSec, err);
+ ACMP_SM_LOCK();
+
+ if (!SEM_IS_ERR_NONE(err)) {
+ if (SEM_IS_ERR_TIMEOUT(err)) {
+ struct timespec now;
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &now);
+
+ // Look for a timed out inflight command
+ openavb_list_node_t node = openavbListIterFirst(openavbAcmpSMControllerVars.inflight);
+ while (node) {
+ openavb_acmp_InflightCommand_t *pInflight = openavbListData(node);
+ if ((openavbTimeTimespecCmp(&now, &pInflight->timer) >= 0)) {
+ // Found a timed out command
+ state = OPENAVB_ACMP_SM_CONTROLLER_STATE_TIMEOUT;
+ pInflightActive = pInflight;
+ break;
+ }
+ node = openavbListIterNext(openavbAcmpSMControllerVars.inflight);
+ }
+ }
+ }
+ else {
+ if (openavbAcmpSMControllerVars.doTerminate) {
+ bRunning = FALSE;
+ }
+ else if (openavbAcmpSMControllerVars.rcvdResponse &&
+ memcmp(pRcvdCmdResp->controller_entity_id, openavbAcmpSMGlobalVars.my_id, sizeof(openavbAcmpSMGlobalVars.my_id)) == 0) {
+ // Look for a corresponding inflight command
+ openavb_list_node_t node = openavbListIterFirst(openavbAcmpSMControllerVars.inflight);
+ while (node) {
+ openavb_acmp_InflightCommand_t *pInflight = openavbListData(node);
+ if (pRcvdCmdResp->sequence_id == pInflight->command.sequence_id &&
+ pRcvdCmdResp->message_type == pInflight->command.message_type + 1) {
+ // Found a corresponding command
+ state = OPENAVB_ACMP_SM_CONTROLLER_STATE_RESPONSE;
+ pInflightActive = pInflight;
+ break;
+ }
+ node = openavbListIterNext(openavbAcmpSMControllerVars.inflight);
+ }
+ }
+ break;
+
+ case OPENAVB_ACMP_SM_CONTROLLER_STATE_TIMEOUT:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_CONTROLLER_STATE_TIMEOUT");
+
+ if (pInflightActive) {
+ if (pInflightActive->retried) {
+ openavbAcmpSMController_removeInflight(&pInflightActive->command);
+ }
+ else {
+ openavbAcmpSMController_txCommand(pInflightActive->command.message_type, &pInflightActive->command, TRUE);
+ }
+ }
+ pInflightActive = NULL;
+ state = OPENAVB_ACMP_SM_CONTROLLER_STATE_WAITING;
+ }
+ break;
+
+ case OPENAVB_ACMP_SM_CONTROLLER_STATE_RESPONSE:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_CONTROLLER_STATE_RESPONSE");
+
+ if (pInflightActive) {
+ openavbAcmpSMController_cancelTimeout(pRcvdCmdResp);
+ openavbAcmpSMController_processResponse(pRcvdCmdResp);
+ openavbAcmpSMController_removeInflight(pRcvdCmdResp);
+ }
+ pInflightActive = NULL;
+ state = OPENAVB_ACMP_SM_CONTROLLER_STATE_WAITING;
+ }
+ break;
+ }
+ }
+ }
+ ACMP_SM_UNLOCK();
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void* openavbAcmpSMControllerThreadFn(void *pv)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ openavbAcmpSMControllerStateMachine();
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return NULL;
+}
+
+bool openavbAcmpSMControllerStart()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ openavbAcmpSMControllerVars.inflight = openavbListNewList();
+ if (!openavbAcmpSMControllerVars.inflight) {
+ AVB_LOG_ERROR("Unable to create inflight list. ACMP protocol not started.");
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return FALSE;
+ }
+
+ MUTEX_ATTR_HANDLE(mta);
+ MUTEX_ATTR_INIT(mta);
+ MUTEX_ATTR_SET_TYPE(mta, MUTEX_ATTR_TYPE_DEFAULT);
+ MUTEX_ATTR_SET_NAME(mta, "openavbAcmpSMControllerMutex");
+ MUTEX_CREATE_ERR();
+ MUTEX_CREATE(openavbAcmpSMControllerMutex, mta);
+ MUTEX_LOG_ERR("Could not create/initialize 'openavbAcmpSMControllerMutex' mutex");
+
+ SEM_ERR_T(err);
+ SEM_INIT(openavbAcmpSMControllerSemaphore, 1, err);
+ SEM_LOG_ERR(err);
+
+ // Start the State Machine
+ bool errResult;
+ bRunning = TRUE;
+ THREAD_CREATE(openavbAcmpSmControllerThread, openavbAcmpSmControllerThread, NULL, openavbAcmpSMControllerThreadFn, NULL);
+ THREAD_CHECK_ERROR(openavbAcmpSmControllerThread, "Thread / task creation failed", errResult);
+ if (errResult) {
+ bRunning = FALSE;
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return TRUE;
+}
+
+void openavbAcmpSMControllerStop()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ if (bRunning) {
+ openavbAcmpSMControllerSet_doTerminate(TRUE);
+
+ THREAD_JOIN(openavbAcmpSmControllerThread, NULL);
+ }
+
+ SEM_ERR_T(err);
+ SEM_DESTROY(openavbAcmpSMControllerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ openavbListDeleteList(openavbAcmpSMControllerVars.inflight);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMControllerSet_rcvdResponse(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ ACMP_SM_LOCK();
+
+ memcpy(pRcvdCmdResp, command, sizeof(*command));
+ openavbAcmpSMControllerVars.rcvdResponse = TRUE;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAcmpSMControllerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ ACMP_SM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMControllerSet_doTerminate(bool value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ openavbAcmpSMControllerVars.doTerminate = value;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAcmpSMControllerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
diff --git a/lib/avtp_pipeline/acmp/openavb_acmp_sm_controller.h b/lib/avtp_pipeline/acmp/openavb_acmp_sm_controller.h
new file mode 100644
index 00000000..15e0394f
--- /dev/null
+++ b/lib/avtp_pipeline/acmp/openavb_acmp_sm_controller.h
@@ -0,0 +1,67 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : ACMP - AVDECC Connection Management Protocol : Controller State Machine Interface
+ * MODULE SUMMARY : Interface for ACMP - AVDECC Connection Management Protocol : Controller State Machine
+ * IEEE Std 1722.1-2013 clause 8.2.2.4
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_ACMP_SM_CONTROLLER_H
+#define OPENAVB_ACMP_SM_CONTROLLER_H 1
+
+#include "openavb_acmp.h"
+
+// State machine vars IEEE Std 1722.1-2013 clause 8.2.2.4.1
+typedef struct {
+ openavb_list_t inflight;
+ bool rcvdResponse;
+
+ // Not part of spec
+ bool doTerminate;
+} openavb_acmp_sm_controller_vars_t;
+
+// State machine functions IEEE Std 1722.1-2013 clause 8.2.2.4.2
+void openavbAcmpSMController_txCommand(U8 messageType, openavb_acmp_ACMPCommandResponse_t *command, bool retry);
+void openavbAcmpSMController_cancelTimeout(openavb_acmp_ACMPCommandResponse_t *commandResponse);
+void openavbAcmpSMController_removeInflight(openavb_acmp_ACMPCommandResponse_t *commandResponse);
+void openavbAcmpSMController_processResponse(openavb_acmp_ACMPCommandResponse_t *commandResponse);
+void openavbAcmpSMController_makeCommand(openavb_acmp_ACMPCommandParams_t *param);
+
+bool openavbAcmpSMControllerStart(void);
+void openavbAcmpSMControllerStop(void);
+
+void openavbAcmpSMControllerSet_rcvdResponse(openavb_acmp_ACMPCommandResponse_t *command);
+void openavbAcmpSMControllerSet_doTerminate(bool value);
+
+#endif // OPENAVB_ACMP_SM_CONTROLLER_H
diff --git a/lib/avtp_pipeline/acmp/openavb_acmp_sm_listener.c b/lib/avtp_pipeline/acmp/openavb_acmp_sm_listener.c
new file mode 100644
index 00000000..515a557f
--- /dev/null
+++ b/lib/avtp_pipeline/acmp/openavb_acmp_sm_listener.c
@@ -0,0 +1,982 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : ACMP - AVDECC Connection Management Protocol : Listener State Machine
+ * MODULE SUMMARY : Implements the ACMP - AVDECC Connection Management Protocol : Listener State Machine
+ * IEEE Std 1722.1-2013 clause 8.2.2.5
+ ******************************************************************
+ */
+
+#include "openavb_platform.h"
+
+#include <errno.h>
+
+#define AVB_LOG_COMPONENT "ACMP"
+#include "openavb_log.h"
+
+#include "openavb_debug.h"
+#include "openavb_time.h"
+#include "openavb_aem.h"
+#include "openavb_acmp.h"
+#include "openavb_acmp_message.h"
+#include "openavb_acmp_sm_talker.h"
+#include "openavb_acmp_sm_listener.h"
+#include "openavb_avdecc_pipeline_interaction_pub.h"
+#include "openavb_time.h"
+
+typedef enum {
+ OPENAVB_ACMP_SM_LISTENER_STATE_WAITING,
+ OPENAVB_ACMP_SM_LISTENER_STATE_CONNECT_RX_COMMAND,
+ OPENAVB_ACMP_SM_LISTENER_STATE_CONNECT_TX_RESPONSE,
+ OPENAVB_ACMP_SM_LISTENER_STATE_GET_STATE,
+ OPENAVB_ACMP_SM_LISTENER_STATE_DISCONNECT_RX_COMMAND,
+ OPENAVB_ACMP_SM_LISTENER_STATE_DISCONNECT_TX_RESPONSE,
+ OPENAVB_ACMP_SM_LISTENER_STATE_CONNECT_TX_TIMEOUT,
+ OPENAVB_ACMP_SM_LISTENER_STATE_DISCONNECT_TX_TIMEOUT,
+} openavb_acmp_sm_listener_state_t;
+
+extern openavb_avdecc_cfg_t gAvdeccCfg;
+extern openavb_acmp_sm_global_vars_t openavbAcmpSMGlobalVars;
+
+static openavb_acmp_ACMPCommandResponse_t rcvdCmdResp;
+static openavb_acmp_ACMPCommandResponse_t *pRcvdCmdResp = &rcvdCmdResp;
+static openavb_acmp_sm_listener_vars_t openavbAcmpSMListenerVars = {0};
+static bool bRunning = FALSE;
+
+extern MUTEX_HANDLE(openavbAcmpMutex);
+#define ACMP_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAcmpMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define ACMP_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAcmpMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+static MUTEX_HANDLE(openavbAcmpSMListenerMutex);
+#define ACMP_SM_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAcmpSMListenerMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define ACMP_SM_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAcmpSMListenerMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+SEM_T(openavbAcmpSMListenerSemaphore);
+THREAD_TYPE(openavbAcmpSmListenerThread);
+THREAD_DEFINITON(openavbAcmpSmListenerThread);
+
+openavb_list_node_t openavbAcmpSMListener_findInflightNodeFromCommand(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ openavb_list_node_t node = NULL;
+
+ node = openavbListIterFirst(openavbAcmpSMListenerVars.inflight);
+ while (node) {
+ openavb_acmp_InflightCommand_t *pInFlightCommand = openavbListData(node);
+ if (pInFlightCommand) {
+ if (memcmp(pInFlightCommand->command.talker_entity_id, command->talker_entity_id, sizeof(pInFlightCommand->command.talker_entity_id)) == 0) {
+ if (pInFlightCommand->command.talker_unique_id == command->talker_unique_id ) {
+ if (pInFlightCommand->command.sequence_id == command->sequence_id) {
+ break;
+ }
+ }
+ }
+ }
+ node = openavbListIterNext(openavbAcmpSMListenerVars.inflight);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return node;
+}
+
+bool openavbAcmpSMListener_validListenerUnique(U16 listenerUniqueId)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ if (!openavbAemGetDescriptor(openavbAemGetConfigIdx(), OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, listenerUniqueId)) {
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return TRUE;
+}
+
+bool openavbAcmpSMListener_listenerIsConnected(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ bool bResult = FALSE;
+
+ // Returns TRUE if listener is connected to a stream source other than the one specified in the command.
+ openavb_acmp_ListenerStreamInfo_t *pListenerStreamInfo = openavbArrayDataIdx(openavbAcmpSMListenerVars.listenerStreamInfos, command->listener_unique_id);
+ if (pListenerStreamInfo) {
+ if (pListenerStreamInfo->connected) {
+ bResult = TRUE;
+ if (memcmp(pListenerStreamInfo->talker_entity_id, command->talker_entity_id, sizeof(command->talker_entity_id)) == 0) {
+ if (pListenerStreamInfo->talker_unique_id == command->talker_unique_id) {
+ bResult = FALSE;
+ }
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return bResult;
+}
+
+bool openavbAcmpSMListener_listenerIsConnectedTo(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ bool bResult = FALSE;
+
+ // Returns TRUE if listener is connected to the stream source specified in the command.
+ openavb_acmp_ListenerStreamInfo_t *pListenerStreamInfo = openavbArrayDataIdx(openavbAcmpSMListenerVars.listenerStreamInfos, command->listener_unique_id);
+ if (pListenerStreamInfo) {
+ if (pListenerStreamInfo->connected) {
+ if (memcmp(pListenerStreamInfo->talker_entity_id, command->talker_entity_id, sizeof(command->talker_entity_id)) == 0) {
+ if (pListenerStreamInfo->talker_unique_id == command->talker_unique_id) {
+ bResult = TRUE;
+ }
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return bResult;
+}
+
+void openavbAcmpSMListener_txCommand(U8 messageType, openavb_acmp_ACMPCommandResponse_t *command, bool retry)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ openavb_list_node_t node = NULL;
+
+ openavbRC rc = openavbAcmpMessageSend(messageType, command, OPENAVB_ACMP_STATUS_SUCCESS);
+ if (IS_OPENAVB_SUCCESS(rc)) {
+ if (!retry) {
+ node = openavbListNew(openavbAcmpSMListenerVars.inflight, sizeof(openavb_acmp_InflightCommand_t));
+ if (node) {
+ openavb_acmp_InflightCommand_t *pInFlightCommand = openavbListData(node);
+ if (pInFlightCommand) {
+
+ memcpy(&pInFlightCommand->command, command, sizeof(pInFlightCommand->command));
+ pInFlightCommand->command.message_type = messageType;
+ pInFlightCommand->retried = FALSE;
+ pInFlightCommand->original_sequence_id = command->sequence_id; // AVDECC_TODO - is this correct?
+
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &pInFlightCommand->timer);
+ switch (messageType) {
+ case OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND:
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_CONNECT_TX_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND:
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_DISCONNECT_TX_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ default:
+ AVB_LOGF_ERROR("Unsupported command %u in openavbAcmpSMListener_txCommand", messageType);
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_CONNECT_RX_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ }
+ }
+ }
+ }
+ else {
+ // Retry case
+ node = openavbAcmpSMListener_findInflightNodeFromCommand(command);
+ if (node) {
+ openavb_acmp_InflightCommand_t *pInFlightCommand = openavbListData(node);
+ if (pInFlightCommand) {
+ pInFlightCommand->retried = TRUE;
+
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &pInFlightCommand->timer);
+ switch (messageType) {
+ case OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND:
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_CONNECT_TX_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ case OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND:
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_DISCONNECT_TX_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ default:
+ AVB_LOGF_ERROR("Unsupported command %u in openavbAcmpSMListener_txCommand", messageType);
+ openavbTimeTimespecAddUsec(&pInFlightCommand->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_CONNECT_RX_COMMAND * MICROSECONDS_PER_MSEC);
+ break;
+ }
+ }
+ }
+ }
+ }
+ else {
+ // Failed to send command
+ openavbAcmpSMListener_txResponse(messageType + 1, command, OPENAVB_ACMP_STATUS_COULD_NOT_SEND_MESSAGE);
+ if (retry) {
+ node = openavbAcmpSMListener_findInflightNodeFromCommand(command);
+ if (node) {
+ openavbListDelete(openavbAcmpSMListenerVars.inflight, node);
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMListener_txResponse(U8 messageType, openavb_acmp_ACMPCommandResponse_t *response, U8 error)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ openavbAcmpMessageSend(messageType, response, error);
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+U8 openavbAcmpSMListener_connectListener(openavb_acmp_ACMPCommandResponse_t *response)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ U8 retStatus;
+
+ // AVDECC_TODO: What do we do if the Listener is already connected?
+
+ openavb_acmp_ListenerStreamInfo_t *pListenerStreamInfo = openavbArrayDataIdx(openavbAcmpSMListenerVars.listenerStreamInfos, response->listener_unique_id);
+ if (pListenerStreamInfo) {
+ memcpy(pListenerStreamInfo->stream_id, response->stream_id, sizeof(pListenerStreamInfo->stream_id));
+ memcpy(pListenerStreamInfo->controller_entity_id, response->controller_entity_id, sizeof(pListenerStreamInfo->controller_entity_id));
+ memcpy(pListenerStreamInfo->talker_entity_id, response->talker_entity_id, sizeof(pListenerStreamInfo->talker_entity_id));
+ pListenerStreamInfo->talker_unique_id = response->talker_unique_id;
+ memcpy(pListenerStreamInfo->stream_dest_mac, response->stream_dest_mac, sizeof(pListenerStreamInfo->stream_dest_mac));
+ pListenerStreamInfo->connected = TRUE;
+ pListenerStreamInfo->flags = response->flags;
+ pListenerStreamInfo->stream_vlan_id = response->stream_vlan_id;
+
+ U16 configIdx = openavbAemGetConfigIdx();
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput = openavbAemGetDescriptor(configIdx, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, response->listener_unique_id);
+
+ // AVDECC_TODO: Verify that the pDescriptorStreamInput->stream details match that of pListenerStreamInfo.
+
+ if (!pDescriptorStreamInput) {
+ retStatus = OPENAVB_ACMP_STATUS_LISTENER_UNKNOWN_ID;
+ }
+ else if (openavbAVDECCRunListener(pDescriptorStreamInput, configIdx, pListenerStreamInfo)) {
+ retStatus = OPENAVB_ACMP_STATUS_SUCCESS;
+ }
+ else {
+ retStatus = OPENAVB_ACMP_STATUS_LISTENER_MISBEHAVING;
+ }
+ }
+ else {
+ retStatus = OPENAVB_ACMP_STATUS_LISTENER_UNKNOWN_ID;
+ }
+
+ // AVDECC_TODO - any flags need to be updated in the response?
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return retStatus;
+}
+
+U8 openavbAcmpSMListener_disconnectListener(openavb_acmp_ACMPCommandResponse_t *response)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ U8 retStatus;
+
+ openavb_acmp_ListenerStreamInfo_t *pListenerStreamInfo = openavbArrayDataIdx(openavbAcmpSMListenerVars.listenerStreamInfos, response->listener_unique_id);
+ if (pListenerStreamInfo) {
+ U16 configIdx = openavbAemGetConfigIdx();
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput = openavbAemGetDescriptor(configIdx, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, response->listener_unique_id);
+
+ // AVDECC_TODO: Verify that the pDescriptorStreamInput->stream details match that of pListenerStreamInfo.
+
+ if (!pDescriptorStreamInput) {
+ retStatus = OPENAVB_ACMP_STATUS_LISTENER_UNKNOWN_ID;
+ }
+ else if (openavbAVDECCStopListener(pDescriptorStreamInput, configIdx, pListenerStreamInfo)) {
+ retStatus = OPENAVB_ACMP_STATUS_SUCCESS;
+ }
+ else {
+ retStatus = OPENAVB_ACMP_STATUS_LISTENER_MISBEHAVING;
+ }
+ memset(pListenerStreamInfo, 0, sizeof(*pListenerStreamInfo));
+ }
+ else {
+ retStatus = OPENAVB_ACMP_STATUS_LISTENER_UNKNOWN_ID;
+ }
+
+ // AVDECC_TODO - any flags need to be updated in the response?
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return retStatus;
+}
+
+void openavbAcmpSMListener_cancelTimeout(openavb_acmp_ACMPCommandResponse_t *commandResponse)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ // Nothing to do since the timer is reset during the wait state and the inFlight entry will have already been removed.
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMListener_removeInflight(openavb_acmp_ACMPCommandResponse_t *commandResponse)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ openavb_list_node_t node = openavbAcmpSMListener_findInflightNodeFromCommand(commandResponse);
+ if (node) {
+ openavbListDelete(openavbAcmpSMListenerVars.inflight, node);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+U8 openavbAcmpSMListener_getState(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ U8 retStatus = OPENAVB_ACMP_STATUS_LISTENER_MISBEHAVING;
+
+ openavb_acmp_ListenerStreamInfo_t *pListenerStreamInfo = openavbArrayDataIdx(openavbAcmpSMListenerVars.listenerStreamInfos, command->listener_unique_id);
+ if (pListenerStreamInfo) {
+ memcpy(command->stream_id, pListenerStreamInfo->stream_id, sizeof(command->stream_id));
+ memcpy(command->talker_entity_id, pListenerStreamInfo->talker_entity_id, sizeof(command->talker_entity_id));
+ command->talker_unique_id = pListenerStreamInfo->talker_unique_id;
+ //command->listener_unique_id = command->listener_unique_id; // Overwriting data in passed in structure
+ memcpy(command->stream_dest_mac, pListenerStreamInfo->stream_dest_mac, sizeof(command->stream_dest_mac));
+ command->connection_count = pListenerStreamInfo->connected ? 1 : 0; // AVDECC_TODO - questionable information in spec.
+ command->flags = pListenerStreamInfo->flags;
+ command->stream_vlan_id = pListenerStreamInfo->stream_vlan_id;
+ retStatus = OPENAVB_ACMP_STATUS_SUCCESS;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return retStatus;
+}
+
+void openavbAcmpSMListenerStateMachine()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ openavb_acmp_InflightCommand_t *pInflightActive = NULL; // The inflight command for the current state
+ openavb_acmp_sm_listener_state_t state = OPENAVB_ACMP_SM_LISTENER_STATE_WAITING;
+
+ // Lock such that the mutex is held unless waiting for a semaphore. Synchronous processing of command responses.
+ ACMP_SM_LOCK();
+ while (bRunning) {
+ switch (state) {
+ case OPENAVB_ACMP_SM_LISTENER_STATE_WAITING:
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_LISTENER_STATE_WAITING");
+
+ openavbAcmpSMListenerVars.rcvdConnectRXCmd = FALSE;
+ openavbAcmpSMListenerVars.rcvdDisconnectRXCmd = FALSE;
+ openavbAcmpSMListenerVars.rcvdConnectTXResp = FALSE;
+ openavbAcmpSMListenerVars.rcvdDisconnectTXResp = FALSE;
+ openavbAcmpSMListenerVars.rcvdGetRXState = FALSE;
+
+ // Wait for a change in state
+ while (state == OPENAVB_ACMP_SM_LISTENER_STATE_WAITING && bRunning) {
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+
+ // Calculate timeout for inflight commands
+ // Start is a arbitrary large time out.
+ struct timespec timeout;
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &timeout);
+ timeout.tv_sec += 60; // At most will timeout after 60 seconds
+
+ // Look for soonest inflight command timeout
+ openavb_list_node_t node = openavbListIterFirst(openavbAcmpSMListenerVars.inflight);
+ while (node) {
+ openavb_acmp_InflightCommand_t *pInflight = openavbListData(node);
+ if ((openavbTimeTimespecCmp(&pInflight->timer, &timeout) < 0)) {
+ timeout.tv_sec = pInflight->timer.tv_sec;
+ timeout.tv_nsec = pInflight->timer.tv_nsec;
+ }
+ node = openavbListIterNext(openavbAcmpSMListenerVars.inflight);
+ }
+
+ ACMP_SM_UNLOCK();
+ U32 timeoutMSec = 0;
+ struct timespec now;
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &now);
+ timeoutMSec = openavbTimeUntilMSec(&now, &timeout);
+ SEM_ERR_T(err);
+ SEM_TIMEDWAIT(openavbAcmpSMListenerSemaphore, timeoutMSec, err);
+ ACMP_SM_LOCK();
+
+ if (!SEM_IS_ERR_NONE(err)) {
+ if (SEM_IS_ERR_TIMEOUT(err)) {
+ struct timespec now;
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &now);
+
+ // Look for a timed out inflight command
+ openavb_list_node_t node = openavbListIterFirst(openavbAcmpSMListenerVars.inflight);
+ while (node) {
+ openavb_acmp_InflightCommand_t *pInflight = openavbListData(node);
+ if ((openavbTimeTimespecCmp(&now, &pInflight->timer) >= 0)) {
+ // Found a timed out command
+ if (pInflight->command.message_type == OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND) {
+ state = OPENAVB_ACMP_SM_LISTENER_STATE_CONNECT_TX_TIMEOUT;
+ pInflightActive = pInflight;
+ }
+ else if (pInflight->command.message_type == OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND) {
+ state = OPENAVB_ACMP_SM_LISTENER_STATE_DISCONNECT_TX_TIMEOUT;
+ pInflightActive = pInflight;
+ }
+ else {
+ AVB_LOGF_ERROR("Unrecognized listener timeout command %u", pInflight->command.message_type);
+ bRunning = FALSE;
+ }
+ break;
+ }
+ node = openavbListIterNext(openavbAcmpSMListenerVars.inflight);
+ }
+ }
+ }
+ else {
+ if (openavbAcmpSMListenerVars.doTerminate) {
+ bRunning = FALSE;
+ }
+ else if (memcmp(pRcvdCmdResp->listener_entity_id, openavbAcmpSMGlobalVars.my_id, sizeof(openavbAcmpSMGlobalVars.my_id)) == 0) {
+ if (openavbAcmpSMListenerVars.rcvdConnectRXCmd) {
+ state = OPENAVB_ACMP_SM_LISTENER_STATE_CONNECT_RX_COMMAND;
+ }
+ else if (openavbAcmpSMListenerVars.rcvdConnectTXResp) {
+ state = OPENAVB_ACMP_SM_LISTENER_STATE_CONNECT_TX_RESPONSE;
+ }
+ else if (openavbAcmpSMListenerVars.rcvdGetRXState) {
+ state = OPENAVB_ACMP_SM_LISTENER_STATE_GET_STATE;
+ }
+ else if (openavbAcmpSMListenerVars.rcvdDisconnectRXCmd) {
+ state = OPENAVB_ACMP_SM_LISTENER_STATE_DISCONNECT_RX_COMMAND;
+ }
+ else if (openavbAcmpSMListenerVars.rcvdDisconnectTXResp) {
+ state = OPENAVB_ACMP_SM_LISTENER_STATE_DISCONNECT_TX_RESPONSE;
+ }
+ }
+ }
+ }
+ break;
+
+ case OPENAVB_ACMP_SM_LISTENER_STATE_CONNECT_RX_COMMAND:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_LISTENER_STATE_CONNECT_RX_COMMAND");
+
+ if (openavbAcmpSMListener_validListenerUnique(pRcvdCmdResp->listener_unique_id)) {
+ if (!openavbAcmpSMListener_listenerIsConnected(pRcvdCmdResp)) {
+ openavbAcmpSMListener_txCommand(OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND, pRcvdCmdResp, FALSE);
+ }
+ else {
+ openavbAcmpSMListener_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE, pRcvdCmdResp, OPENAVB_ACMP_STATUS_LISTENER_EXCLUSIVE);
+ }
+ }
+ else {
+ openavbAcmpSMListener_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE, pRcvdCmdResp, OPENAVB_ACMP_STATUS_LISTENER_UNKNOWN_ID);
+ }
+ state = OPENAVB_ACMP_SM_LISTENER_STATE_WAITING;
+ }
+ break;
+ case OPENAVB_ACMP_SM_LISTENER_STATE_CONNECT_TX_RESPONSE:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_LISTENER_STATE_CONNECT_TX_RESPONSE");
+
+ U8 status;
+ if (openavbAcmpSMListener_validListenerUnique(pRcvdCmdResp->listener_unique_id)) {
+ openavb_acmp_ACMPCommandResponse_t response;
+ memcpy(&response, pRcvdCmdResp, sizeof(response));
+ if (pRcvdCmdResp->status == OPENAVB_ACMP_STATUS_SUCCESS) {
+ status = openavbAcmpSMListener_connectListener(&response);
+ }
+ else {
+ status = pRcvdCmdResp->status;
+ }
+
+ // Save the state for this connection, so it can potentially be fast connected later.
+ // TODO: Add fast connect support for STREAMING_WAIT connections by handling START_STREAMING and STOP_STREAMING commands.
+ if (status == OPENAVB_ACMP_STATUS_SUCCESS) {
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput = openavbAemGetDescriptor(openavbAemGetConfigIdx(), OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, pRcvdCmdResp->listener_unique_id);
+ if (pDescriptorStreamInput != NULL && pDescriptorStreamInput->stream != NULL) {
+ if (gAvdeccCfg.bFastConnectSupported &&
+ (pRcvdCmdResp->flags & OPENAVB_ACMP_FLAG_STREAMING_WAIT) == 0) {
+ if (openavbAvdeccSaveState(
+ pDescriptorStreamInput->stream,
+ (pRcvdCmdResp->flags & (OPENAVB_ACMP_FLAG_CLASS_B | OPENAVB_ACMP_FLAG_SUPPORTS_ENCRYPTED | OPENAVB_ACMP_FLAG_ENCRYPTED_PDU)),
+ pRcvdCmdResp->talker_unique_id,
+ pRcvdCmdResp->talker_entity_id,
+ pRcvdCmdResp->controller_entity_id)) {
+ // Let the Controller know that the state is saved.
+ response.flags |= OPENAVB_ACMP_FLAG_SAVED_STATE;
+ }
+ if (pDescriptorStreamInput->fast_connect_status >= OPENAVB_FAST_CONNECT_STATUS_IN_PROGRESS) {
+ pDescriptorStreamInput->fast_connect_status = OPENAVB_FAST_CONNECT_STATUS_SUCCEEDED;
+ }
+ }
+
+ // Save the response flags for reference later.
+ pDescriptorStreamInput->acmp_flags = response.flags;
+
+ // Save the stream information for reference later.
+ memcpy(pDescriptorStreamInput->acmp_stream_id, pRcvdCmdResp->stream_id, 8);
+ memcpy(pDescriptorStreamInput->acmp_dest_addr, pRcvdCmdResp->stream_dest_mac, 6);
+ pDescriptorStreamInput->acmp_stream_vlan_id = pRcvdCmdResp->stream_vlan_id;
+ }
+ }
+
+ openavb_list_node_t node = openavbAcmpSMListener_findInflightNodeFromCommand(pRcvdCmdResp);
+ if (node) {
+ openavb_acmp_InflightCommand_t *pInFlightCommand = openavbListData(node);
+ if (pInFlightCommand) {
+ response.sequence_id = pInFlightCommand->original_sequence_id;
+ }
+ }
+ openavbAcmpSMListener_cancelTimeout(pRcvdCmdResp);
+ openavbAcmpSMListener_removeInflight(pRcvdCmdResp);
+ openavbAcmpSMListener_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_RX_RESPONSE, &response, status);
+ }
+ state = OPENAVB_ACMP_SM_LISTENER_STATE_WAITING;
+ }
+ break;
+ case OPENAVB_ACMP_SM_LISTENER_STATE_GET_STATE:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_LISTENER_STATE_GET_STATE");
+
+ U8 error;
+
+ openavb_acmp_ACMPCommandResponse_t response;
+ memcpy(&response, pRcvdCmdResp, sizeof(response));
+ if (openavbAcmpSMListener_validListenerUnique(pRcvdCmdResp->listener_unique_id)) {
+ error = openavbAcmpSMListener_getState(&response);
+ }
+ else {
+ error = OPENAVB_ACMP_STATUS_LISTENER_UNKNOWN_ID;
+ }
+ openavbAcmpSMListener_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_GET_RX_STATE_RESPONSE, &response, error);
+ state = OPENAVB_ACMP_SM_LISTENER_STATE_WAITING;
+ }
+ break;
+ case OPENAVB_ACMP_SM_LISTENER_STATE_DISCONNECT_RX_COMMAND:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_LISTENER_STATE_DISCONNECT_RX_COMMAND");
+
+ if (openavbAcmpSMListener_validListenerUnique(pRcvdCmdResp->listener_unique_id)) {
+ U8 status;
+
+ openavb_acmp_ACMPCommandResponse_t response;
+ memcpy(&response, pRcvdCmdResp, sizeof(response));
+ status = openavbAcmpSMListener_disconnectListener(pRcvdCmdResp);
+ if (status == OPENAVB_ACMP_STATUS_SUCCESS) {
+ openavbAcmpSMListener_txCommand(OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND, pRcvdCmdResp, FALSE);
+ }
+ else {
+ openavbAcmpSMListener_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_RESPONSE, &response, status);
+ }
+
+ // Clear the saved state for this connection, so it won't be fast connected later.
+ if (gAvdeccCfg.bFastConnectSupported) {
+ U16 configIdx = openavbAemGetConfigIdx();
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput = openavbAemGetDescriptor(configIdx, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, pRcvdCmdResp->listener_unique_id);
+ if (pDescriptorStreamInput != NULL && pDescriptorStreamInput->stream != NULL) {
+ pDescriptorStreamInput->fast_connect_status = OPENAVB_FAST_CONNECT_STATUS_NOT_AVAILABLE;
+ openavbAvdeccClearSavedState(pDescriptorStreamInput->stream);
+ }
+ }
+ }
+ else {
+ openavbAcmpSMListener_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_RESPONSE, pRcvdCmdResp, OPENAVB_ACMP_STATUS_NOT_CONNECTED);
+ }
+ state = OPENAVB_ACMP_SM_LISTENER_STATE_WAITING;
+ }
+ break;
+ case OPENAVB_ACMP_SM_LISTENER_STATE_DISCONNECT_TX_RESPONSE:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_LISTENER_STATE_DISCONNECT_TX_RESPONSE");
+
+ if (openavbAcmpSMListener_validListenerUnique(pRcvdCmdResp->listener_unique_id)) {
+ openavb_acmp_ACMPCommandResponse_t response;
+ memcpy(&response, pRcvdCmdResp, sizeof(response));
+ U8 status = pRcvdCmdResp->status;
+
+ openavb_list_node_t node = openavbAcmpSMListener_findInflightNodeFromCommand(pRcvdCmdResp);
+ if (node) {
+ openavb_acmp_InflightCommand_t *pInFlightCommand = openavbListData(node);
+ if (pInFlightCommand) {
+ response.sequence_id = pInFlightCommand->original_sequence_id;
+ }
+ }
+ openavbAcmpSMListener_cancelTimeout(pRcvdCmdResp);
+ openavbAcmpSMListener_removeInflight(pRcvdCmdResp);
+ openavbAcmpSMListener_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_RESPONSE, &response, status);
+
+ state = OPENAVB_ACMP_SM_LISTENER_STATE_WAITING;
+ }
+ }
+ break;
+ case OPENAVB_ACMP_SM_LISTENER_STATE_CONNECT_TX_TIMEOUT:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_LISTENER_STATE_CONNECT_TX_TIMEOUT");
+
+ if (pInflightActive) {
+ if (pInflightActive->retried) {
+ if ((pInflightActive->command.flags & OPENAVB_ACMP_FLAG_FAST_CONNECT) != 0) {
+ // Special handling for Fast Connect CONNECT_TX_COMMAND failures.
+ AVB_LOG_DEBUG("Fast Connect timeout handling");
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput = openavbAemGetDescriptor(openavbAemGetConfigIdx(), OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, pInflightActive->command.listener_unique_id);
+ if (pDescriptorStreamInput != NULL &&
+ pDescriptorStreamInput->fast_connect_status == OPENAVB_FAST_CONNECT_STATUS_IN_PROGRESS) {
+ pDescriptorStreamInput->fast_connect_status = OPENAVB_FAST_CONNECT_STATUS_TIMED_OUT;
+ }
+#if 0
+ // Wait another CONNECT_TX_COMMAND timeout period and then try again.
+ // This option is described at the end of the second paragraph of IEEE 1722.1-2013 Clause 8.2.2.1.1.
+ //
+ // This feature is currently disabled, as it's not clear all the ramifications
+ // of having an inflight attempt at the same time we might be initiating another
+ // fast connect as a result of the ADP discovery of the Talker,
+ // or of using the state machine to allow retries indefinitely.
+ //
+ pInflightActive->retried = FALSE;
+ openavbTimeTimespecAddUsec(&pInflightActive->timer, OPENAVB_ACMP_COMMAND_TIMEOUT_CONNECT_TX_COMMAND * MICROSECONDS_PER_MSEC);
+#else
+ // Abort this attempt without sending a message the Controller.
+ openavbAcmpSMListener_removeInflight(&pInflightActive->command);
+#endif
+ }
+ else {
+ // Standard handling. Notify the AVDECC controller.
+ openavb_acmp_ACMPCommandResponse_t response;
+ memcpy(&response, &pInflightActive->command, sizeof(response));
+ response.sequence_id = pInflightActive->original_sequence_id;
+ openavbAcmpSMListener_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_RX_RESPONSE, &response, OPENAVB_ACMP_STATUS_LISTENER_TALKER_TIMEOUT);
+ openavbAcmpSMListener_removeInflight(&pInflightActive->command);
+ }
+ }
+ else {
+ openavbAcmpSMListener_txCommand(OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_COMMAND, &pInflightActive->command, TRUE);
+ }
+ }
+ state = OPENAVB_ACMP_SM_LISTENER_STATE_WAITING;
+ }
+ break;
+ case OPENAVB_ACMP_SM_LISTENER_STATE_DISCONNECT_TX_TIMEOUT:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_LISTENER_STATE_DISCONNECT_TX_TIMEOUT");
+
+ if (pInflightActive) {
+ if (pInflightActive->retried) {
+ openavb_acmp_ACMPCommandResponse_t response;
+ memcpy(&response, &pInflightActive->command, sizeof(response));
+ response.sequence_id = pInflightActive->original_sequence_id;
+ openavbAcmpSMListener_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_RX_RESPONSE, &response, OPENAVB_ACMP_STATUS_LISTENER_TALKER_TIMEOUT);
+ openavbAcmpSMListener_removeInflight(&pInflightActive->command);
+ }
+ else {
+ openavbAcmpSMListener_txCommand(OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_COMMAND, &pInflightActive->command, TRUE);
+ }
+ }
+ state = OPENAVB_ACMP_SM_LISTENER_STATE_WAITING;
+ }
+ break;
+ }
+ }
+ ACMP_SM_UNLOCK();
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void* openavbAcmpSmListenerThreadFn(void *pv)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ openavbAcmpSMListenerStateMachine();
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return NULL;
+}
+
+bool openavbAcmpSMListenerStart()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ openavbAcmpSMListenerVars.inflight = openavbListNewList();
+ if (!openavbAcmpSMListenerVars.inflight) {
+ AVB_LOG_ERROR("Unable to create inflight list. ACMP protocol not started.");
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return FALSE;
+ }
+ openavbAcmpSMListenerVars.listenerStreamInfos = openavbArrayNewArray(sizeof(openavb_acmp_ListenerStreamInfo_t));
+ if (!openavbAcmpSMListenerVars.listenerStreamInfos) {
+ AVB_LOG_ERROR("Unable to create listenerStreamInfos array. ACMP protocol not started.");
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return FALSE;
+ }
+ openavb_array_t streamInputDescriptorArray = openavbAemGetDescriptorArray(openavbAemGetConfigIdx(), OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT);
+ if (streamInputDescriptorArray) {
+ openavbArrayMultiNew(openavbAcmpSMListenerVars.listenerStreamInfos, openavbArrayCount(streamInputDescriptorArray));
+ }
+
+ MUTEX_ATTR_HANDLE(mta);
+ MUTEX_ATTR_INIT(mta);
+ MUTEX_ATTR_SET_TYPE(mta, MUTEX_ATTR_TYPE_DEFAULT);
+ MUTEX_ATTR_SET_NAME(mta, "openavbAcmpSMListenerMutex");
+ MUTEX_CREATE_ERR();
+ MUTEX_CREATE(openavbAcmpSMListenerMutex, mta);
+ MUTEX_LOG_ERR("Could not create/initialize 'openavbAcmpSMListenerMutex' mutex");
+
+ SEM_ERR_T(err);
+ SEM_INIT(openavbAcmpSMListenerSemaphore, 1, err);
+ SEM_LOG_ERR(err);
+
+ // Start the State Machine
+ bool errResult;
+ bRunning = TRUE;
+ THREAD_CREATE(openavbAcmpSmListenerThread, openavbAcmpSmListenerThread, NULL, openavbAcmpSmListenerThreadFn, NULL);
+ THREAD_CHECK_ERROR(openavbAcmpSmListenerThread, "Thread / task creation failed", errResult);
+ if (errResult) {
+ bRunning = FALSE;
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return TRUE;
+}
+
+void openavbAcmpSMListenerStop()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ if (bRunning) {
+ openavbAcmpSMListenerSet_doTerminate(TRUE);
+
+ THREAD_JOIN(openavbAcmpSmListenerThread, NULL);
+ }
+
+ SEM_ERR_T(err);
+ SEM_DESTROY(openavbAcmpSMListenerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ openavbListDeleteList(openavbAcmpSMListenerVars.inflight);
+ openavbArrayDeleteArray(openavbAcmpSMListenerVars.listenerStreamInfos);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMListenerSet_rcvdConnectRXCmd(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ ACMP_SM_LOCK();
+
+ memcpy(pRcvdCmdResp, command, sizeof(*command));
+ openavbAcmpSMListenerVars.rcvdConnectRXCmd = TRUE;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAcmpSMListenerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ ACMP_SM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMListenerSet_rcvdDisconnectRXCmd(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ ACMP_SM_LOCK();
+
+ memcpy(pRcvdCmdResp, command, sizeof(*command));
+ openavbAcmpSMListenerVars.rcvdDisconnectRXCmd = TRUE;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAcmpSMListenerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ ACMP_SM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMListenerSet_rcvdConnectTXResp(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ ACMP_SM_LOCK();
+
+ memcpy(pRcvdCmdResp, command, sizeof(*command));
+ openavbAcmpSMListenerVars.rcvdConnectTXResp = TRUE;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAcmpSMListenerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ ACMP_SM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMListenerSet_rcvdDisconnectTXResp(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ ACMP_SM_LOCK();
+
+ memcpy(pRcvdCmdResp, command, sizeof(*command));
+ openavbAcmpSMListenerVars.rcvdDisconnectTXResp = TRUE;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAcmpSMListenerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ ACMP_SM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMListenerSet_rcvdGetRXState(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ ACMP_SM_LOCK();
+
+ memcpy(pRcvdCmdResp, command, sizeof(*command));
+ openavbAcmpSMListenerVars.rcvdGetRXState = TRUE;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAcmpSMListenerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ ACMP_SM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMListenerSet_doTerminate(bool value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ openavbAcmpSMListenerVars.doTerminate = value;
+ SEM_ERR_T(err);
+ SEM_POST(openavbAcmpSMListenerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+
+// Special command to initiate the fast connect support.
+void openavbAcmpSMListenerSet_doFastConnect(const openavb_tl_data_cfg_t *pListener, U16 flags, U16 talker_unique_id, const U8 talker_entity_id[8], const U8 controller_entity_id[8])
+{
+ openavb_acmp_ACMPCommandResponse_t command;
+ static U16 s_sequence_id = 0;
+
+ // Get the descriptor and listener_unique_id for the supplied listener.
+ openavb_aem_descriptor_stream_io_t *pDescriptor;
+ U16 listenerUniqueId;
+ for (listenerUniqueId = 0; listenerUniqueId < 0xFFFF; ++listenerUniqueId) {
+ pDescriptor = openavbAemGetDescriptor(openavbAemGetConfigIdx(), OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, listenerUniqueId);
+ if (!pDescriptor) {
+ // Out of listeners to try. Assume something went wrong.
+ AVB_LOG_ERROR("Unable to find listener_unique_id for fast connect");
+ return;
+ }
+ if (pDescriptor->stream && strcmp(pDescriptor->stream->friendly_name, pListener->friendly_name) == 0) {
+ // We found a match.
+ break;
+ }
+ }
+
+ // Should we attempt to fast connect?
+ if (!gAvdeccCfg.bFastConnectSupported ||
+ (pDescriptor->fast_connect_status != OPENAVB_FAST_CONNECT_STATUS_UNKNOWN &&
+ pDescriptor->fast_connect_status != OPENAVB_FAST_CONNECT_STATUS_TIMED_OUT)) {
+ return;
+ }
+
+ // Update the descriptor.
+ pDescriptor->fast_connect_status = OPENAVB_FAST_CONNECT_STATUS_IN_PROGRESS;
+ memcpy(pDescriptor->fast_connect_talker_entity_id, talker_entity_id, sizeof(pDescriptor->fast_connect_talker_entity_id));
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &pDescriptor->fast_connect_start_time);
+
+ // Create a fake CONNECT_RX_COMMAND to kick off the fast connect process.
+ // The FAST_CONNECT flag is used to indicate internally that the controller didn't initiate this.
+ //
+ // TODO: IEEE 1722.1-2013 Clause 8.2.1.18 implies that stream_vlan_id should always be 0 for CONNECT_RX_COMMAND,
+ // as it is the Talker that may set a non-zero value in CONNECT_TX_RESPONSE.
+ // Is that really the case?
+ //
+ memset(&command, 0, sizeof(command));
+ command.message_type = OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_RX_COMMAND;
+ memset(command.stream_id, 0xFF, 8);
+ memcpy(command.controller_entity_id, controller_entity_id, 8);
+ memcpy(command.talker_entity_id, talker_entity_id, 8);
+ memcpy(command.listener_entity_id, openavbAcmpSMGlobalVars.my_id, 8);
+ command.talker_unique_id = talker_unique_id;
+ command.listener_unique_id = listenerUniqueId;
+ memset(command.stream_dest_mac, 0xFF, 6);
+ command.sequence_id = ++s_sequence_id;
+ command.flags = flags | OPENAVB_ACMP_FLAG_FAST_CONNECT | OPENAVB_ACMP_FLAG_SAVED_STATE;
+
+ AVB_LOGF_INFO("Listener %s attempting fast connect to flags=0x%04x, talker_unique_id=0x%04x, talker_entity_id=" ENTITYID_FORMAT ", controller_entity_id=" ENTITYID_FORMAT,
+ pListener->friendly_name,
+ flags,
+ talker_unique_id,
+ ENTITYID_ARGS(talker_entity_id),
+ ENTITYID_ARGS(controller_entity_id));
+
+ // Start processing the faked command.
+ openavbAcmpSMListenerSet_rcvdConnectRXCmd(&command);
+}
+
+// Assist function to detect if Talker available for fast connect
+void openavbAcmpSMListenerSet_talkerTestFastConnect(
+ const U8 entity_id[8])
+{
+ //AVB_LOGF_DEBUG("Talker entity discovered: " ENTITYID_FORMAT, ENTITYID_ARGS(entity_id));
+
+ // Are there any Listeners that have been unsuccessful in a fast connect?
+ openavb_aem_descriptor_stream_io_t *pDescriptor;
+ U16 listenerUniqueId;
+ for (listenerUniqueId = 0; listenerUniqueId < 0xFFFF; ++listenerUniqueId) {
+ pDescriptor = openavbAemGetDescriptor(openavbAemGetConfigIdx(), OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, listenerUniqueId);
+ if (!pDescriptor) {
+ // Out of listeners to try.
+ break;
+ }
+
+ if (pDescriptor->stream &&
+ pDescriptor->fast_connect_status == OPENAVB_FAST_CONNECT_STATUS_TIMED_OUT &&
+ memcmp(pDescriptor->fast_connect_talker_entity_id, entity_id, sizeof(pDescriptor->fast_connect_talker_entity_id)) == 0) {
+ //
+ // We found a Talker matching the one we have been looking for.
+ //
+
+ // See if it is time to connect yet.
+ struct timespec currenttime;
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &currenttime);
+ if (openavbTimeTimespecCmp(&currenttime, &pDescriptor->fast_connect_start_time) < 0) {
+ AVB_LOG_DEBUG("Not yet time to do a fast connect");
+ break;
+ }
+
+ // Get the rest of the details we need to connect to it.
+ U16 flags, talker_unique_id;
+ U8 talker_entity_id[8], controller_entity_id[8];
+ bool bAvailable = openavbAvdeccGetSaveStateInfo(pDescriptor->stream, &flags, &talker_unique_id, &talker_entity_id, &controller_entity_id);
+ if (bAvailable && memcmp(entity_id, talker_entity_id, 8) == 0) {
+ AVB_LOGF_DEBUG("Detected talker_entity_id=" ENTITYID_FORMAT ". Retrying fast connect.", ENTITYID_ARGS(talker_entity_id));
+ openavbAcmpSMListenerSet_doFastConnect(pDescriptor->stream, flags, talker_unique_id, talker_entity_id, controller_entity_id);
+ }
+ else {
+ AVB_LOGF_DEBUG("Fast connect info for talker_entity_id=" ENTITYID_FORMAT " no longer valid", ENTITYID_ARGS(entity_id));
+ memset(pDescriptor->fast_connect_talker_entity_id, 0, sizeof(pDescriptor->fast_connect_talker_entity_id));
+ }
+
+ break;
+ }
+ }
+}
diff --git a/lib/avtp_pipeline/acmp/openavb_acmp_sm_listener.h b/lib/avtp_pipeline/acmp/openavb_acmp_sm_listener.h
new file mode 100644
index 00000000..4cfd9dfa
--- /dev/null
+++ b/lib/avtp_pipeline/acmp/openavb_acmp_sm_listener.h
@@ -0,0 +1,94 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : ACMP - AVDECC Connection Management Protocol : Listener State Machine Interface
+ * MODULE SUMMARY : Interface for the ACMP - AVDECC Connection Management Protocol : Listener State Machine
+ * IEEE Std 1722.1-2013 clause 8.2.2.5
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_ACMP_SM_LISTENER_H
+#define OPENAVB_ACMP_SM_LISTENER_H 1
+
+#include "openavb_list.h"
+#include "openavb_acmp.h"
+
+// State machine vars IEEE Std 1722.1-2013 clause 8.2.2.5.1
+typedef struct {
+ openavb_list_t inflight;
+ openavb_array_t listenerStreamInfos;
+ bool rcvdConnectRXCmd;
+ bool rcvdDisconnectRXCmd;
+ bool rcvdConnectTXResp;
+ bool rcvdDisconnectTXResp;
+ bool rcvdGetRXState;
+
+ // Not part of spec
+ bool doTerminate;
+} openavb_acmp_sm_listener_vars_t;
+
+// State machine functions IEEE Std 1722.1-2013 clause 8.2.2.5.2
+bool openavbAcmpSMListener_validListenerUnique(U16 listenerUniqueId);
+bool openavbAcmpSMListener_listenerIsConnected(openavb_acmp_ACMPCommandResponse_t *command);
+bool openavbAcmpSMListener_listenerIsConnectedTo(openavb_acmp_ACMPCommandResponse_t *command);
+void openavbAcmpSMListener_txCommand(U8 messageType, openavb_acmp_ACMPCommandResponse_t *command, bool retry);
+void openavbAcmpSMListener_txResponse(U8 messageType, openavb_acmp_ACMPCommandResponse_t *response, U8 error);
+U8 openavbAcmpSMListener_connectListener(openavb_acmp_ACMPCommandResponse_t *response);
+U8 openavbAcmpSMListener_disconnectListener(openavb_acmp_ACMPCommandResponse_t *response);
+void openavbAcmpSMListener_cancelTimeout(openavb_acmp_ACMPCommandResponse_t *commandResponse);
+void openavbAcmpSMListener_removeInflight(openavb_acmp_ACMPCommandResponse_t *commandResponse);
+U8 openavbAcmpSMListener_getState(openavb_acmp_ACMPCommandResponse_t *command);
+
+bool openavbAcmpSMListenerStart(void);
+void openavbAcmpSMListenerStop(void);
+
+void openavbAcmpSMListenerSet_rcvdConnectRXCmd(openavb_acmp_ACMPCommandResponse_t *command);
+void openavbAcmpSMListenerSet_rcvdDisconnectRXCmd(openavb_acmp_ACMPCommandResponse_t *command);
+void openavbAcmpSMListenerSet_rcvdConnectTXResp(openavb_acmp_ACMPCommandResponse_t *command);
+void openavbAcmpSMListenerSet_rcvdDisconnectTXResp(openavb_acmp_ACMPCommandResponse_t *command);
+void openavbAcmpSMListenerSet_rcvdGetRXState(openavb_acmp_ACMPCommandResponse_t *command);
+void openavbAcmpSMListenerSet_doTerminate(bool value);
+
+// Special command to initiate the fast connect support.
+void openavbAcmpSMListenerSet_doFastConnect(
+ const openavb_tl_data_cfg_t *pListener,
+ U16 flags,
+ U16 talker_unique_id,
+ const U8 talker_entity_id[8],
+ const U8 controller_entity_id[8]);
+
+// Assist function to detect if Talker available for fast connect
+void openavbAcmpSMListenerSet_talkerTestFastConnect(
+ const U8 entity_id[8]);
+
+#endif // OPENAVB_ACMP_SM_LISTENER_H
diff --git a/lib/avtp_pipeline/acmp/openavb_acmp_sm_talker.c b/lib/avtp_pipeline/acmp/openavb_acmp_sm_talker.c
new file mode 100644
index 00000000..f0818a24
--- /dev/null
+++ b/lib/avtp_pipeline/acmp/openavb_acmp_sm_talker.c
@@ -0,0 +1,682 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : ACMP - AVDECC Connection Management Protocol : Talker State Machine
+ * MODULE SUMMARY : Implements the ACMP - AVDECC Connection Management Protocol : Talker State Machine
+ * IEEE Std 1722.1-2013 clause 8.2.2.6
+ ******************************************************************
+ */
+
+#include "openavb_platform.h"
+
+#include <signal.h>
+
+#define AVB_LOG_COMPONENT "ACMP"
+#include "openavb_log.h"
+
+#include "openavb_aem.h"
+#include "openavb_acmp_sm_talker.h"
+#include "openavb_acmp_sm_listener.h"
+#include "openavb_acmp_message.h"
+#include "openavb_avdecc_pipeline_interaction_pub.h"
+
+typedef enum {
+ OPENAVB_ACMP_SM_TALKER_STATE_WAITING,
+ OPENAVB_ACMP_SM_TALKER_STATE_CONNECT,
+ OPENAVB_ACMP_SM_TALKER_STATE_DISCONNECT,
+ OPENAVB_ACMP_SM_TALKER_STATE_GET_STATE,
+ OPENAVB_ACMP_SM_TALKER_STATE_GET_CONNECTION
+} openavb_acmp_sm_talker_state_t;
+
+extern openavb_acmp_sm_global_vars_t openavbAcmpSMGlobalVars;
+
+static openavb_acmp_ACMPCommandResponse_t rcvdCmdResp;
+static openavb_acmp_ACMPCommandResponse_t *pRcvdCmdResp = &rcvdCmdResp;
+static openavb_acmp_sm_talker_vars_t openavbAcmpSMTalkerVars = {0};
+static bool bRunning = FALSE;
+
+extern MUTEX_HANDLE(openavbAcmpMutex);
+#define ACMP_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAcmpMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define ACMP_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAcmpMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+static MUTEX_HANDLE(openavbAcmpSMTalkerMutex);
+#define ACMP_SM_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAcmpSMTalkerMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define ACMP_SM_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAcmpSMTalkerMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+SEM_T(openavbAcmpSMTalkerSemaphore);
+THREAD_TYPE(openavbAcmpSmTalkerThread);
+THREAD_DEFINITON(openavbAcmpSmTalkerThread);
+
+
+openavb_list_node_t openavbAcmpSMTalker_findListenerPairNodeFromCommand(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ openavb_list_node_t node = NULL;
+
+ openavb_acmp_TalkerStreamInfo_t *pTalkerStreamInfo = openavbArrayDataIdx(openavbAcmpSMTalkerVars.talkerStreamInfos, command->talker_unique_id);
+ if (pTalkerStreamInfo) {
+ node = openavbListIterFirst(pTalkerStreamInfo->connected_listeners);
+ while (node) {
+ openavb_acmp_ListenerPair_t *pListenerPair = openavbListData(node);
+ if (pListenerPair) {
+ if (memcmp(pListenerPair->listener_entity_id, command->listener_entity_id, sizeof(pListenerPair->listener_entity_id)) == 0) {
+ if (pListenerPair->listener_unique_id == command->listener_unique_id) {
+ break;
+ }
+ }
+ }
+ node = openavbListIterNext(pTalkerStreamInfo->connected_listeners);
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return node;
+}
+
+
+bool openavbAcmpSMTalker_validTalkerUnique(U16 talkerUniqueId)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ if (!openavbAemGetDescriptor(openavbAemGetConfigIdx(), OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT, talkerUniqueId)) {
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return TRUE;
+}
+
+U8 openavbAcmpSMTalker_connectTalker(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ U8 retStatus = OPENAVB_ACMP_STATUS_TALKER_MISBEHAVING;
+
+ openavb_acmp_TalkerStreamInfo_t *pTalkerStreamInfo = openavbArrayDataIdx(openavbAcmpSMTalkerVars.talkerStreamInfos, command->talker_unique_id);
+ if (pTalkerStreamInfo) {
+ openavb_list_node_t node = openavbAcmpSMTalker_findListenerPairNodeFromCommand(command);
+ if (node) {
+ if (memcmp(pTalkerStreamInfo->stream_id, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0 ||
+ memcmp(pTalkerStreamInfo->stream_dest_mac, "\x00\x00\x00\x00\x00\x00", 6) == 0) {
+ // In the process of connecting. Ignore this, as we don't yet have a response.
+ AVB_LOG_INFO("Ignoring duplicate CONNECT_TX_COMMAND");
+ retStatus = OPENAVB_ACMP_STATUS_SUCCESS;
+ }
+ else {
+ // Already connected, so return the current status.
+ AVB_LOG_DEBUG("Sending immediate response to CONNECT_TX_COMMAND");
+ U16 configIdx = openavbAemGetConfigIdx();
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput = openavbAemGetDescriptor(configIdx, OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT, command->talker_unique_id);
+ if (pDescriptorStreamOutput) {
+ command->flags = (pDescriptorStreamOutput->acmp_flags &
+ (OPENAVB_ACMP_FLAG_CLASS_B |
+ OPENAVB_ACMP_FLAG_FAST_CONNECT |
+ OPENAVB_ACMP_FLAG_SAVED_STATE |
+ OPENAVB_ACMP_FLAG_SUPPORTS_ENCRYPTED |
+ OPENAVB_ACMP_FLAG_ENCRYPTED_PDU));
+ }
+ memcpy(command->stream_id, pTalkerStreamInfo->stream_id, sizeof(command->stream_id));
+ memcpy(command->stream_dest_mac, pTalkerStreamInfo->stream_dest_mac, sizeof(command->stream_dest_mac));
+ command->stream_vlan_id = pTalkerStreamInfo->stream_vlan_id;
+ command->connection_count = pTalkerStreamInfo->connection_count;
+ openavbAcmpSMTalker_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE, command, OPENAVB_ACMP_STATUS_SUCCESS);
+ retStatus = OPENAVB_ACMP_STATUS_SUCCESS;
+ }
+ }
+ else {
+ if (!pTalkerStreamInfo->connected_listeners) {
+ pTalkerStreamInfo->connected_listeners = openavbListNewList();
+ }
+ node = openavbListNew(pTalkerStreamInfo->connected_listeners, sizeof(openavb_acmp_ListenerPair_t));
+ if (node) {
+ openavb_acmp_ListenerPair_t *pListenerPair = openavbListData(node);
+ memcpy(pListenerPair->listener_entity_id, command->listener_entity_id, sizeof(pListenerPair->listener_entity_id));
+ pListenerPair->listener_unique_id = command->listener_unique_id;
+ pTalkerStreamInfo->connection_count++;
+
+ U16 configIdx = openavbAemGetConfigIdx();
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput = openavbAemGetDescriptor(configIdx, OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT, command->talker_unique_id);
+ if (!pDescriptorStreamOutput) {
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return retStatus;
+ }
+
+ if (openavbAVDECCRunTalker(pDescriptorStreamOutput, configIdx, pTalkerStreamInfo)) {
+
+ command->connection_count = pTalkerStreamInfo->connection_count;
+
+ // Wait for the Talker to supply us with updated stream information.
+ if (!pTalkerStreamInfo->waiting_on_talker) {
+ pTalkerStreamInfo->waiting_on_talker = (openavb_acmp_ACMPCommandResponse_t *) malloc(sizeof(openavb_acmp_ACMPCommandResponse_t));
+ if (!pTalkerStreamInfo->waiting_on_talker) {
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return OPENAVB_ACMP_STATUS_TALKER_MISBEHAVING;
+ }
+ }
+ memcpy(pTalkerStreamInfo->waiting_on_talker, command, sizeof(openavb_acmp_ACMPCommandResponse_t));
+ retStatus = OPENAVB_ACMP_STATUS_SUCCESS;
+ }
+ }
+ }
+ }
+ else {
+ retStatus = OPENAVB_ACMP_STATUS_TALKER_UNKNOWN_ID;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return retStatus;
+}
+
+void openavbAcmpSMTalker_txResponse(U8 messageType, openavb_acmp_ACMPCommandResponse_t *response, U8 error)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ openavbAcmpMessageSend(messageType, response, error);
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+U8 openavbAcmpSMTalker_disconnectTalker(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ U8 retStatus = OPENAVB_ACMP_STATUS_TALKER_MISBEHAVING;
+
+ openavb_acmp_TalkerStreamInfo_t *pTalkerStreamInfo = openavbArrayDataIdx(openavbAcmpSMTalkerVars.talkerStreamInfos, command->talker_unique_id);
+ if (pTalkerStreamInfo) {
+ openavb_list_node_t node = openavbAcmpSMTalker_findListenerPairNodeFromCommand(command);
+ if (!node) {
+ // Already disconnected, so return the current status.
+ memcpy(command->stream_id, pTalkerStreamInfo->stream_id, sizeof(command->stream_id));
+ memcpy(command->stream_dest_mac, pTalkerStreamInfo->stream_dest_mac, sizeof(command->stream_dest_mac));
+ command->connection_count = pTalkerStreamInfo->connection_count;
+ retStatus = OPENAVB_ACMP_STATUS_SUCCESS;
+ }
+ else {
+ openavbListDelete(pTalkerStreamInfo->connected_listeners, node);
+ pTalkerStreamInfo->connection_count--;
+
+ U16 configIdx = openavbAemGetConfigIdx();
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput = openavbAemGetDescriptor(configIdx, OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT, command->talker_unique_id);
+ if (!pDescriptorStreamOutput) {
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return retStatus;
+ }
+ openavbAVDECCGetTalkerStreamInfo(pDescriptorStreamOutput, configIdx, pTalkerStreamInfo);
+
+ // Stop the Talker if connection_count is 0.
+ if (pTalkerStreamInfo->connection_count > 0 ||
+ openavbAVDECCStopTalker(pDescriptorStreamOutput, configIdx, pTalkerStreamInfo)) {
+ memcpy(command->stream_id, pTalkerStreamInfo->stream_id, sizeof(command->stream_id));
+ memcpy(command->stream_dest_mac, pTalkerStreamInfo->stream_dest_mac, sizeof(command->stream_dest_mac));
+ command->connection_count = pTalkerStreamInfo->connection_count;
+ retStatus = OPENAVB_ACMP_STATUS_SUCCESS;
+ }
+ }
+ }
+ else {
+ retStatus = OPENAVB_ACMP_STATUS_TALKER_UNKNOWN_ID;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return retStatus;
+}
+
+U8 openavbAcmpSMTalker_getState(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ U8 retStatus = OPENAVB_ACMP_STATUS_TALKER_MISBEHAVING;
+
+ openavb_acmp_TalkerStreamInfo_t *pTalkerStreamInfo = openavbArrayDataIdx(openavbAcmpSMTalkerVars.talkerStreamInfos, command->talker_unique_id);
+ if (pTalkerStreamInfo) {
+ U16 configIdx = openavbAemGetConfigIdx();
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput = openavbAemGetDescriptor(configIdx, OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT, command->talker_unique_id);
+ if (!pDescriptorStreamOutput) {
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return retStatus;
+ }
+ openavbAVDECCGetTalkerStreamInfo(pDescriptorStreamOutput, configIdx, pTalkerStreamInfo);
+
+ memcpy(command->stream_id, pTalkerStreamInfo->stream_id, sizeof(command->stream_id));
+ memcpy(command->stream_dest_mac, pTalkerStreamInfo->stream_dest_mac, sizeof(command->stream_dest_mac));
+ command->stream_vlan_id = pTalkerStreamInfo->stream_vlan_id;
+ command->connection_count = pTalkerStreamInfo->connection_count;
+ retStatus = OPENAVB_ACMP_STATUS_SUCCESS;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return retStatus;
+}
+
+U8 openavbAcmpSMTalker_getConnection(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ U8 retStatus = OPENAVB_ACMP_STATUS_TALKER_MISBEHAVING;
+
+ openavb_acmp_TalkerStreamInfo_t *pTalkerStreamInfo = openavbArrayDataIdx(openavbAcmpSMTalkerVars.talkerStreamInfos, command->talker_unique_id);
+ if (pTalkerStreamInfo) {
+ int count = command->connection_count;
+
+ openavb_list_node_t node = openavbListIterFirst(pTalkerStreamInfo->connected_listeners);
+ while (node && count-- > 0) {
+ node = openavbListIterNext(pTalkerStreamInfo->connected_listeners);
+ }
+
+ openavb_acmp_ListenerPair_t *pListenerPair = openavbListData(node);
+ if (pListenerPair) {
+ memcpy(command->stream_id, pTalkerStreamInfo->stream_id, sizeof(command->stream_id));
+ memcpy(command->stream_dest_mac, pTalkerStreamInfo->stream_dest_mac, sizeof(command->stream_dest_mac));
+ command->stream_vlan_id = pTalkerStreamInfo->stream_vlan_id;
+ command->connection_count = pTalkerStreamInfo->connection_count;
+
+ memcpy(command->listener_entity_id, pListenerPair->listener_entity_id, sizeof(command->listener_entity_id));
+ command->listener_unique_id = pListenerPair->listener_unique_id;
+ retStatus = OPENAVB_ACMP_STATUS_SUCCESS;
+ }
+ else {
+ retStatus = OPENAVB_ACMP_STATUS_NO_SUCH_CONNECTION;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return retStatus;
+}
+
+void openavbAcmpSMTalkerStateMachine()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ openavb_acmp_sm_talker_state_t state = OPENAVB_ACMP_SM_TALKER_STATE_WAITING;
+
+ // Lock such that the mutex is held unless waiting for a semaphore. Synchronous processing of command responses.
+ ACMP_SM_LOCK();
+ while (bRunning) {
+ switch (state) {
+ case OPENAVB_ACMP_SM_TALKER_STATE_WAITING:
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_TALKER_STATE_WAITING");
+
+ openavbAcmpSMTalkerVars.rcvdConnectTX = FALSE;
+ openavbAcmpSMTalkerVars.rcvdDisconnectTX = FALSE;
+ openavbAcmpSMTalkerVars.rcvdGetTXState = FALSE;
+ openavbAcmpSMTalkerVars.rcvdGetTXConnection = FALSE;
+
+ // Wait for a change in state
+ while (state == OPENAVB_ACMP_SM_TALKER_STATE_WAITING && bRunning) {
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+
+ ACMP_SM_UNLOCK();
+ SEM_ERR_T(err);
+ SEM_WAIT(openavbAcmpSMTalkerSemaphore, err);
+ ACMP_SM_LOCK();
+
+ if (SEM_IS_ERR_NONE(err)) {
+ if (openavbAcmpSMTalkerVars.doTerminate) {
+ bRunning = FALSE;
+ }
+ else if (memcmp(pRcvdCmdResp->talker_entity_id, openavbAcmpSMGlobalVars.my_id, sizeof(openavbAcmpSMGlobalVars.my_id)) == 0) {
+
+ if (openavbAcmpSMTalkerVars.rcvdConnectTX) {
+ state = OPENAVB_ACMP_SM_TALKER_STATE_CONNECT;
+ }
+ else if (openavbAcmpSMTalkerVars.rcvdDisconnectTX) {
+ state = OPENAVB_ACMP_SM_TALKER_STATE_DISCONNECT;
+ }
+ else if (openavbAcmpSMTalkerVars.rcvdGetTXState) {
+ state = OPENAVB_ACMP_SM_TALKER_STATE_GET_STATE;
+ }
+ else if (openavbAcmpSMTalkerVars.rcvdGetTXConnection) {
+ state = OPENAVB_ACMP_SM_TALKER_STATE_GET_CONNECTION;
+ }
+ }
+ }
+ }
+ break;
+
+ case OPENAVB_ACMP_SM_TALKER_STATE_CONNECT:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_TALKER_STATE_CONNECT");
+
+ U8 error;
+ openavb_acmp_ACMPCommandResponse_t response;
+ memcpy(&response, pRcvdCmdResp, sizeof(response));
+ if (!openavbAcmpSMTalker_validTalkerUnique(pRcvdCmdResp->talker_unique_id)) {
+ // Talker ID is not recognized.
+ error = OPENAVB_ACMP_STATUS_TALKER_UNKNOWN_ID;
+ openavbAcmpSMTalker_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE, &response, error);
+ state = OPENAVB_ACMP_SM_TALKER_STATE_WAITING;
+ break;
+ }
+
+ // Try and start the Talker.
+ error = openavbAcmpSMTalker_connectTalker(&response);
+ if (error != OPENAVB_ACMP_STATUS_SUCCESS) {
+ openavbAcmpSMTalker_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE, &response, error);
+ state = OPENAVB_ACMP_SM_TALKER_STATE_WAITING;
+ break;
+ }
+
+ // openavbAcmpSMTalker_connectTalker() either sent a response, or updated the state
+ // to indicate we are waiting for information from the Talker.
+ // Either way, there is nothing else to do for now.
+ state = OPENAVB_ACMP_SM_TALKER_STATE_WAITING;
+ }
+ break;
+
+ case OPENAVB_ACMP_SM_TALKER_STATE_DISCONNECT:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ACMP);
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_TALKER_STATE_DISCONNECT");
+
+ U8 error;
+ openavb_acmp_ACMPCommandResponse_t response;
+ memcpy(&response, pRcvdCmdResp, sizeof(response));
+ if (openavbAcmpSMTalker_validTalkerUnique(pRcvdCmdResp->talker_unique_id)) {
+ error = openavbAcmpSMTalker_disconnectTalker(&response);
+ }
+ else {
+ error = OPENAVB_ACMP_STATUS_TALKER_UNKNOWN_ID;
+ }
+ openavbAcmpSMTalker_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_RESPONSE, &response, error);
+
+ state = OPENAVB_ACMP_SM_TALKER_STATE_WAITING;
+ }
+ break;
+
+ case OPENAVB_ACMP_SM_TALKER_STATE_GET_STATE:
+ {
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_TALKER_STATE_GET_STATE");
+
+ U8 error;
+ openavb_acmp_ACMPCommandResponse_t response;
+ memcpy(&response, pRcvdCmdResp, sizeof(response));
+ if (openavbAcmpSMTalker_validTalkerUnique(pRcvdCmdResp->talker_unique_id)) {
+ error = openavbAcmpSMTalker_getState(&response);
+ }
+ else {
+ error = OPENAVB_ACMP_STATUS_TALKER_UNKNOWN_ID;
+ }
+ openavbAcmpSMTalker_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_GET_TX_STATE_RESPONSE, &response, error);
+
+ state = OPENAVB_ACMP_SM_TALKER_STATE_WAITING;
+ }
+ break;
+
+ case OPENAVB_ACMP_SM_TALKER_STATE_GET_CONNECTION:
+ {
+ AVB_LOG_DEBUG("State: OPENAVB_ACMP_SM_TALKER_STATE_GET_CONNECTION");
+
+ U8 error;
+ openavb_acmp_ACMPCommandResponse_t response;
+ memcpy(&response, pRcvdCmdResp, sizeof(response));
+ if (openavbAcmpSMTalker_validTalkerUnique(pRcvdCmdResp->talker_unique_id)) {
+ error = openavbAcmpSMTalker_getConnection(&response);
+ }
+ else {
+ error = OPENAVB_ACMP_STATUS_TALKER_UNKNOWN_ID;
+ }
+ openavbAcmpSMTalker_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_GET_TX_CONNECTION_RESPONSE, &response, error);
+
+ state = OPENAVB_ACMP_SM_TALKER_STATE_WAITING;
+ }
+ break;
+ }
+ }
+ ACMP_SM_UNLOCK();
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void* openavbAcmpSMTalkerThreadFn(void *pv)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ openavbAcmpSMTalkerStateMachine();
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return NULL;
+}
+
+bool openavbAcmpSMTalkerStart()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ openavbAcmpSMTalkerVars.talkerStreamInfos = openavbArrayNewArray(sizeof(openavb_acmp_TalkerStreamInfo_t));
+ if (!openavbAcmpSMTalkerVars.talkerStreamInfos) {
+ AVB_LOG_ERROR("Unable to create talkerStreamInfos array. ACMP protocol not started.");
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return FALSE;
+ }
+ openavb_array_t streamOutputDescriptorArray = openavbAemGetDescriptorArray(openavbAemGetConfigIdx(), OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT);
+ if (streamOutputDescriptorArray) {
+ openavbArrayMultiNew(openavbAcmpSMTalkerVars.talkerStreamInfos, openavbArrayCount(streamOutputDescriptorArray));
+ }
+
+ MUTEX_ATTR_HANDLE(mta);
+ MUTEX_ATTR_INIT(mta);
+ MUTEX_ATTR_SET_TYPE(mta, MUTEX_ATTR_TYPE_DEFAULT);
+ MUTEX_ATTR_SET_NAME(mta, "openavbAcmpSMTalkerMutex");
+ MUTEX_CREATE_ERR();
+ MUTEX_CREATE(openavbAcmpSMTalkerMutex, mta);
+ MUTEX_LOG_ERR("Could not create/initialize 'openavbAcmpSMTalkerMutex' mutex");
+
+ SEM_ERR_T(err);
+ SEM_INIT(openavbAcmpSMTalkerSemaphore, 1, err);
+ SEM_LOG_ERR(err);
+
+ // Start the State Machine
+ bool errResult;
+ bRunning = TRUE;
+ THREAD_CREATE(openavbAcmpSmTalkerThread, openavbAcmpSmTalkerThread, NULL, openavbAcmpSMTalkerThreadFn, NULL);
+ THREAD_CHECK_ERROR(openavbAcmpSmTalkerThread, "Thread / task creation failed", errResult);
+ if (errResult) {
+ bRunning = FALSE;
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+ return TRUE;
+}
+
+void openavbAcmpSMTalkerStop()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ if (bRunning) {
+ openavbAcmpSMTalkerSet_doTerminate(TRUE);
+
+ THREAD_JOIN(openavbAcmpSmTalkerThread, NULL);
+ }
+
+ SEM_ERR_T(err);
+ SEM_DESTROY(openavbAcmpSMTalkerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ openavb_array_elem_t node = openavbArrayIterFirst(openavbAcmpSMTalkerVars.talkerStreamInfos);
+ while (node) {
+ openavb_acmp_TalkerStreamInfo_t *pTalkerStreamInfo = openavbArrayData(node);
+ if (pTalkerStreamInfo != NULL) {
+ openavbListDeleteList(pTalkerStreamInfo->connected_listeners);
+ if (pTalkerStreamInfo->waiting_on_talker) {
+ free(pTalkerStreamInfo->waiting_on_talker);
+ pTalkerStreamInfo->waiting_on_talker = NULL;
+ }
+ }
+ node = openavbArrayIterNext(openavbAcmpSMTalkerVars.talkerStreamInfos);
+ }
+ openavbArrayDeleteArray(openavbAcmpSMTalkerVars.talkerStreamInfos);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMTalkerSet_rcvdConnectTXCmd(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ ACMP_SM_LOCK();
+
+ memcpy(pRcvdCmdResp, command, sizeof(*command));
+ openavbAcmpSMTalkerVars.rcvdConnectTX = TRUE;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAcmpSMTalkerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ ACMP_SM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMTalkerSet_rcvdDisconnectTXCmd(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ ACMP_SM_LOCK();
+
+ memcpy(pRcvdCmdResp, command, sizeof(*command));
+ openavbAcmpSMTalkerVars.rcvdDisconnectTX = TRUE;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAcmpSMTalkerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ ACMP_SM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMTalkerSet_rcvdGetTXState(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ ACMP_SM_LOCK();
+
+ memcpy(pRcvdCmdResp, command, sizeof(*command));
+ openavbAcmpSMTalkerVars.rcvdGetTXState = TRUE;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAcmpSMTalkerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ ACMP_SM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMTalkerSet_rcvdGetTXConnectionCmd(openavb_acmp_ACMPCommandResponse_t *command)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ ACMP_SM_LOCK();
+
+ memcpy(pRcvdCmdResp, command, sizeof(*command));
+ openavbAcmpSMTalkerVars.rcvdGetTXConnection = TRUE;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAcmpSMTalkerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ ACMP_SM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+void openavbAcmpSMTalkerSet_doTerminate(bool value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+ openavbAcmpSMTalkerVars.doTerminate = value;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAcmpSMTalkerSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
+
+
+void openavbAcmpSMTalker_updateStreamInfo(openavb_tl_data_cfg_t *pCfg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ACMP);
+
+ ACMP_SM_LOCK();
+
+ // Find the talker stream waiting for the update.
+ openavb_array_elem_t node = openavbArrayIterFirst(openavbAcmpSMTalkerVars.talkerStreamInfos);
+ while (node) {
+ openavb_acmp_TalkerStreamInfo_t *pTalkerStreamInfo = openavbArrayData(node);
+ if (pTalkerStreamInfo != NULL && pTalkerStreamInfo->waiting_on_talker != NULL) {
+ U16 configIdx = openavbAemGetConfigIdx();
+ S32 talker_unique_id = openavbArrayGetIdx(node);
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput = openavbAemGetDescriptor(configIdx, OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT, talker_unique_id);
+ if (pDescriptorStreamOutput && pDescriptorStreamOutput->stream == pCfg) {
+
+ // Verify that the destination address is valid.
+ if (pCfg->dest_addr.mac == NULL ||
+ memcmp(pCfg->dest_addr.buffer.ether_addr_octet, "\x00\x00\x00\x00\x00\x00", 6) == 0) {
+ AVB_LOG_DEBUG("stream_dest_mac not yet valid. Continue to wait.");
+ continue;
+ }
+
+ // We will handle the GET_TX_CONNECTION_RESPONSE command response here.
+ AVB_LOGF_DEBUG("Received an update for talker_unique_id %d", talker_unique_id);
+ openavb_acmp_ACMPCommandResponse_t *response = pTalkerStreamInfo->waiting_on_talker;
+ pTalkerStreamInfo->waiting_on_talker = NULL;
+
+ // Update the talker stream information with the information from the configuration.
+ memcpy(pTalkerStreamInfo->stream_id, pCfg->stream_addr.mac, ETH_ALEN);
+ U8 *pStreamUID = pTalkerStreamInfo->stream_id + 6;
+ *(U16 *)(pStreamUID) = htons(pCfg->stream_uid);
+ memcpy(pTalkerStreamInfo->stream_dest_mac, pCfg->dest_addr.buffer.ether_addr_octet, ETH_ALEN);
+ pTalkerStreamInfo->stream_vlan_id = pCfg->vlan_id;
+
+ // Update the GET_TX_CONNECTION_RESPONSE command information.
+ memcpy(response->stream_id, pTalkerStreamInfo->stream_id, sizeof(response->stream_id));
+ memcpy(response->stream_dest_mac, pTalkerStreamInfo->stream_dest_mac, sizeof(response->stream_dest_mac));
+ response->stream_vlan_id = pTalkerStreamInfo->stream_vlan_id;
+ response->connection_count = pTalkerStreamInfo->connection_count;
+
+ // Save the response flags for reference later.
+ pDescriptorStreamOutput->acmp_flags = response->flags;
+
+ // Save the stream information for reference later.
+ // (This is currently only used by Listeners, but it doesn't hurt to have it just in case.)
+ memcpy(pDescriptorStreamOutput->acmp_stream_id, response->stream_id, 8);
+ memcpy(pDescriptorStreamOutput->acmp_dest_addr, response->stream_dest_mac, 6);
+ pDescriptorStreamOutput->acmp_stream_vlan_id = response->stream_vlan_id;
+
+ // Send the response.
+ openavbAcmpSMTalker_txResponse(OPENAVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE, response, OPENAVB_ACMP_STATUS_SUCCESS);
+ AVB_LOG_DEBUG("Sent a CONNECT_TX_RESPONSE command");
+
+ // Done with the response command.
+ free(response);
+ break;
+ }
+ }
+ node = openavbArrayIterNext(openavbAcmpSMTalkerVars.talkerStreamInfos);
+ }
+
+ ACMP_SM_UNLOCK();
+
+ AVB_TRACE_EXIT(AVB_TRACE_ACMP);
+}
diff --git a/lib/avtp_pipeline/acmp/openavb_acmp_sm_talker.h b/lib/avtp_pipeline/acmp/openavb_acmp_sm_talker.h
new file mode 100644
index 00000000..f78ce72d
--- /dev/null
+++ b/lib/avtp_pipeline/acmp/openavb_acmp_sm_talker.h
@@ -0,0 +1,76 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : ACMP - AVDECC Connection Management Protocol : Talker State Machine Interface
+ * MODULE SUMMARY : Interface for the ACMP - AVDECC Connection Management Protocol : Talker State Machine
+ * IEEE Std 1722.1-2013 clause 8.2.2.6
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_ACMP_SM_TALKER_H
+#define OPENAVB_ACMP_SM_TALKER_H 1
+
+#include "openavb_acmp.h"
+
+// State machine vars IEEE Std 1722.1-2013 clause 8.2.2.6.1
+typedef struct {
+ openavb_array_t talkerStreamInfos;
+ bool rcvdConnectTX;
+ bool rcvdDisconnectTX;
+ bool rcvdGetTXState;
+ bool rcvdGetTXConnection;
+
+ // Not part of spec
+ bool doTerminate;
+} openavb_acmp_sm_talker_vars_t;
+
+// State machine functions IEEE Std 1722.1-2013 clause 8.2.2.6.2
+bool openavbAcmpSMTalker_validTalkerUnique(U16 talkerUniqueId);
+U8 openavbAcmpSMTalker_connectTalker(openavb_acmp_ACMPCommandResponse_t *command);
+void openavbAcmpSMTalker_txResponse(U8 messageType, openavb_acmp_ACMPCommandResponse_t *response, U8 error);
+U8 openavbAcmpSMTalker_disconnectTalker(openavb_acmp_ACMPCommandResponse_t *command);
+U8 openavbAcmpSMTalker_getState(openavb_acmp_ACMPCommandResponse_t *command);
+U8 openavbAcmpSMTalker_getConnection(openavb_acmp_ACMPCommandResponse_t *command);
+
+bool openavbAcmpSMTalkerStart(void);
+void openavbAcmpSMTalkerStop(void);
+
+void openavbAcmpSMTalkerSet_rcvdConnectTXCmd(openavb_acmp_ACMPCommandResponse_t *command);
+void openavbAcmpSMTalkerSet_rcvdDisconnectTXCmd(openavb_acmp_ACMPCommandResponse_t *command);
+void openavbAcmpSMTalkerSet_rcvdGetTXState(openavb_acmp_ACMPCommandResponse_t *command);
+void openavbAcmpSMTalkerSet_rcvdGetTXConnectionCmd(openavb_acmp_ACMPCommandResponse_t *command);
+void openavbAcmpSMTalkerSet_doTerminate(bool value);
+
+void openavbAcmpSMTalker_updateStreamInfo(openavb_tl_data_cfg_t *pCfg);
+
+#endif // OPENAVB_ACMP_SM_TALKER_H
diff --git a/lib/avtp_pipeline/adp/CMakeLists.txt b/lib/avtp_pipeline/adp/CMakeLists.txt
new file mode 100644
index 00000000..c8da8d8d
--- /dev/null
+++ b/lib/avtp_pipeline/adp/CMakeLists.txt
@@ -0,0 +1,9 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/adp/openavb_adp.c
+ ${AVB_SRC_DIR}/adp/openavb_adp_message.c
+ ${AVB_SRC_DIR}/adp/openavb_adp_sm_advertise_entity.c
+ ${AVB_SRC_DIR}/adp/openavb_adp_sm_advertise_interface.c
+ ${AVB_SRC_DIR}/adp/openavb_adp_sm_discovery.c
+ PARENT_SCOPE
+)
+
diff --git a/lib/avtp_pipeline/adp/openavb_adp.c b/lib/avtp_pipeline/adp/openavb_adp.c
new file mode 100644
index 00000000..474c8d3e
--- /dev/null
+++ b/lib/avtp_pipeline/adp/openavb_adp.c
@@ -0,0 +1,181 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : ADP - AVDECC Discovery Protocol
+ * MODULE SUMMARY : Implements the 1722.1 (AVDECC) discovery protocol
+ ******************************************************************
+ */
+
+#include "openavb_platform.h"
+
+#include <signal.h>
+
+#define AVB_LOG_COMPONENT "ADP"
+#include "openavb_log.h"
+
+#include "openavb_aem.h"
+#include "openavb_adp.h"
+#include "openavb_adp_sm_advertise_entity.h"
+#include "openavb_adp_sm_advertise_interface.h"
+#include "openavb_adp_message.h"
+
+#ifdef AVB_PTP_AVAILABLE
+#include "openavb_ptp_api.h"
+
+// PTP declarations
+openavbRC openavbPtpInitializeSharedMemory ();
+void openavbPtpReleaseSharedMemory ();
+openavbRC openavbPtpUpdateSharedMemoryEntry ();
+openavbRC openavbPtpFindLatestSharedMemoryEntry(U32 *index);
+extern gmChangeTable_t openavbPtpGMChageTable;
+#endif // AVB_PTP_AVAILABLE
+
+openavb_adp_sm_global_vars_t openavbAdpSMGlobalVars;
+
+MUTEX_HANDLE(openavbAdpMutex);
+#define ADP_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAdpMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define ADP_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAdpMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+extern openavb_avdecc_cfg_t gAvdeccCfg;
+
+static bool s_bPreviousHaveTL = false;
+
+openavbRC openavbAdpStart()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ openavb_avdecc_entity_model_t *pAem = openavbAemGetModel();
+ if (!pAem) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_ENTITY_MODEL_MISSING), AVB_TRACE_ADP);
+ }
+
+ {
+ MUTEX_ATTR_HANDLE(mta);
+ MUTEX_ATTR_INIT(mta);
+ MUTEX_ATTR_SET_TYPE(mta, MUTEX_ATTR_TYPE_DEFAULT);
+ MUTEX_ATTR_SET_NAME(mta, "openavbAdpMutex");
+ MUTEX_CREATE_ERR();
+ MUTEX_CREATE(openavbAdpMutex, mta);
+ MUTEX_LOG_ERR("Could not create/initialize 'openavbAdpMutex' mutex");
+ }
+
+ ADP_LOCK();
+ {
+ // Populate global ADP vars
+ openavb_adp_control_header_t *pHeader = &openavbAdpSMGlobalVars.entityInfo.header;
+
+ pHeader->cd = 1;
+ pHeader->subtype = OPENAVB_ADP_AVTP_SUBTYPE;
+ pHeader->sv = 0;
+ pHeader->version = 0;
+ pHeader->message_type = 0; // Set later depending on message type
+ pHeader->valid_time = gAvdeccCfg.valid_time;
+ pHeader->control_data_length = 56;
+ memcpy(pHeader->entity_id, pAem->pDescriptorEntity->entity_id, sizeof(pAem->pDescriptorEntity->entity_id));
+ }
+
+ {
+ // Populate global ADP PDU vars
+ openavb_adp_data_unit_t *pPdu = &openavbAdpSMGlobalVars.entityInfo.pdu;
+
+#ifdef AVB_PTP_AVAILABLE
+ openavbRC retCode = OPENAVB_PTP_FAILURE;
+ retCode = openavbPtpInitializeSharedMemory();
+ if (IS_OPENAVB_FAILURE(retCode)) {
+ AVB_LOG_WARNING("Failed to init PTP shared memory");
+ }
+#endif // AVB_PTP_AVAILABLE
+
+ memcpy(pPdu->entity_model_id, pAem->pDescriptorEntity->entity_model_id, sizeof(pPdu->entity_model_id));
+ pPdu->entity_capabilities = pAem->pDescriptorEntity->entity_capabilities;
+ pPdu->talker_stream_sources = pAem->pDescriptorEntity->talker_stream_sources;
+ pPdu->talker_capabilities = pAem->pDescriptorEntity->talker_capabilities;
+ pPdu->listener_stream_sinks = pAem->pDescriptorEntity->listener_stream_sinks;
+ pPdu->listener_capabilities = pAem->pDescriptorEntity->listener_capabilities;
+ pPdu->controller_capabilities = pAem->pDescriptorEntity->controller_capabilities;
+ pPdu->available_index = pAem->pDescriptorEntity->available_index;
+ // The pPdu->gptp_grandmaster_id and pPdu->gptp_domain_number will be filled in when the ADPDU is transmitted.
+ // pPdu->reserved0;
+ // pPdu->identify_control_index = ???; // AVDECC_TODO
+ // pPdu->interface_index = ???; // AVDECC_TODO
+ memcpy(pPdu->association_id, pAem->pDescriptorEntity->association_id, sizeof(pPdu->association_id));
+ // pPdu->reserved1;
+ }
+ ADP_UNLOCK();
+
+ // Wait until we are notified that we have a Talker or Listener before supporting discover.
+ s_bPreviousHaveTL = false;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_ADP);
+}
+
+void openavbAdpStop()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+#ifdef AVB_PTP_AVAILABLE
+ openavbPtpReleaseSharedMemory();
+#endif // AVB_PTP_AVAILABLE
+
+ // Stop Advertising and supporting Discovery.
+ openavbAdpHaveTL(false);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+
+openavbRC openavbAdpHaveTL(bool bHaveTL)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ if (bHaveTL && !s_bPreviousHaveTL) {
+ // Start Advertising and supporting Discovery.
+ openavbRC rc = openavbAdpMessageHandlerStart();
+ if (IS_OPENAVB_FAILURE(rc)) {
+ AVB_RC_TRACE_RET(rc, AVB_TRACE_ADP);
+ }
+
+ openavbAdpSMAdvertiseInterfaceStart();
+ openavbAdpSMAdvertiseEntityStart();
+ s_bPreviousHaveTL = true;
+ }
+ else if (!bHaveTL && s_bPreviousHaveTL) {
+ // Stop Advertising and supporting Discovery.
+ openavbAdpSMAdvertiseInterfaceStop();
+ openavbAdpSMAdvertiseEntityStop();
+ openavbAdpMessageHandlerStop();
+ s_bPreviousHaveTL = false;
+ }
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_ADP);
+}
diff --git a/lib/avtp_pipeline/adp/openavb_adp.h b/lib/avtp_pipeline/adp/openavb_adp.h
new file mode 100644
index 00000000..54594527
--- /dev/null
+++ b/lib/avtp_pipeline/adp/openavb_adp.h
@@ -0,0 +1,93 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : ADP - AVDECC Discovery Protocol Internal Interface
+ * MODULE SUMMARY : Internal Interface for the 1722.1 (AVDECC) discovery protocol
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_ADP_H
+#define OPENAVB_ADP_H 1
+
+#include "openavb_avdecc.h"
+#include "openavb_adp_pub.h"
+
+#define OPENAVB_ADP_AVTP_SUBTYPE (0x7a)
+
+typedef struct {
+ U8 cd;
+ U8 subtype;
+ U8 sv;
+ U8 version;
+ U8 message_type; // Redefined from control data
+ U8 valid_time; // Redefined from status
+ U16 control_data_length;
+ U8 entity_id[8]; // Redefined from stream_id
+} openavb_adp_control_header_t;
+
+typedef struct {
+ U8 entity_model_id[8];
+ U32 entity_capabilities;
+ U16 talker_stream_sources;
+ U16 talker_capabilities;
+ U16 listener_stream_sinks;
+ U16 listener_capabilities;
+ U32 controller_capabilities;
+ U32 available_index;
+ U8 gptp_grandmaster_id[8];
+ U8 gptp_domain_number;
+ U8 reserved0[3];
+ U16 identify_control_index;
+ U16 interface_index;
+ U8 association_id[8];
+ U8 reserved1[4];
+} openavb_adp_data_unit_t;
+
+typedef struct {
+ openavb_adp_control_header_t header;
+ openavb_adp_data_unit_t pdu;
+} openavb_adp_entity_info_t;
+
+// IEEE Std 1722.1-2013 clause 6.2.3.
+typedef struct {
+ U64 currentTime;
+ openavb_adp_entity_info_t entityInfo;
+} openavb_adp_sm_global_vars_t;
+
+
+openavbRC openavbAdpStart(void);
+void openavbAdpStop(void);
+
+openavbRC openavbAdpHaveTL(bool bHaveTL);
+
+#endif // OPENAVB_ADP_H
diff --git a/lib/avtp_pipeline/adp/openavb_adp_message.c b/lib/avtp_pipeline/adp/openavb_adp_message.c
new file mode 100644
index 00000000..3f695101
--- /dev/null
+++ b/lib/avtp_pipeline/adp/openavb_adp_message.c
@@ -0,0 +1,464 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : ADP - AVDECC Discovery Protocol Message Handler
+ * MODULE SUMMARY : Implements the 1722.1 (AVDECC) discovery protocol message handlers
+ ******************************************************************
+ */
+
+#include "openavb_platform.h"
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#define AVB_LOG_COMPONENT "ADP"
+#include "openavb_log.h"
+
+#include "openavb_debug.h"
+#include "openavb_rawsock.h"
+#include "openavb_avtp.h"
+#include "openavb_srp.h"
+#include "openavb_adp.h"
+#include "openavb_adp_sm_advertise_interface.h"
+#include "openavb_acmp_sm_listener.h"
+
+#ifdef AVB_PTP_AVAILABLE
+#include "openavb_ptp_api.h"
+
+// PTP declarations
+openavbRC openavbPtpInitializeSharedMemory ();
+void openavbPtpReleaseSharedMemory ();
+openavbRC openavbPtpUpdateSharedMemoryEntry ();
+openavbRC openavbPtpFindLatestSharedMemoryEntry(U32 *index);
+extern gmChangeTable_t openavbPtpGMChageTable;
+#else
+#include "openavb_grandmaster_osal_pub.h"
+#endif // AVB_PTP_AVAILABLE
+
+
+#define INVALID_SOCKET (-1)
+
+// ADP Multicast address
+#define ADP_PROTOCOL_ADDR "91:E0:F0:01:00:00"
+
+// message length
+#define AVTP_HDR_LEN 12
+#define ADP_DATA_LEN 56
+#define ADP_FRAME_LEN (ETH_HDR_LEN_VLAN + AVTP_HDR_LEN + ADP_DATA_LEN)
+
+// number of buffers (arbitrary, and rounded up by rawsock)
+#define ADP_NUM_BUFFERS 2
+
+// do cast from ether_addr to U8*
+#define ADDR_PTR(A) (U8*)(&((A)->ether_addr_octet))
+
+extern openavb_avdecc_cfg_t gAvdeccCfg;
+
+extern MUTEX_HANDLE(openavbAdpMutex);
+#define ADP_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAdpMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define ADP_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAdpMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+static void *rxSock = NULL;
+static void *txSock = NULL;
+static struct ether_addr intfAddr;
+static struct ether_addr adpAddr;
+
+extern openavb_adp_sm_global_vars_t openavbAdpSMGlobalVars;
+
+THREAD_TYPE(openavbAdpMessageRxThread);
+THREAD_DEFINITON(openavbAdpMessageRxThread);
+
+static bool bRunning = FALSE;
+
+void openavbAdpCloseSocket()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ if (rxSock) {
+ openavbRawsockClose(rxSock);
+ rxSock = NULL;
+ }
+ if (txSock) {
+ openavbRawsockClose(txSock);
+ txSock = NULL;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+bool openavbAdpOpenSocket(const char* ifname, U16 vlanID, U8 vlanPCP)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ hdr_info_t hdr;
+
+#ifndef UBUNTU
+ // This is the normal case for most of our supported platforms
+ rxSock = openavbRawsockOpen(ifname, TRUE, FALSE, ETHERTYPE_8021Q, ADP_FRAME_LEN, ADP_NUM_BUFFERS);
+#else
+ rxSock = openavbRawsockOpen(ifname, TRUE, FALSE, ETHERTYPE_AVTP, ADP_FRAME_LEN, ADP_NUM_BUFFERS);
+#endif
+ txSock = openavbRawsockOpen(ifname, FALSE, TRUE, ETHERTYPE_AVTP, ADP_FRAME_LEN, ADP_NUM_BUFFERS);
+
+ if (txSock && rxSock
+ && openavbRawsockGetAddr(txSock, ADDR_PTR(&intfAddr))
+ && ether_aton_r(ADP_PROTOCOL_ADDR, &adpAddr)
+ && openavbRawsockRxMulticast(rxSock, TRUE, ADDR_PTR(&adpAddr)))
+ {
+ if (!openavbRawsockRxAVTPSubtype(rxSock, OPENAVB_ADP_AVTP_SUBTYPE | 0x80)) {
+ AVB_LOG_DEBUG("RX AVTP Subtype not supported");
+ }
+
+ memset(&hdr, 0, sizeof(hdr_info_t));
+ hdr.shost = ADDR_PTR(&intfAddr);
+ hdr.dhost = ADDR_PTR(&adpAddr);
+ hdr.ethertype = ETHERTYPE_AVTP;
+ if (vlanID != 0 || vlanPCP != 0) {
+ hdr.vlan = TRUE;
+ hdr.vlan_pcp = vlanPCP;
+ hdr.vlan_vid = vlanID;
+ AVB_LOGF_DEBUG("VLAN pcp=%d vid=%d", hdr.vlan_pcp, hdr.vlan_vid);
+ }
+ if (!openavbRawsockTxSetHdr(txSock, &hdr)) {
+ AVB_LOG_ERROR("TX socket Header Failure");
+ openavbAdpCloseSocket();
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+ return false;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+ return true;
+ }
+
+ AVB_LOG_ERROR("Invalid socket");
+ openavbAdpCloseSocket();
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+ return false;
+}
+
+static void openavbAdpMessageRxFrameParse(U8* payload, int payload_len, hdr_info_t *hdr)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ openavb_adp_control_header_t adpHeader;
+ openavb_adp_data_unit_t adpPdu;
+
+#if 0
+ AVB_LOGF_DEBUG("openavbAdpMessageRxFrameParse packet data (length %d):", payload_len);
+ AVB_LOG_BUFFER(AVB_LOG_LEVEL_DEBUG, payload, payload_len, 16);
+#endif
+
+ U8 *pSrc = payload;
+ {
+ // AVTP Control Header
+ openavb_adp_control_header_t *pDst = &adpHeader;
+
+ BIT_B2DNTOHB(pDst->cd, pSrc, 0x80, 7, 0);
+ BIT_B2DNTOHB(pDst->subtype, pSrc, 0x7f, 0, 1);
+ BIT_B2DNTOHB(pDst->sv, pSrc, 0x80, 7, 0);
+ BIT_B2DNTOHB(pDst->version, pSrc, 0x70, 4, 0);
+ BIT_B2DNTOHB(pDst->message_type, pSrc, 0x0f, 0, 1);
+ BIT_B2DNTOHB(pDst->valid_time, pSrc, 0xf800, 11, 0);
+ BIT_B2DNTOHS(pDst->control_data_length, pSrc, 0x07ff, 0, 2);
+ OCT_B2DMEMCP(pDst->entity_id, pSrc);
+ }
+
+ if (adpHeader.subtype == OPENAVB_ADP_AVTP_SUBTYPE &&
+ (adpHeader.message_type == OPENAVB_ADP_MESSAGE_TYPE_ENTITY_DISCOVER ||
+ (gAvdeccCfg.bFastConnectSupported && adpHeader.message_type == OPENAVB_ADP_MESSAGE_TYPE_ENTITY_AVAILABLE))) {
+ // ADP PDU
+ openavb_adp_data_unit_t *pDst = &adpPdu;
+
+ OCT_B2DMEMCP(pDst->entity_model_id, pSrc);
+ OCT_B2DNTOHL(pDst->entity_capabilities, pSrc);
+ OCT_B2DNTOHS(pDst->talker_stream_sources, pSrc);
+ OCT_B2DNTOHS(pDst->talker_capabilities, pSrc);
+ OCT_B2DNTOHS(pDst->listener_stream_sinks, pSrc);
+ OCT_B2DNTOHS(pDst->listener_capabilities, pSrc);
+ OCT_B2DNTOHL(pDst->controller_capabilities, pSrc);
+ OCT_B2DNTOHL(pDst->available_index, pSrc);
+ OCT_B2DMEMCP(pDst->gptp_grandmaster_id, pSrc);
+ OCT_B2DNTOHB(pDst->gptp_domain_number, pSrc);
+ OCT_B2DMEMCP(pDst->reserved0, pSrc);
+ OCT_B2DNTOHS(pDst->identify_control_index, pSrc);
+ OCT_B2DNTOHS(pDst->interface_index, pSrc);
+ OCT_B2DMEMCP(pDst->association_id, pSrc);
+ OCT_B2DMEMCP(pDst->reserved1, pSrc);
+
+ if (adpHeader.message_type == OPENAVB_ADP_MESSAGE_TYPE_ENTITY_DISCOVER) {
+ // Update the interface state machine
+ openavbAdpSMAdvertiseInterfaceSet_entityID(adpHeader.entity_id);
+ openavbAdpSMAdvertiseInterfaceSet_rcvdDiscover(TRUE);
+ }
+ else {
+ // See if Fast Connect is waiting for this device to be available.
+ if (adpPdu.talker_stream_sources > 0) {
+ openavbAcmpSMListenerSet_talkerTestFastConnect(adpHeader.entity_id);
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+static void openavbAdpMessageRxFrameReceive(U32 timeoutUsec)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ hdr_info_t hdrInfo;
+ unsigned int offset, len;
+ U8 *pBuf, *pFrame;
+
+ memset(&hdrInfo, 0, sizeof(hdr_info_t));
+
+ pBuf = (U8 *)openavbRawsockGetRxFrame(rxSock, timeoutUsec, &offset, &len);
+ if (pBuf) {
+ pFrame = pBuf + offset;
+
+ offset = openavbRawsockRxParseHdr(rxSock, pBuf, &hdrInfo);
+ {
+#ifndef UBUNTU
+ if (hdrInfo.ethertype == ETHERTYPE_8021Q) {
+ // Oh! Need to look past the VLAN tag
+ U16 vlan_bits = ntohs(*(U16 *)(pFrame + offset));
+ hdrInfo.vlan = TRUE;
+ hdrInfo.vlan_vid = vlan_bits & 0x0FFF;
+ hdrInfo.vlan_pcp = (vlan_bits >> 13) & 0x0007;
+ offset += 2;
+ hdrInfo.ethertype = ntohs(*(U16 *)(pFrame + offset));
+ offset += 2;
+ }
+#endif
+
+ // Make sure that this is an AVTP packet
+ // (Should always be AVTP if it's to our AVTP-specific multicast address)
+ if (hdrInfo.ethertype == ETHERTYPE_AVTP) {
+ // parse the PDU only for ADP messages
+ if (*(pFrame + offset) == (0x80 | OPENAVB_ADP_AVTP_SUBTYPE)) {
+ if (memcmp(hdrInfo.shost, ADDR_PTR(&intfAddr), 6) != 0) { // Not from us!
+ openavbAdpMessageRxFrameParse(pFrame + offset, len - offset, &hdrInfo);
+ }
+ }
+ }
+ else {
+ AVB_LOG_WARNING("Received non-AVTP frame!");
+ AVB_LOGF_DEBUG("Unexpected packet data (length %d):", len);
+ AVB_LOG_BUFFER(AVB_LOG_LEVEL_DEBUG, pFrame, len, 16);
+ }
+ }
+
+ // Release the frame
+ openavbRawsockRelRxFrame(rxSock, pBuf);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+
+void openavbAdpMessageTxFrame(U8 msgType, U8 *destAddr)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ U8 *pBuf;
+ U32 size;
+ unsigned int hdrlen = 0;
+
+ pBuf = openavbRawsockGetTxFrame(txSock, TRUE, &size);
+
+ if (!pBuf) {
+ AVB_LOG_ERROR("No TX buffer");
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+ return;
+ }
+
+ if (size < ADP_FRAME_LEN) {
+ AVB_LOG_ERROR("TX buffer too small");
+ openavbRawsockRelTxFrame(txSock, pBuf);
+ pBuf = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+ return;
+ }
+
+ memset(pBuf, 0, ADP_FRAME_LEN);
+ openavbRawsockTxFillHdr(txSock, pBuf, &hdrlen);
+
+ if (destAddr)
+ memcpy(pBuf, destAddr, ETH_ALEN);
+
+ ADP_LOCK();
+ U8 *pDst = pBuf + hdrlen;
+ {
+ // AVTP Control Header
+ openavb_adp_control_header_t *pSrc = &openavbAdpSMGlobalVars.entityInfo.header;
+ BIT_D2BHTONB(pDst, pSrc->cd, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtype, 0, 1);
+ BIT_D2BHTONB(pDst, pSrc->sv, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc->version, 4, 0);
+ BIT_D2BHTONB(pDst, msgType, 0, 1);
+ BIT_D2BHTONS(pDst, pSrc->valid_time, 11, 0);
+ BIT_D2BHTONS(pDst, pSrc->control_data_length, 0, 2);
+ OCT_D2BMEMCP(pDst, pSrc->entity_id);
+ }
+
+ {
+ // ADP PDU
+ openavb_adp_data_unit_t *pSrc = &openavbAdpSMGlobalVars.entityInfo.pdu;
+ OCT_D2BMEMCP(pDst, pSrc->entity_model_id);
+ OCT_D2BHTONL(pDst, pSrc->entity_capabilities);
+ OCT_D2BHTONS(pDst, pSrc->talker_stream_sources);
+ OCT_D2BHTONS(pDst, pSrc->talker_capabilities);
+ OCT_D2BHTONS(pDst, pSrc->listener_stream_sinks);
+ OCT_D2BHTONS(pDst, pSrc->listener_capabilities);
+ OCT_D2BHTONL(pDst, pSrc->controller_capabilities);
+ OCT_D2BHTONL(pDst, pSrc->available_index);
+ OCT_D2BMEMCP(pDst, pSrc->gptp_grandmaster_id);
+ OCT_D2BHTONB(pDst, pSrc->gptp_domain_number);
+ OCT_D2BMEMCP(pDst, pSrc->reserved0);
+ OCT_D2BHTONS(pDst, pSrc->identify_control_index);
+ OCT_D2BHTONS(pDst, pSrc->interface_index);
+ OCT_D2BMEMCP(pDst, pSrc->association_id);
+ OCT_D2BMEMCP(pDst, pSrc->reserved1);
+ }
+ ADP_UNLOCK();
+
+#if 0
+ AVB_LOGF_DEBUG("openavbAdpMessageTxFrame packet data (length %d):", hdrlen + AVTP_HDR_LEN + ADP_DATA_LEN);
+ AVB_LOG_BUFFER(AVB_LOG_LEVEL_DEBUG, pBuf, hdrlen + AVTP_HDR_LEN + ADP_DATA_LEN, 16);
+#endif
+
+ openavbRawsockTxFrameReady(txSock, pBuf, hdrlen + AVTP_HDR_LEN + ADP_DATA_LEN, 0);
+ openavbRawsockSend(txSock);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void* openavbAdpMessageRxThreadFn(void *pv)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ AVB_LOG_DEBUG("ADP Thread Started");
+ while (bRunning) {
+ // Try to get and process an ADP discovery message.
+ openavbAdpMessageRxFrameReceive(MICROSECONDS_PER_SECOND);
+ }
+ AVB_LOG_DEBUG("ADP Thread Done");
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+ return NULL;
+}
+
+openavbRC openavbAdpMessageHandlerStart()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ bRunning = TRUE;
+
+ if (openavbAdpOpenSocket((const char *)gAvdeccCfg.ifname, gAvdeccCfg.vlanID, gAvdeccCfg.vlanPCP)) {
+
+ // Start the RX thread
+ bool errResult;
+ THREAD_CREATE(openavbAdpMessageRxThread, openavbAdpMessageRxThread, NULL, openavbAdpMessageRxThreadFn, NULL);
+ THREAD_CHECK_ERROR(openavbAdpMessageRxThread, "Thread / task creation failed", errResult);
+ if (errResult) {
+ bRunning = FALSE;
+ openavbAdpCloseSocket();
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_FAILURE, AVB_TRACE_ADP);
+ }
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_ADP);
+ }
+
+ bRunning = FALSE;
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_FAILURE, AVB_TRACE_ADP);
+}
+
+void openavbAdpMessageHandlerStop()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ if (bRunning) {
+ bRunning = FALSE;
+ THREAD_JOIN(openavbAdpMessageRxThread, NULL);
+ openavbAdpCloseSocket();
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+openavbRC openavbAdpMessageSend(U8 messageType)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ // Note: this entire process of the GM ID is not as the 1722.1 spec expects.
+ // The openavbAdpSMAdvertiseInterfaceSet_advertisedGrandmasterID() should be called when the
+ // stack detects a GM change that will trigger an advertise. Instead we are detecting
+ // the GM change when we have are sending an advertise message. This means we will not have a timely
+ // new advertise in the event of a GM change. Additionally the handling the advertiseInterface var
+ // of GM ID is not normal since the GM ID is being placed directly into the PDU rather than getting
+ // pulled from the state machine var.
+ // AVDECC_TODO: This logic should change to detect GM change else where in the system and call the
+ // expected openavbAdpSMAdvertiseInterfaceSet_advertisedGrandmasterID() to start the advertise process.
+#ifdef AVB_PTP_AVAILABLE
+ openavb_adp_data_unit_t *pPdu = &openavbAdpSMGlobalVars.entityInfo.pdu;
+ openavbRC retCode = OPENAVB_PTP_FAILURE;
+ U32 ptpSharedMemoryEntryIndex;
+ retCode = openavbPtpFindLatestSharedMemoryEntry(&ptpSharedMemoryEntryIndex);
+ if (IS_OPENAVB_FAILURE(retCode)) {
+ AVB_LOG_INFO("Failed to find PTP shared memory entry.");
+ }
+ else {
+ if (memcmp(pPdu->gptp_grandmaster_id, openavbPtpGMChageTable.entry[ptpSharedMemoryEntryIndex].gmId, sizeof(pPdu->gptp_grandmaster_id))) {
+ memcpy(pPdu->gptp_grandmaster_id, openavbPtpGMChageTable.entry[ptpSharedMemoryEntryIndex].gmId, sizeof(pPdu->gptp_grandmaster_id));
+ openavbAdpSMAdvertiseInterfaceSet_advertisedGrandmasterID(pPdu->gptp_grandmaster_id);
+ }
+ }
+#else
+ openavb_adp_data_unit_t *pPdu = &openavbAdpSMGlobalVars.entityInfo.pdu;
+ uint8_t current_grandmaster_id[8];
+ if (!osalAVBGrandmasterGetCurrent(current_grandmaster_id, &(pPdu->gptp_domain_number)))
+ {
+ AVB_LOG_ERROR("osalAVBGrandmasterGetCurrent failure");
+ }
+ else if (memcmp(pPdu->gptp_grandmaster_id, current_grandmaster_id, sizeof(pPdu->gptp_grandmaster_id)))
+ {
+ memcpy(pPdu->gptp_grandmaster_id, current_grandmaster_id, sizeof(pPdu->gptp_grandmaster_id));
+ openavbAdpSMAdvertiseInterfaceSet_advertisedGrandmasterID(pPdu->gptp_grandmaster_id);
+ }
+#endif
+
+ openavbAdpMessageTxFrame(messageType, NULL);
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_ADP);
+}
+
diff --git a/lib/avtp_pipeline/adp/openavb_adp_message.h b/lib/avtp_pipeline/adp/openavb_adp_message.h
new file mode 100644
index 00000000..3769ebc6
--- /dev/null
+++ b/lib/avtp_pipeline/adp/openavb_adp_message.h
@@ -0,0 +1,50 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : ADP - AVDECC Discovery Protocol Message Handler Interface
+ * MODULE SUMMARY : Interface for the the 1722.1 (AVDECC) discovery protocol message handlers
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_ADP_MESSAGE_H
+#define OPENAVB_ADP_MESSAGE_H 1
+
+#include "openavb_avdecc.h"
+
+openavbRC openavbAdpMessageHandlerStart(void);
+
+void openavbAdpMessageHandlerStop(void);
+
+openavbRC openavbAdpMessageSend(U8 messageType);
+
+#endif // OPENAVB_ADP_MESSAGE_H
diff --git a/lib/avtp_pipeline/adp/openavb_adp_pub.h b/lib/avtp_pipeline/adp/openavb_adp_pub.h
new file mode 100644
index 00000000..6e332486
--- /dev/null
+++ b/lib/avtp_pipeline/adp/openavb_adp_pub.h
@@ -0,0 +1,90 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : ADP - AVDECC Discovery Protocol Public Interface
+ * MODULE SUMMARY : Public interface for the 1722.1 (AVDECC) discovery protocol
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_ADP_PUB_H
+#define OPENAVB_ADP_PUB_H 1
+
+// message_type field IEEE Std 1722.1-2013 clause 6.2.1.5
+#define OPENAVB_ADP_MESSAGE_TYPE_ENTITY_AVAILABLE (0x00)
+#define OPENAVB_ADP_MESSAGE_TYPE_ENTITY_DEPARTING (0x01)
+#define OPENAVB_ADP_MESSAGE_TYPE_ENTITY_DISCOVER (0x02)
+
+// entity_capabilities field IEEE Std 1722.1-2013 clause 6.2.1.10
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_EFU_MODE (0x00000001)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_ADDRESS_ACCESS_SUPPORTED (0x00000002)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_GATEWAY_ENTITY (0x00000004)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_AEM_SUPPORTED (0x00000008)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_LEGACY_AVC (0x00000010)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_ASSOCIATION_ID_SUPPORTED (0x00000020)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_ASSOCIATION_ID_VALID (0x00000040)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_VENDOR_UNIQUE_SUPPORTED (0x00000080)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_CLASS_A_SUPPORTED (0x00000100)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_CLASS_B_SUPPORTED (0x00000200)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_GPTP_SUPPORTED (0x00000400)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_AEM_AUTHENTICATION_SUPPORTED (0x00000800)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_AEM_AUTHENTICATION_REQUIRED (0x00001000)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_AEM_PERSISTENT_ACQUIRE_SUPPORTED (0x00002000)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_AEM_IDENTIFY_CONTROL_INDEX_VALID (0x00004000)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_AEM_INTERFACE_INDEX_VALID (0x00008000)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_GENERAL_CONTROLLER_IGNORE (0x00010000)
+#define OPENAVB_ADP_ENTITY_CAPABILITIES_ENTITY_NOT_READY (0x00020000)
+
+// talker_capabilities field IEEE Std 1722.1-2013 clause 6.2.1.12
+#define OPENAVB_ADP_TALKER_CAPABILITIES_IMPLEMENTED (0x0001)
+#define OPENAVB_ADP_TALKER_CAPABILITIES_OTHER_SOURCE (0x0200)
+#define OPENAVB_ADP_TALKER_CAPABILITIES_CONTROL_SOURCE (0x0400)
+#define OPENAVB_ADP_TALKER_CAPABILITIES_MEDIA_CLOCK_SOURCE (0x0800)
+#define OPENAVB_ADP_TALKER_CAPABILITIES_SMPTE_SOURCE (0x1000)
+#define OPENAVB_ADP_TALKER_CAPABILITIES_MIDI_SOURCE (0x2000)
+#define OPENAVB_ADP_TALKER_CAPABILITIES_AUDIO_SOURCE (0x4000)
+#define OPENAVB_ADP_TALKER_CAPABILITIES_VIDEO_SOURCE (0x8000)
+
+// listener_capabilities field IEEE Std 1722.1-2013 clause 6.2.1.14
+#define OPENAVB_ADP_LISTENER_CAPABILITIES_IMPLEMENTED (0x0001)
+#define OPENAVB_ADP_LISTENER_CAPABILITIES_OTHER_SINK (0x0200)
+#define OPENAVB_ADP_LISTENER_CAPABILITIES_CONTROL_SINK (0x0400)
+#define OPENAVB_ADP_LISTENER_CAPABILITIES_MEDIA_CLOCK_SINK (0x0800)
+#define OPENAVB_ADP_LISTENER_CAPABILITIES_SMPTE_SINK (0x1000)
+#define OPENAVB_ADP_LISTENER_CAPABILITIES_MIDI_SINK (0x2000)
+#define OPENAVB_ADP_LISTENER_CAPABILITIES_AUDIO_SINK (0x4000)
+#define OPENAVB_ADP_LISTENER_CAPABILITIES_VIDEO_SINK (0x8000)
+
+// controller_capabilities field IEEE Std 1722.1-2013 clause 6.2.1.15
+#define OPENAVB_ADP_CONTROLLER_CAPABILITES_IMPLEMENTED (0x00000001)
+
+#endif // OPENAVB_ADP_PUB_H
diff --git a/lib/avtp_pipeline/adp/openavb_adp_sm_advertise_entity.c b/lib/avtp_pipeline/adp/openavb_adp_sm_advertise_entity.c
new file mode 100644
index 00000000..6a1e5d44
--- /dev/null
+++ b/lib/avtp_pipeline/adp/openavb_adp_sm_advertise_entity.c
@@ -0,0 +1,252 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : ADP - AVDECC Discovery Protocol : Advertise Entity State Machine
+ * MODULE SUMMARY : Implements the AVDECC Discovery Protocol : Advertise Entity State Machine
+ * IEEE Std 1722.1-2013 clause 6.2.4.
+ ******************************************************************
+ */
+
+#include "openavb_platform.h"
+
+#include <errno.h>
+
+#define AVB_LOG_COMPONENT "ADP"
+#include "openavb_log.h"
+
+#include "openavb_time.h"
+#include "openavb_adp.h"
+#include "openavb_adp_sm_advertise_interface.h"
+#include "openavb_adp_sm_advertise_entity.h"
+
+typedef enum {
+ OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_INITIALIZE,
+ OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_ADVERTISE,
+ OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_RESET_WAIT,
+ OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_WAITING,
+ OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_TERMINATE,
+} openavb_adp_sm_advertise_entity_state_t;
+
+extern openavb_adp_sm_global_vars_t openavbAdpSMGlobalVars;
+extern openavb_adp_sm_advertise_interface_vars_t openavbAdpSMAdvertiseInterfaceVars;
+openavb_adp_sm_advertise_entity_vars_t openavbAdpSMAdvertiseEntityVars;
+
+extern MUTEX_HANDLE(openavbAdpMutex);
+#define ADP_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAdpMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define ADP_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAdpMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+SEM_T(openavbAdpSMAdvertiseEntitySemaphore);
+THREAD_TYPE(openavbAdpSmAdvertiseEntityThread);
+THREAD_DEFINITON(openavbAdpSmAdvertiseEntityThread);
+
+void openavbAdpSMAdvertiseEntity_sendAvailable()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+ openavbAdpSMAdvertiseInterfaceSet_doAdvertise(TRUE);
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void openavbAdpSMAdvertiseEntityStateMachine()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+ bool bRunning = TRUE;
+
+ openavb_adp_sm_advertise_entity_state_t state = OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_INITIALIZE;
+
+ while (bRunning) {
+ switch (state) {
+ case OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_INITIALIZE:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ADP);
+ AVB_LOG_DEBUG("State: OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_INITIALIZE");
+
+ ADP_LOCK();
+ openavbAdpSMGlobalVars.entityInfo.pdu.available_index = 0;
+ ADP_UNLOCK();
+
+ // The advertise interface will send the first advertisement on startup.
+ // This entity will be responsible for sending subsequent advertisements.
+ // This allows the advertise entity and advertise interface to startup without any inter-dependencies.
+ state = OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_RESET_WAIT;
+ }
+ break;
+ case OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_ADVERTISE:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ADP);
+ AVB_LOG_DEBUG("State: OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_ADVERTISE");
+
+ openavbAdpSMAdvertiseEntity_sendAvailable();
+ ADP_LOCK();
+ openavbAdpSMAdvertiseEntityVars.needsAdvertise = FALSE;
+ ADP_UNLOCK();
+ state = OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_RESET_WAIT;
+ }
+ break;
+ case OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_RESET_WAIT:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ADP);
+ AVB_LOG_DEBUG("State: OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_RESET_WAIT");
+
+ ADP_LOCK();
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &openavbAdpSMAdvertiseEntityVars.reannounceTimerTimeout);
+ /* The advertisements should be sent at intervals of 1/4 valid_time, where valid_time is in 2-second units.
+ * See IEEE Std 1722.1-2013 clauses 6.2.1.6 and 6.2.4. */
+ U32 advDelayUsec = openavbAdpSMGlobalVars.entityInfo.header.valid_time / 2 * MICROSECONDS_PER_SECOND;
+ if (advDelayUsec < MICROSECONDS_PER_SECOND) {
+ advDelayUsec = MICROSECONDS_PER_SECOND;
+ }
+ openavbTimeTimespecAddUsec(&openavbAdpSMAdvertiseEntityVars.reannounceTimerTimeout, advDelayUsec);
+ ADP_UNLOCK();
+ state = OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_WAITING;
+ }
+ break;
+ case OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_WAITING:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ADP);
+ AVB_LOG_DEBUG("State: OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_WAITING");
+
+ ADP_LOCK();
+ openavbAdpSMAdvertiseInterfaceSet_rcvdDiscover(FALSE);
+ openavbAdpSMGlobalVars.entityInfo.pdu.available_index++;
+ ADP_UNLOCK();
+
+ // Wait for change in state
+ while (state == OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_WAITING && bRunning) {
+ U32 timeoutMSec;
+ struct timespec now;
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &now);
+ timeoutMSec = openavbTimeUntilMSec(&now, &openavbAdpSMAdvertiseEntityVars.reannounceTimerTimeout);
+
+ if (timeoutMSec == 0) {
+ /* No need to wait. */
+ state = OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_ADVERTISE;
+ }
+ else {
+ SEM_ERR_T(err);
+ SEM_TIMEDWAIT(openavbAdpSMAdvertiseEntitySemaphore, timeoutMSec, err);
+ if (!SEM_IS_ERR_NONE(err) && !SEM_IS_ERR_TIMEOUT(err)) { AVB_LOGF_WARNING("Semaphore error %d", err); }
+
+ if (openavbAdpSMAdvertiseEntityVars.doTerminate) {
+ bRunning = FALSE;
+ } else if (SEM_IS_ERR_TIMEOUT(err) ||
+ openavbAdpSMAdvertiseEntityVars.needsAdvertise) {
+ state = OPENAVB_ADP_SM_ADVERTISE_ENTITY_STATE_ADVERTISE;
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ AVB_LOG_ERROR("State: Unexpected!");
+ bRunning = FALSE; // Unexpected
+ break;
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void* openavbAdpSMAdvertiseEntityThreadFn(void *pv)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+ openavbAdpSMAdvertiseEntityStateMachine();
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+ return NULL;
+}
+
+void openavbAdpSMAdvertiseEntityStart()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ SEM_ERR_T(err);
+ SEM_INIT(openavbAdpSMAdvertiseEntitySemaphore, 1, err);
+ SEM_LOG_ERR(err);
+
+ ADP_LOCK();
+ openavbAdpSMAdvertiseEntityVars.needsAdvertise = FALSE;
+ openavbAdpSMAdvertiseEntityVars.doTerminate = FALSE;
+ ADP_UNLOCK();
+
+ // Start the Advertise Entity State Machine
+ bool errResult;
+ THREAD_CREATE(openavbAdpSmAdvertiseEntityThread, openavbAdpSmAdvertiseEntityThread, NULL, openavbAdpSMAdvertiseEntityThreadFn, NULL);
+ THREAD_CHECK_ERROR(openavbAdpSmAdvertiseEntityThread, "Thread / task creation failed", errResult);
+ if (errResult); // Already reported
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void openavbAdpSMAdvertiseEntityStop()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ openavbAdpSMAdvertiseEntitySet_doTerminate(TRUE);
+ THREAD_JOIN(openavbAdpSmAdvertiseEntityThread, NULL);
+
+ SEM_ERR_T(err);
+ SEM_DESTROY(openavbAdpSMAdvertiseEntitySemaphore, err);
+ SEM_LOG_ERR(err);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void openavbAdpSMAdvertiseEntitySet_needsAdvertise(bool value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ openavbAdpSMAdvertiseEntityVars.needsAdvertise = value;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAdpSMAdvertiseEntitySemaphore, err);
+ SEM_LOG_ERR(err);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void openavbAdpSMAdvertiseEntitySet_doTerminate(bool value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ openavbAdpSMAdvertiseEntityVars.doTerminate = value;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAdpSMAdvertiseEntitySemaphore, err);
+ SEM_LOG_ERR(err);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+
+
+
+
diff --git a/lib/avtp_pipeline/adp/openavb_adp_sm_advertise_entity.h b/lib/avtp_pipeline/adp/openavb_adp_sm_advertise_entity.h
new file mode 100644
index 00000000..97f20e39
--- /dev/null
+++ b/lib/avtp_pipeline/adp/openavb_adp_sm_advertise_entity.h
@@ -0,0 +1,63 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : ADP - AVDECC Discovery Protocol : Advertise Entity State Machine Interface
+ * MODULE SUMMARY : Interface for the AVDECC Discovery Protocol : Advertise Entity State Machine
+ * IEEE Std 1722.1-2013 clause 6.2.4.
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_ADP_SM_ADVERTISE_ENTITY_H
+#define OPENAVB_ADP_SM_ADVERTISE_ENTITY_H 1
+
+#include "openavb_adp.h"
+
+// State machine vars IEEE Std 1722.1-2013 clause 6.2.4.1
+typedef struct {
+ struct timespec reannounceTimerTimeout;
+ bool needsAdvertise;
+ bool doTerminate;
+} openavb_adp_sm_advertise_entity_vars_t;
+
+// State machine functions IEEE Std 1722.1-2013 clause 6.2.4.2
+void openavbAdpSMAdvertiseEntity_sendAvailable(void);
+
+void openavbAdpSMAdvertiseEntityStart(void);
+void openavbAdpSMAdvertiseEntityStop(void);
+
+// Accessors
+void openavbAdpSMAdvertiseEntitySet_needsAdvertise(bool value);
+void openavbAdpSMAdvertiseEntitySet_doTerminate(bool value);
+
+
+#endif // OPENAVB_ADP_SM_ADVERTISE_ENTITY_H
diff --git a/lib/avtp_pipeline/adp/openavb_adp_sm_advertise_interface.c b/lib/avtp_pipeline/adp/openavb_adp_sm_advertise_interface.c
new file mode 100644
index 00000000..1bc1f101
--- /dev/null
+++ b/lib/avtp_pipeline/adp/openavb_adp_sm_advertise_interface.c
@@ -0,0 +1,341 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : ADP - AVDECC Discovery Protocol : Advertise interface State Machine
+ * MODULE SUMMARY : Implements the AVDECC Discovery Protocol : Advertise Interface State Machine
+ * IEEE Std 1722.1-2013 clause 6.2.5.
+ *
+ * Note: 1722.1 allows for multiple Interface state machines,
+ * one per AVB Interface descriptor. This implementation
+ * assumes one AVB Interface descriptor exists in the Entity Model.
+ ******************************************************************
+ */
+
+#include "openavb_platform.h"
+
+#include <signal.h>
+
+#define AVB_LOG_COMPONENT "ADP"
+#include "openavb_log.h"
+
+#include "openavb_adp_sm_advertise_interface.h"
+#include "openavb_adp_sm_advertise_entity.h"
+#include "openavb_adp_message.h"
+
+#define OPENAVB_ADP_SM_ADVERTISE_INTERFACE_WAIT_TIME_USEC 10000
+
+typedef enum {
+ OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_INITIALIZE,
+ OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_WAITING,
+ OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_DEPARTING,
+ OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_ADVERTISE,
+ OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_RECEIVED_DISCOVER,
+ OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_UPDATE_GM,
+ OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_LINK_STATE_CHANGE,
+} openavb_adp_sm_advertise_interface_state_t;
+
+extern openavb_avdecc_cfg_t gAvdeccCfg;
+extern openavb_adp_sm_global_vars_t openavbAdpSMGlobalVars;
+extern openavb_adp_sm_advertise_entity_vars_t openavbAdpSMAdvertiseEntityVars;
+openavb_adp_sm_advertise_interface_vars_t openavbAdpSMAdvertiseInterfaceVars;
+
+extern MUTEX_HANDLE(openavbAdpMutex);
+#define ADP_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAdpMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define ADP_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAdpMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+SEM_T(openavbAdpSMAdvertiseInterfaceSemaphore);
+THREAD_TYPE(openavbAdpSmAdvertiseInterfaceThread);
+THREAD_DEFINITON(openavbAdpSmAdvertiseInterfaceThread);
+
+void openavbAdpSMAdvertiseInterface_txEntityAvailable()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+ ADP_LOCK();
+ openavbAdpSMGlobalVars.entityInfo.header.valid_time = gAvdeccCfg.valid_time;
+ ADP_UNLOCK();
+ openavbAdpMessageSend(OPENAVB_ADP_MESSAGE_TYPE_ENTITY_AVAILABLE);
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void openavbAdpSMAdvertiseInterface_txEntityDeparting()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+ ADP_LOCK();
+ openavbAdpSMGlobalVars.entityInfo.header.valid_time = 0;
+ ADP_UNLOCK();
+ openavbAdpMessageSend(OPENAVB_ADP_MESSAGE_TYPE_ENTITY_DEPARTING);
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void openavbAdpSMAdvertiseInterfaceStateMachine()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+ bool bRunning = TRUE;
+
+ openavb_adp_sm_advertise_interface_state_t state = OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_INITIALIZE;
+
+ while (bRunning) {
+ switch (state) {
+ case OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_INITIALIZE:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ADP);
+ AVB_LOG_DEBUG("State: OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_INITIALIZE");
+
+ ADP_LOCK();
+ openavbAdpSMAdvertiseInterfaceVars.lastLinkIsUp = FALSE;
+ openavbAdpSMAdvertiseInterfaceVars.doAdvertise = FALSE; // Per 1722.1 What's next notes
+ memcpy(openavbAdpSMAdvertiseInterfaceVars.advertisedGrandmasterID,
+ openavbAdpSMGlobalVars.entityInfo.pdu.gptp_grandmaster_id,
+ sizeof(openavbAdpSMGlobalVars.entityInfo.pdu.gptp_grandmaster_id));
+ ADP_UNLOCK();
+
+ // This interface will send the first advertisement on startup.
+ // The advertise entity will be responsible for sending subsequent advertisements.
+ // This allows the advertise entity and advertise interface to startup without any inter-dependencies.
+ state = OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_ADVERTISE;
+ }
+ break;
+ case OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_WAITING:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ADP);
+ AVB_LOG_DEBUG("State: OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_WAITING");
+
+ // openavbAdpSMAdvertiseInterfaceVars.rcvdDiscover = FALSE; // Per 1722.1 What's next notes. Note: setting this elsewhere otherwise incorrect behavior.
+ // openavbAdpSMGlobalVars.entityInfo.pdu.available_index++; // Per 1722.1 What's next notes
+
+ // Wait for a change in state
+ while (state == OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_WAITING && bRunning) {
+ SEM_ERR_T(err);
+ SEM_WAIT(openavbAdpSMAdvertiseInterfaceSemaphore, err);
+ if (!SEM_IS_ERR_NONE(err)) { AVB_LOGF_WARNING("Semaphore error %d", err); }
+
+ ADP_LOCK();
+ if (openavbAdpSMAdvertiseInterfaceVars.doTerminate)
+ state = OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_DEPARTING;
+ else if (openavbAdpSMAdvertiseInterfaceVars.doAdvertise)
+ state = OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_ADVERTISE;
+ else if (openavbAdpSMAdvertiseInterfaceVars.rcvdDiscover)
+ state = OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_RECEIVED_DISCOVER;
+ else if (memcmp(openavbAdpSMAdvertiseInterfaceVars.advertisedGrandmasterID,
+ openavbAdpSMGlobalVars.entityInfo.pdu.gptp_grandmaster_id,
+ sizeof(openavbAdpSMGlobalVars.entityInfo.pdu.gptp_grandmaster_id)))
+ state = OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_UPDATE_GM;
+ else if (openavbAdpSMAdvertiseInterfaceVars.lastLinkIsUp != openavbAdpSMAdvertiseInterfaceVars.linkIsUp)
+ state = OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_LINK_STATE_CHANGE;
+ ADP_UNLOCK();
+ }
+ }
+ break;
+ case OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_DEPARTING:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ADP);
+ AVB_LOG_DEBUG("State: OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_DEPARTING");
+
+ openavbAdpSMAdvertiseInterface_txEntityDeparting();
+ bRunning = FALSE;
+ }
+ break;
+ case OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_ADVERTISE:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ADP);
+ AVB_LOG_DEBUG("State: OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_ADVERTISE");
+
+ ADP_LOCK();
+ openavbAdpSMAdvertiseInterfaceVars.doAdvertise = FALSE; // Per 1722.1 What's next notes
+ ADP_UNLOCK();
+ openavbAdpSMAdvertiseInterface_txEntityAvailable();
+ state = OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_WAITING;
+ }
+ break;
+ case OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_RECEIVED_DISCOVER:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ADP);
+ AVB_LOG_DEBUG("State: OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_RECEIVED_DISCOVER");
+
+ ADP_LOCK();
+ openavbAdpSMAdvertiseInterfaceVars.rcvdDiscover = FALSE; // Not per spec but is needed.
+ if (((U64)*openavbAdpSMAdvertiseInterfaceVars.entityID == 0x0000000000000000L) ||
+ ((U64)*openavbAdpSMAdvertiseInterfaceVars.entityID == (U64)*openavbAdpSMGlobalVars.entityInfo.header.entity_id)) {
+ openavbAdpSMAdvertiseEntitySet_needsAdvertise(TRUE);
+ }
+ ADP_UNLOCK();
+ state = OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_WAITING;
+ }
+ break;
+ case OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_UPDATE_GM:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ADP);
+ AVB_LOG_DEBUG("State: OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_UPDATE_GM");
+
+ openavbAdpSMAdvertiseEntitySet_needsAdvertise(TRUE);
+ state = OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_WAITING;
+ }
+ break;
+ case OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_LINK_STATE_CHANGE:
+ {
+ AVB_TRACE_LINE(AVB_TRACE_ADP);
+ AVB_LOG_DEBUG("State: OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_LINK_STATE_CHANGE");
+
+ openavbAdpSMAdvertiseInterfaceVars.lastLinkIsUp = openavbAdpSMAdvertiseInterfaceVars.linkIsUp;
+ if (openavbAdpSMAdvertiseInterfaceVars.linkIsUp) {
+ openavbAdpSMAdvertiseEntitySet_needsAdvertise(TRUE);
+ }
+ state = OPENAVB_ADP_SM_ADVERTISE_INTERFACE_STATE_WAITING;
+ }
+ break;
+ default:
+ AVB_LOG_ERROR("State: Unexpected!");
+ bRunning = FALSE; // Unexpected
+ break;
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void* openavbAdpSMAdvertiseInterfaceThreadFn(void *pv)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+ openavbAdpSMAdvertiseInterfaceStateMachine();
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+ return NULL;
+}
+
+
+void openavbAdpSMAdvertiseInterfaceStart()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ SEM_ERR_T(err);
+ SEM_INIT(openavbAdpSMAdvertiseInterfaceSemaphore, 1, err);
+ SEM_LOG_ERR(err);
+
+ ADP_LOCK();
+ memset(&openavbAdpSMAdvertiseInterfaceVars, 0, sizeof(openavbAdpSMAdvertiseInterfaceVars));
+ ADP_UNLOCK();
+
+ // Start the Advertise Entity State Machine
+ bool errResult;
+ THREAD_CREATE(openavbAdpSmAdvertiseInterfaceThread, openavbAdpSmAdvertiseInterfaceThread, NULL, openavbAdpSMAdvertiseInterfaceThreadFn, NULL);
+ THREAD_CHECK_ERROR(openavbAdpSmAdvertiseInterfaceThread, "Thread / task creation failed", errResult);
+ if (errResult); // Already reported
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void openavbAdpSMAdvertiseInterfaceStop()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+
+ openavbAdpSMAdvertiseInterfaceSet_doTerminate(TRUE);
+ THREAD_JOIN(openavbAdpSmAdvertiseInterfaceThread, NULL);
+
+ SEM_ERR_T(err);
+ SEM_DESTROY(openavbAdpSMAdvertiseInterfaceSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void openavbAdpSMAdvertiseInterfaceSet_advertisedGrandmasterID(U8 *pValue)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+ if (pValue) {
+ memcpy(openavbAdpSMAdvertiseInterfaceVars.advertisedGrandmasterID, pValue, sizeof(openavbAdpSMAdvertiseInterfaceVars.advertisedGrandmasterID));
+ }
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAdpSMAdvertiseInterfaceSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void openavbAdpSMAdvertiseInterfaceSet_rcvdDiscover(bool value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+ openavbAdpSMAdvertiseInterfaceVars.rcvdDiscover = value;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAdpSMAdvertiseInterfaceSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void openavbAdpSMAdvertiseInterfaceSet_entityID(U8 *pValue)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+ if (pValue) {
+ memcpy(openavbAdpSMAdvertiseInterfaceVars.entityID, pValue, sizeof(openavbAdpSMAdvertiseInterfaceVars.entityID));
+ }
+ // sem post is done when the rcvdDiscover is set.
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void openavbAdpSMAdvertiseInterfaceSet_doTerminate(bool value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+ openavbAdpSMAdvertiseInterfaceVars.doTerminate = value;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAdpSMAdvertiseInterfaceSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void openavbAdpSMAdvertiseInterfaceSet_doAdvertise(bool value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+ openavbAdpSMAdvertiseInterfaceVars.doAdvertise = value;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAdpSMAdvertiseInterfaceSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+void openavbAdpSMAdvertiseInterfaceSet_linkIsUp(bool value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ADP);
+ openavbAdpSMAdvertiseInterfaceVars.linkIsUp = value;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAdpSMAdvertiseInterfaceSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ADP);
+}
+
+
diff --git a/lib/avtp_pipeline/adp/openavb_adp_sm_advertise_interface.h b/lib/avtp_pipeline/adp/openavb_adp_sm_advertise_interface.h
new file mode 100644
index 00000000..4c32b5f7
--- /dev/null
+++ b/lib/avtp_pipeline/adp/openavb_adp_sm_advertise_interface.h
@@ -0,0 +1,73 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : ADP - AVDECC Discovery Protocol : Advertise interface State Machine Interface
+ * MODULE SUMMARY : Interface for the AVDECC Discovery Protocol : Advertise Interface State Machine
+ * IEEE Std 1722.1-2013 clause 6.2.5.
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_ADP_SM_ADVERTISE_INTERFACE_H
+#define OPENAVB_ADP_SM_ADVERTISE_INTERFACE_H 1
+
+#include "openavb_adp.h"
+
+// State machine vars IEEE Std 1722.1-2013 clause 6.2.5.1
+typedef struct {
+ U8 advertisedGrandmasterID[8];
+ bool rcvdDiscover;
+ U8 entityID[8];
+ bool doTerminate;
+ bool doAdvertise;
+ bool linkIsUp;
+ bool lastLinkIsUp;
+} openavb_adp_sm_advertise_interface_vars_t;
+
+// State machine functions IEEE Std 1722.1-2013 clause 6.2.5.2
+void openavbAdpSMAdvertiseInterface_txEntityAvailable(void);
+void openavbAdpSMAdvertiseInterface_txEntityDeparting(void);
+
+void openavbAdpSMAdvertiseInterfaceStart(void);
+void openavbAdpSMAdvertiseInterfaceStop(void);
+
+// Accessors
+void openavbAdpSMAdvertiseInterfaceSet_advertisedGrandmasterID(U8 *pValue);
+void openavbAdpSMAdvertiseInterfaceSet_rcvdDiscover(bool value);
+void openavbAdpSMAdvertiseInterfaceSet_entityID(U8 *pValue);
+void openavbAdpSMAdvertiseInterfaceSet_doTerminate(bool value);
+void openavbAdpSMAdvertiseInterfaceSet_doAdvertise(bool value);
+void openavbAdpSMAdvertiseInterfaceSet_linkIsUp(bool value);
+
+
+
+#endif // OPENAVB_ADP_SM_ADVERTISE_INTERFACE_H
diff --git a/lib/avtp_pipeline/adp/openavb_adp_sm_discovery.c b/lib/avtp_pipeline/adp/openavb_adp_sm_discovery.c
new file mode 100644
index 00000000..b4c1390a
--- /dev/null
+++ b/lib/avtp_pipeline/adp/openavb_adp_sm_discovery.c
@@ -0,0 +1,45 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : ADP - AVDECC Discovery Protocol : Discovery State Machine
+ * MODULE SUMMARY : Implements the AVDECC Discovery Protocol : Discovery State Machine
+ * IEEE Std 1722.1-2013 clause 6.2.6.
+ ******************************************************************
+ */
+
+// Not implemented in OPENAVB phase 1 support of 1722.1
+
+#define AVB_LOG_COMPONENT "ADP"
+#include "openavb_log.h"
+
+#include "openavb_adp_sm_discovery.h"
diff --git a/lib/avtp_pipeline/adp/openavb_adp_sm_discovery.h b/lib/avtp_pipeline/adp/openavb_adp_sm_discovery.h
new file mode 100644
index 00000000..7c6cb8be
--- /dev/null
+++ b/lib/avtp_pipeline/adp/openavb_adp_sm_discovery.h
@@ -0,0 +1,48 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : ADP - AVDECC Discovery Protocol : Discovery State Machine Interface
+ * MODULE SUMMARY : Interface for the Implements the AVDECC Discovery Protocol : Discovery State Machine
+ * IEEE Std 1722.1-2013 clause 6.2.6.
+ ******************************************************************
+ */
+
+// Not implemented in OPENAVB phase 1 support of 1722.1
+
+#ifndef OPENAVB_ADP_SM_DISCOVERY_H
+#define OPENAVB_ADP_SM_DISCOVERY_H 1
+
+#include "openavb_adp.h"
+
+
+#endif // OPENAVB_ADP_SM_DISCOVERY_H
diff --git a/lib/avtp_pipeline/aecp/CMakeLists.txt b/lib/avtp_pipeline/aecp/CMakeLists.txt
new file mode 100644
index 00000000..ae4bb6e9
--- /dev/null
+++ b/lib/avtp_pipeline/aecp/CMakeLists.txt
@@ -0,0 +1,8 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/aecp/openavb_aecp.c
+ ${AVB_SRC_DIR}/aecp/openavb_aecp_message.c
+ ${AVB_SRC_DIR}/aecp/openavb_aecp_sm_entity_model_entity.c
+ ${AVB_SRC_DIR}/aecp/openavb_aecp_cmd_get_counters.c
+ PARENT_SCOPE
+)
+
diff --git a/lib/avtp_pipeline/aecp/openavb_aecp.c b/lib/avtp_pipeline/aecp/openavb_aecp.c
new file mode 100644
index 00000000..c87be0de
--- /dev/null
+++ b/lib/avtp_pipeline/aecp/openavb_aecp.c
@@ -0,0 +1,98 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AVDECC Enumeration and control protocol (AECP)
+ * MODULE SUMMARY : Implements the AVDECC Enumeration and control protocol (AECP)
+ ******************************************************************
+ */
+
+#include "openavb_platform.h"
+
+#include <signal.h>
+
+#define AVB_LOG_COMPONENT "AECP"
+#include "openavb_log.h"
+
+#include "openavb_aem.h"
+#include "openavb_aecp.h"
+#include "openavb_aecp_sm_entity_model_entity.h"
+#include "openavb_aecp_message.h"
+
+openavb_aecp_sm_global_vars_t openavbAecpSMGlobalVars;
+
+MUTEX_HANDLE(openavbAecpMutex);
+#define ADP_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAecpMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define ADP_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAecpMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+openavbRC openavbAecpStart()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ openavb_avdecc_entity_model_t *pAem = openavbAemGetModel();
+ if (!pAem) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_ENTITY_MODEL_MISSING), AVB_TRACE_AECP);
+ }
+
+ MUTEX_ATTR_HANDLE(mta);
+ MUTEX_ATTR_INIT(mta);
+ MUTEX_ATTR_SET_TYPE(mta, MUTEX_ATTR_TYPE_DEFAULT);
+ MUTEX_ATTR_SET_NAME(mta, "openavbAecpMutex");
+ MUTEX_CREATE_ERR();
+ MUTEX_CREATE(openavbAecpMutex, mta);
+ MUTEX_LOG_ERR("Could not create/initialize 'openavbAecpMutex' mutex");
+
+ // Set AECP global vars
+ memcpy(openavbAecpSMGlobalVars.myEntityID, pAem->pDescriptorEntity->entity_id, sizeof(openavbAecpSMGlobalVars.myEntityID));
+
+ openavbRC rc = openavbAecpMessageHandlerStart();
+ if (IS_OPENAVB_FAILURE(rc)) {
+ openavbAecpStop();
+ AVB_RC_TRACE_RET(rc, AVB_TRACE_AECP);
+ }
+
+ openavbAecpSMEntityModelEntityStart();
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AECP);
+}
+
+void openavbAecpStop()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ openavbAecpSMEntityModelEntityStop();
+ openavbAecpMessageHandlerStop();
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
+
+
diff --git a/lib/avtp_pipeline/aecp/openavb_aecp.h b/lib/avtp_pipeline/aecp/openavb_aecp.h
new file mode 100644
index 00000000..cdd57b70
--- /dev/null
+++ b/lib/avtp_pipeline/aecp/openavb_aecp.h
@@ -0,0 +1,408 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AVDECC Enumeration and control protocol (AECP)
+ * MODULE SUMMARY : Interface for the AVDECC Enumeration and control protocol (AECP)
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_AECP_H
+#define OPENAVB_AECP_H 1
+
+#include "openavb_avdecc.h"
+#include "openavb_aecp_pub.h"
+
+#define OPENAVB_AECP_AVTP_SUBTYPE (0x7b)
+
+// message_type field IEEE Std 1722.1-2013 clause 9.2.1.1.5
+#define OPENAVB_AECP_MESSAGE_TYPE_AEM_COMMAND (0)
+#define OPENAVB_AECP_MESSAGE_TYPE_AEM_RESPONSE (1)
+#define OPENAVB_AECP_MESSAGE_TYPE_ADDRESS_ACCESS_COMMAND (2)
+#define OPENAVB_AECP_MESSAGE_TYPE_ADDRESS_ACCESS_RESPONSE (3)
+#define OPENAVB_AECP_MESSAGE_TYPE_AVC_COMMAND (4)
+#define OPENAVB_AECP_MESSAGE_TYPE_AVC_RESPONSE (5)
+#define OPENAVB_AECP_MESSAGE_TYPE_VENDOR_UNIQUE_COMMAND (6)
+#define OPENAVB_AECP_MESSAGE_TYPE_VENDOR_UNIQUE_RESPONSE (7)
+#define OPENAVB_AECP_MESSAGE_TYPE_HDCP_APM_COMMAND (8)
+#define OPENAVB_AECP_MESSAGE_TYPE_HDCP_APM_RESPONSE (9)
+#define OPENAVB_AECP_MESSAGE_TYPE_EXTENDED_COMMAND (14)
+#define OPENAVB_AECP_MESSAGE_TYPE_EXTENDED_RESPONSE (15)
+
+// status field IEEE Std 1722.1-2013 clause 9.2.1.1.6
+#define OPENAVB_AECP_STATUS_SUCCESS (0)
+#define OPENAVB_AECP_STATUS_NOT_IMPLEMENTED (1)
+
+typedef struct {
+ U8 cd;
+ U8 subtype;
+ U8 sv;
+ U8 version;
+ U8 message_type; // Redefined from control data
+ U8 status;
+ U16 control_data_length;
+ U8 target_entity_id[8]; // Redefined from stream_id
+} openavb_aecp_control_header_t;
+
+typedef struct {
+ U8 controller_entity_id[8];
+ U16 sequence_id;
+} openavb_aecp_common_data_unit_t;
+
+typedef struct {
+ U32 flags;
+ U8 owner_id[8];
+ U16 descriptor_type;
+ U16 descriptor_index;
+} openavb_aecp_command_data_acquire_entity_t;
+
+typedef struct {
+ // No command specific data
+} openavb_aecp_commandresponse_data_lock_entity_t;
+
+typedef struct {
+ // No command specific data
+} openavb_aecp_commandresponse_data_entity_available_t;
+
+typedef struct {
+ // No command specific data
+} openavb_aecp_commandresponse_data_controller_available_t;
+
+typedef struct {
+ U16 configuration_index;
+ U16 reserved;
+ U16 descriptor_type;
+ U16 descriptor_index;
+} openavb_aecp_command_data_read_descriptor_t;
+
+typedef struct {
+ U16 configuration_index;
+ U16 reserved;
+ U16 descriptor_length;
+ U8 descriptor_data[508];
+} openavb_aecp_response_data_read_descriptor_t;
+
+// SET_STREAM_FORMAT command and response IEEE Std 1722.1-2013 clause 7.4.9
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+ U8 stream_format[8]; // Stream format sub details aren't needed for this command
+} openavb_aecp_commandresponse_data_set_stream_format_t;
+
+// GET_STREAM_FORMAT command IEEE Std 1722.1-2013 clause 7.4.10
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+} openavb_aecp_command_data_get_stream_format_t;
+
+// GET_STREAM_FORMAT response IEEE Std 1722.1-2013 clause 7.4.10
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+ U8 stream_format[8]; // Stream format sub details aren't needed for this command
+} openavb_aecp_response_data_get_stream_format_t;
+
+// SET_STREAM_INFO command and response IEEE Std 1722.1-2013 clause 7.4.15
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+ U32 flags;
+ U8 stream_format[8];
+ U8 stream_id[8];
+ U32 msrp_accumulated_latency;
+ U8 stream_dest_mac[6];
+ U8 msrp_failure_code;
+ U8 reserved_1;
+ U8 msrp_failure_bridge_id[8];
+ U16 stream_vlan_id;
+ U16 reserved_2;
+} openavb_aecp_commandresponse_data_set_stream_info_t;
+
+// GET_STREAM_INFO command IEEE Std 1722.1-2013 clause 7.4.16
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+} openavb_aecp_command_data_get_stream_info_t;
+
+// GET_STREAM_INFO response IEEE Std 1722.1-2013 clause 7.4.16
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+ U32 flags;
+ U8 stream_format[8];
+ U8 stream_id[8];
+ U32 msrp_accumulated_latency;
+ U8 stream_dest_mac[6];
+ U8 msrp_failure_code;
+ U8 reserved_1;
+ U8 msrp_failure_bridge_id[8];
+ U16 stream_vlan_id;
+ U16 reserved_2;
+} openavb_aecp_response_data_get_stream_info_t;
+
+// SET_SAMPLING_RATE command and response IEEE Std 1722.1-2013 clause 7.4.21
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+ U8 sampling_rate[4]; // Sampling rate format sub details aren't needed for this command
+} openavb_aecp_commandresponse_data_set_sampling_rate_t;
+
+// GET_SAMPLING_RATE command IEEE Std 1722.1-2013 clause 7.4.22
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+} openavb_aecp_command_data_get_sampling_rate_t;
+
+// GET_SAMPLING_RATE response IEEE Std 1722.1-2013 clause 7.4.22
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+ U8 sampling_rate[4]; // Sampling rate format sub details aren't needed for this command
+} openavb_aecp_response_data_get_sampling_rate_t;
+
+// SET_CLOCK_SOURCE command and response IEEE Std 1722.1-2013 clause 7.4.23
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+ U16 clock_source_index;
+ U16 reserved;
+} openavb_aecp_commandresponse_data_set_clock_source_t;
+
+// GET_CLOCK_SOURCE command IEEE Std 1722.1-2013 clause 7.4.24
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+} openavb_aecp_command_data_get_clock_source_t;
+
+// GET_CLOCK_SOURCE response IEEE Std 1722.1-2013 clause 7.4.24
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+ U16 clock_source_index;
+ U16 reserved;
+} openavb_aecp_response_data_get_clock_source_t;
+
+// SET_CONTROL command and response IEEE Std 1722.1-2013 clause 7.4.25
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+ union {
+ S8 linear_int8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT8];
+ U8 linear_uint8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT8];
+ S16 linear_int16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT16];
+ U16 linear_uint16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT16];
+ S32 linear_int32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT32];
+ U32 linear_uint32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT32];
+ S64 linear_int64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT64];
+ U64 linear_uint64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT64];
+ float linear_float[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_FLOAT];
+ double linear_double[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_DOUBLE];
+ // AVDECC_TODO : These aren't implemented in the CONTROl descriptor yet.
+ //selector_int8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT8];
+ //selector_uint8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT8];
+ //selector_int16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT16];
+ //selector_uint16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT16];
+ //selector_int32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT32];
+ //selector_uint32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT32];
+ //selector_int64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT64];
+ //selector_uint64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT64];
+ //selector_float[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_FLOAT];
+ //selector_double[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_DOUBLE];
+ //selector_string[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_STRING];
+ //array_int8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT8];
+ //array_uint8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT8];
+ //array_int16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT16];
+ //array_uint16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT16];
+ //array_int32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT32];
+ //array_uint32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT32];
+ //array_int64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT64];
+ //array_uint64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT64];
+ //array_float[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_FLOAT];
+ //array_double[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_DOUBLE];
+ //utf8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_UTF8];
+ //bode_plot[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_BODE_PLOT];
+ //smpte_time[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SMPTE_TIME];
+ //sample_rate[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SAMPLE_RATE];
+ //gptp_time[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_GPTP_TIME];
+ //vendor[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_VENDOR];
+ } values;
+
+ U16 valuesCount; // Not part of spec. Used to track elements in arrays.
+} openavb_aecp_commandresponse_data_set_control_t;
+
+// GET_CONTROL command IEEE Std 1722.1-2013 clause 7.4.26
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+} openavb_aecp_command_data_get_control_t;
+
+// GET_CONTROL response IEEE Std 1722.1-2013 clause 7.4.26
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+ union {
+ S8 linear_int8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT8];
+ U8 linear_uint8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT8];
+ S16 linear_int16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT16];
+ U16 linear_uint16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT16];
+ S32 linear_int32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT32];
+ U32 linear_uint32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT32];
+ S64 linear_int64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT64];
+ U64 linear_uint64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT64];
+ float linear_float[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_FLOAT];
+ double linear_double[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_DOUBLE];
+ // AVDECC_TODO : These aren't implemented in the CONTROl descriptor yet.
+ //selector_int8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT8];
+ //selector_uint8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT8];
+ //selector_int16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT16];
+ //selector_uint16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT16];
+ //selector_int32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT32];
+ //selector_uint32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT32];
+ //selector_int64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT64];
+ //selector_uint64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT64];
+ //selector_float[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_FLOAT];
+ //selector_double[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_DOUBLE];
+ //selector_string[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_STRING];
+ //array_int8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT8];
+ //array_uint8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT8];
+ //array_int16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT16];
+ //array_uint16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT16];
+ //array_int32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT32];
+ //array_uint32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT32];
+ //array_int64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT64];
+ //array_uint64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT64];
+ //array_float[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_FLOAT];
+ //array_double[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_DOUBLE];
+ //utf8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_UTF8];
+ //bode_plot[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_BODE_PLOT];
+ //smpte_time[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SMPTE_TIME];
+ //sample_rate[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SAMPLE_RATE];
+ //gptp_time[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_GPTP_TIME];
+ //vendor[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_VENDOR];
+ } values;
+
+ U16 valuesCount; // Not part of spec. Used to track elements in arrays.
+} openavb_aecp_response_data_get_control_t;
+
+// START_STREAMING command and response IEEE Std 1722.1-2013 clause 7.4.35
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+} openavb_aecp_commandresponse_data_start_streaming_t;
+
+// STOP_STREAMING command and response IEEE Std 1722.1-2013 clause 7.4.36
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+} openavb_aecp_commandresponse_data_stop_streaming_t;
+
+// GET_COUNTERS command IEEE Std 1722.1-2013 clause 7.4.42
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+} openavb_aecp_command_data_get_counters_t;
+
+// GET_COUNTERS response IEEE Std 1722.1-2013 clause 7.4.42
+typedef struct {
+ U16 descriptor_type;
+ U16 descriptor_index;
+ U32 counters_valid;
+ U16 counters_block_length;
+ U8 counters_block[128];
+} openavb_aecp_response_data_get_counters_t;
+
+
+typedef struct {
+ U8 u;
+ U16 command_type;
+ union {
+ openavb_aecp_command_data_acquire_entity_t acquireEntityCmd;
+ openavb_aecp_command_data_acquire_entity_t acquireEntityRsp;
+ openavb_aecp_commandresponse_data_lock_entity_t lockEntityCmd;
+ openavb_aecp_commandresponse_data_lock_entity_t lockEntityRsp;
+ openavb_aecp_commandresponse_data_entity_available_t entityAvailableCmd;
+ openavb_aecp_commandresponse_data_entity_available_t entityAvailableRsp;
+ openavb_aecp_commandresponse_data_controller_available_t controllerAvailableCmd;
+ openavb_aecp_commandresponse_data_controller_available_t controllerAvailableRsp;
+ openavb_aecp_command_data_read_descriptor_t readDescriptorCmd;
+ openavb_aecp_response_data_read_descriptor_t readDescriptorRsp;
+ openavb_aecp_commandresponse_data_set_stream_format_t setStreamFormatCmd;
+ openavb_aecp_commandresponse_data_set_stream_format_t setStreamFormatRsp;
+ openavb_aecp_command_data_get_stream_format_t getStreamFormatCmd;
+ openavb_aecp_response_data_get_stream_format_t getStreamFormatRsp;
+ openavb_aecp_commandresponse_data_set_stream_info_t setStreamInfoCmd;
+ openavb_aecp_commandresponse_data_set_stream_info_t setStreamInfoRsp;
+ openavb_aecp_command_data_get_stream_info_t getStreamInfoCmd;
+ openavb_aecp_response_data_get_stream_info_t getStreamInfoRsp;
+ openavb_aecp_commandresponse_data_set_sampling_rate_t setSamplingRateCmd;
+ openavb_aecp_commandresponse_data_set_sampling_rate_t setSamplingRateRsp;
+ openavb_aecp_command_data_get_sampling_rate_t getSamplingRateCmd;
+ openavb_aecp_response_data_get_sampling_rate_t getSamplingRateRsp;
+ openavb_aecp_commandresponse_data_set_clock_source_t setClockSourceCmd;
+ openavb_aecp_commandresponse_data_set_clock_source_t setClockSourceRsp;
+ openavb_aecp_command_data_get_clock_source_t getClockSourceCmd;
+ openavb_aecp_response_data_get_clock_source_t getClockSourceRsp;
+ openavb_aecp_commandresponse_data_set_control_t setControlCmd;
+ openavb_aecp_commandresponse_data_set_control_t setControlRsp;
+ openavb_aecp_command_data_get_control_t getControlCmd;
+ openavb_aecp_response_data_get_control_t getControlRsp;
+ openavb_aecp_commandresponse_data_start_streaming_t startStreamingCmd;
+ openavb_aecp_commandresponse_data_start_streaming_t startStreamingRsp;
+ openavb_aecp_commandresponse_data_stop_streaming_t stopStreamingCmd;
+ openavb_aecp_commandresponse_data_stop_streaming_t stopStreamingRsp;
+ openavb_aecp_command_data_get_counters_t getCountersCmd;
+ openavb_aecp_response_data_get_counters_t getCountersRsp;
+ } command_data;
+} openavb_aecp_entity_model_data_unit_t;
+
+typedef struct {
+ openavb_aecp_common_data_unit_t commonPdu;
+ openavb_aecp_entity_model_data_unit_t entityModelPdu;
+} openavb_aecp_data_unit_t;
+
+// IEEE Std 1722.1-2013 clause 9.2.2.3.1.1.1
+typedef struct {
+ U8 host[ETH_ALEN];
+ openavb_aecp_control_header_t headers;
+ openavb_aecp_common_data_unit_t commonPdu;
+ openavb_aecp_entity_model_data_unit_t entityModelPdu;
+} openavb_aecp_AEMCommandResponse_t;
+
+// IEEE Std 1722.1-2013 clause 9.2.2.3.1.2.3
+typedef struct {
+ U8 myEntityID[8];
+} openavb_aecp_sm_global_vars_t;
+
+openavbRC openavbAecpStart(void);
+void openavbAecpStop(void);
+
+#endif // OPENAVB_AECP_H
diff --git a/lib/avtp_pipeline/aecp/openavb_aecp_cmd_get_counters.c b/lib/avtp_pipeline/aecp/openavb_aecp_cmd_get_counters.c
new file mode 100644
index 00000000..756f7bbc
--- /dev/null
+++ b/lib/avtp_pipeline/aecp/openavb_aecp_cmd_get_counters.c
@@ -0,0 +1,223 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#include "openavb_platform.h"
+
+#include <errno.h>
+
+#define AVB_LOG_COMPONENT "AECP"
+#include "openavb_log.h"
+
+#include "openavb_aem.h"
+#include "openavb_aecp.h"
+#include "openavb_aecp_message.h"
+#include "openavb_aecp_cmd_get_counters.h"
+#include "openavb_avdecc_pipeline_interaction_pub.h"
+
+
+static void GetEntitySpecificCounters(void * pDescriptor, U16 descriptorType, openavb_aecp_response_data_get_counters_t *pRsp)
+{
+ U32 retValue;
+
+ // Code assumes that ENTITY_SPECIFIC flags and offsets are the same regardless of the Descriptor Type.
+ if (openavbAVDECCGetCounterValue(pDescriptor, descriptorType, OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_1, &retValue)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_1;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_1]) = htonl(retValue);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptor, descriptorType, OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_2, &retValue)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_2;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_2]) = htonl(retValue);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptor, descriptorType, OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_3, &retValue)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_3;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_3]) = htonl(retValue);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptor, descriptorType, OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_4, &retValue)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_4;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_4]) = htonl(retValue);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptor, descriptorType, OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_5, &retValue)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_5;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_5]) = htonl(retValue);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptor, descriptorType, OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_6, &retValue)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_6;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_6]) = htonl(retValue);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptor, descriptorType, OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_7, &retValue)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_7;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_7]) = htonl(retValue);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptor, descriptorType, OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_8, &retValue)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_8;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_8]) = htonl(retValue);
+ }
+}
+
+U8 openavbAecpCommandGetCountersHandler(
+ openavb_aecp_command_data_get_counters_t *pCmd,
+ openavb_aecp_response_data_get_counters_t *pRsp )
+{
+ U8 result = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+ U32 value = 0;
+
+ if (!pCmd || !pRsp) {
+ return OPENAVB_AEM_COMMAND_STATUS_NO_RESOURCES;
+ }
+
+ // Default to no counters.
+ pRsp->counters_valid = 0;
+ pRsp->counters_block_length = 128;
+ memset(pRsp->counters_block, 0, sizeof(pRsp->counters_block));
+
+ if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_ENTITY) {
+ openavb_aem_descriptor_entity_t *pDescriptorEntity = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorEntity) {
+ // Get the supported counter values.
+ GetEntitySpecificCounters(pDescriptorEntity, OPENAVB_AEM_DESCRIPTOR_ENTITY, pRsp);
+
+ result = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ }
+ else if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_AVB_INTERFACE) {
+ openavb_aem_descriptor_avb_interface_t *pDescriptorAvbInterface = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorAvbInterface) {
+ // Get the supported counter values.
+ if (openavbAVDECCGetCounterValue(pDescriptorAvbInterface, OPENAVB_AEM_DESCRIPTOR_AVB_INTERFACE, OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_LINK_UP, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_LINK_UP;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_LINK_UP]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorAvbInterface, OPENAVB_AEM_DESCRIPTOR_AVB_INTERFACE, OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_LINK_DOWN, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_LINK_DOWN;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_LINK_DOWN]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorAvbInterface, OPENAVB_AEM_DESCRIPTOR_AVB_INTERFACE, OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_FRAMES_TX, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_FRAMES_TX;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_FRAMES_TX]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorAvbInterface, OPENAVB_AEM_DESCRIPTOR_AVB_INTERFACE, OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_FRAMES_RX, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_FRAMES_RX;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_FRAMES_RX]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorAvbInterface, OPENAVB_AEM_DESCRIPTOR_AVB_INTERFACE, OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_RX_CRC_ERROR, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_RX_CRC_ERROR;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_RX_CRC_ERROR]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorAvbInterface, OPENAVB_AEM_DESCRIPTOR_AVB_INTERFACE, OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_GPTP_GM_CHANGED, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_GPTP_GM_CHANGED;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_GPTP_GM_CHANGED]) = htonl(value);
+ }
+ GetEntitySpecificCounters(pDescriptorAvbInterface, OPENAVB_AEM_DESCRIPTOR_AVB_INTERFACE, pRsp);
+
+ result = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ }
+ else if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_CLOCK_DOMAIN) {
+ openavb_aem_descriptor_clock_domain_t *pDescriptorClockDomain = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorClockDomain) {
+ // Get the supported counter values.
+ if (openavbAVDECCGetCounterValue(pDescriptorClockDomain, OPENAVB_AEM_DESCRIPTOR_CLOCK_DOMAIN, OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_LOCKED, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_LOCKED;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_OFFSET_LOCKED]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorClockDomain, OPENAVB_AEM_DESCRIPTOR_CLOCK_DOMAIN, OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_UNLOCKED, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_UNLOCKED;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_OFFSET_UNLOCKED]) = htonl(value);
+ }
+ GetEntitySpecificCounters(pDescriptorClockDomain, OPENAVB_AEM_DESCRIPTOR_CLOCK_DOMAIN, pRsp);
+
+ result = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ }
+ else if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT) {
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorStreamInput) {
+ // Get the supported counter values.
+ if (openavbAVDECCGetCounterValue(pDescriptorStreamInput, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_MEDIA_LOCKED, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_MEDIA_LOCKED;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_MEDIA_LOCKED]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorStreamInput, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_MEDIA_UNLOCKED, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_MEDIA_UNLOCKED;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_MEDIA_UNLOCKED]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorStreamInput, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_STREAM_RESET, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_STREAM_RESET;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_STREAM_RESET]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorStreamInput, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_SEQ_NUM_MISMATCH, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_SEQ_NUM_MISMATCH;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_SEQ_NUM_MISMATCH]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorStreamInput, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_MEDIA_RESET, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_MEDIA_RESET;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_MEDIA_RESET]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorStreamInput, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_TIMESTAMP_UNCERTAIN, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_TIMESTAMP_UNCERTAIN;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_TIMESTAMP_UNCERTAIN]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorStreamInput, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_TIMESTAMP_VALID, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_TIMESTAMP_VALID;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_TIMESTAMP_VALID]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorStreamInput, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_TIMESTAMP_NOT_VALID, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_TIMESTAMP_NOT_VALID;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_TIMESTAMP_NOT_VALID]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorStreamInput, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_UNSUPPORTED_FORMAT, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_UNSUPPORTED_FORMAT;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_UNSUPPORTED_FORMAT]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorStreamInput, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_LATE_TIMESTAMP, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_LATE_TIMESTAMP;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_LATE_TIMESTAMP]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorStreamInput, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_EARLY_TIMESTAMP, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_EARLY_TIMESTAMP;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_EARLY_TIMESTAMP]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorStreamInput, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_FRAMES_RX, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_FRAMES_RX;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_FRAMES_RX]) = htonl(value);
+ }
+ if (openavbAVDECCGetCounterValue(pDescriptorStreamInput, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_FRAMES_TX, &value)) {
+ pRsp->counters_valid |= OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_FRAMES_TX;
+ *(U32 *)&(pRsp->counters_block[OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_FRAMES_TX]) = htonl(value);
+ }
+ GetEntitySpecificCounters(pDescriptorStreamInput, OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, pRsp);
+
+ result = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ }
+
+ return result;
+}
diff --git a/lib/avtp_pipeline/aecp/openavb_aecp_cmd_get_counters.h b/lib/avtp_pipeline/aecp/openavb_aecp_cmd_get_counters.h
new file mode 100644
index 00000000..777940a6
--- /dev/null
+++ b/lib/avtp_pipeline/aecp/openavb_aecp_cmd_get_counters.h
@@ -0,0 +1,103 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#ifndef OPENAVB_AECP_CMD_GET_COUNTERS_H
+#define OPENAVB_AECP_CMD_GET_COUNTERS_H 1
+
+#include "openavb_aecp.h"
+
+// GET_COUNTERS Command ENTITY Counter offsets IEEE Std 1722.1-2013 clause 7.4.42
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_8 (96)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_7 (100)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_6 (104)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_5 (108)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_4 (112)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_3 (116)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_2 (120)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_OFFSET_ENTITY_SPECIFIC_1 (124)
+
+// GET_COUNTERS Command AVB_INTERFACE Counter offsets IEEE Std 1722.1-2013 clause 7.4.42
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_LINK_UP (0)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_LINK_DOWN (4)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_FRAMES_TX (8)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_FRAMES_RX (12)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_RX_CRC_ERROR (16)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_GPTP_GM_CHANGED (20)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_ENTITY_SPECIFIC_8 (96)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_ENTITY_SPECIFIC_7 (100)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_ENTITY_SPECIFIC_6 (104)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_ENTITY_SPECIFIC_5 (108)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_ENTITY_SPECIFIC_4 (112)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_ENTITY_SPECIFIC_3 (116)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_ENTITY_SPECIFIC_2 (120)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_OFFSET_ENTITY_SPECIFIC_1 (124)
+
+// GET_COUNTERS Command CLOCK_DOMAIN Counter offsets IEEE Std 1722.1-2013 clause 7.4.42
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_OFFSET_LOCKED (0)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_OFFSET_UNLOCKED (4)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_OFFSET_ENTITY_SPECIFIC_8 (96)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_OFFSET_ENTITY_SPECIFIC_7 (100)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_OFFSET_ENTITY_SPECIFIC_6 (104)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_OFFSET_ENTITY_SPECIFIC_5 (108)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_OFFSET_ENTITY_SPECIFIC_4 (112)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_OFFSET_ENTITY_SPECIFIC_3 (116)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_OFFSET_ENTITY_SPECIFIC_2 (120)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_OFFSET_ENTITY_SPECIFIC_1 (124)
+
+// GET_COUNTERS Command STREAM_INPUT Counter offsets IEEE Std 1722.1-2013 clause 7.4.42
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_MEDIA_LOCKED (0)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_MEDIA_UNLOCKED (4)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_STREAM_RESET (8)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_SEQ_NUM_MISMATCH (12)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_MEDIA_RESET (16)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_TIMESTAMP_UNCERTAIN (20)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_TIMESTAMP_VALID (24)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_TIMESTAMP_NOT_VALID (28)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_UNSUPPORTED_FORMAT (32)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_LATE_TIMESTAMP (36)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_EARLY_TIMESTAMP (40)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_FRAMES_RX (44)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_FRAMES_TX (48)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_ENTITY_SPECIFIC_8 (96)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_ENTITY_SPECIFIC_7 (100)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_ENTITY_SPECIFIC_6 (104)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_ENTITY_SPECIFIC_5 (108)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_ENTITY_SPECIFIC_4 (112)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_ENTITY_SPECIFIC_3 (116)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_ENTITY_SPECIFIC_2 (120)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_OFFSET_ENTITY_SPECIFIC_1 (124)
+
+
+U8 openavbAecpCommandGetCountersHandler(
+ openavb_aecp_command_data_get_counters_t *pCmd,
+ openavb_aecp_response_data_get_counters_t *pRsp );
+
+#endif // OPENAVB_AECP_CMD_GET_COUNTERS_H
diff --git a/lib/avtp_pipeline/aecp/openavb_aecp_message.c b/lib/avtp_pipeline/aecp/openavb_aecp_message.c
new file mode 100644
index 00000000..b2e55bee
--- /dev/null
+++ b/lib/avtp_pipeline/aecp/openavb_aecp_message.c
@@ -0,0 +1,1049 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AVDECC Enumeration and control protocol (AECP) Message Handler
+ * MODULE SUMMARY : Implements the AVDECC Enumeration and control protocol (AECP) message handler
+ ******************************************************************
+ */
+
+#include "openavb_platform.h"
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#define AVB_LOG_COMPONENT "AECP"
+#include "openavb_log.h"
+
+#include "openavb_debug.h"
+#include "openavb_rawsock.h"
+#include "openavb_avtp.h"
+#include "openavb_srp.h"
+#include "openavb_aecp.h"
+#include "openavb_aecp_sm_entity_model_entity.h"
+
+#define INVALID_SOCKET (-1)
+
+// message length
+#define AVTP_HDR_LEN 12
+#define AECP_DATA_LEN 1480 // AVDECC_TODO - Need to figure out a valid length
+#define AECP_FRAME_LEN (ETH_HDR_LEN_VLAN + AVTP_HDR_LEN + AECP_DATA_LEN)
+
+// number of buffers (arbitrary, and rounded up by rawsock)
+#define AECP_NUM_BUFFERS 3
+
+// do cast from ether_addr to U8*
+#define ADDR_PTR(A) (U8*)(&((A)->ether_addr_octet))
+
+extern openavb_avdecc_cfg_t gAvdeccCfg;
+
+static void *rxSock = NULL;
+static void *txSock = NULL;
+static struct ether_addr intfAddr;
+
+extern openavb_aecp_sm_global_vars_t openavbAecpSMGlobalVars;
+
+THREAD_TYPE(openavbAecpMessageRxThread);
+THREAD_DEFINITON(openavbAecpMessageRxThread);
+
+static bool bRunning = FALSE;
+
+void openavbAecpCloseSocket()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ if (rxSock) {
+ openavbRawsockClose(rxSock);
+ rxSock = NULL;
+ }
+ if (txSock) {
+ openavbRawsockClose(txSock);
+ txSock = NULL;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
+
+bool openavbAecpOpenSocket(const char* ifname, U16 vlanID, U8 vlanPCP)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ hdr_info_t hdr;
+
+#ifndef UBUNTU
+ // This is the normal case for most of our supported platforms
+ rxSock = openavbRawsockOpen(ifname, TRUE, FALSE, ETHERTYPE_8021Q, AECP_FRAME_LEN, AECP_NUM_BUFFERS);
+#else
+ rxSock = openavbRawsockOpen(ifname, TRUE, FALSE, ETHERTYPE_AVTP, AECP_FRAME_LEN, AECP_NUM_BUFFERS);
+#endif
+ txSock = openavbRawsockOpen(ifname, FALSE, TRUE, ETHERTYPE_AVTP, AECP_FRAME_LEN, AECP_NUM_BUFFERS);
+
+ if (txSock && rxSock
+ && openavbRawsockGetAddr(txSock, ADDR_PTR(&intfAddr))
+ && openavbRawsockRxMulticast(rxSock, TRUE, ADDR_PTR(&intfAddr))) // Only accept packets sent directly to this interface
+ {
+ if (!openavbRawsockRxAVTPSubtype(rxSock, OPENAVB_AECP_AVTP_SUBTYPE | 0x80)) {
+ AVB_LOG_DEBUG("RX AVTP Subtype not supported");
+ }
+
+ memset(&hdr, 0, sizeof(hdr_info_t));
+ hdr.shost = ADDR_PTR(&intfAddr);
+ // hdr.dhost; // Set at tx time.
+ hdr.ethertype = ETHERTYPE_AVTP;
+ if (vlanID != 0 || vlanPCP != 0) {
+ hdr.vlan = TRUE;
+ hdr.vlan_pcp = vlanPCP;
+ hdr.vlan_vid = vlanID;
+ AVB_LOGF_DEBUG("VLAN pcp=%d vid=%d", hdr.vlan_pcp, hdr.vlan_vid);
+ }
+ if (!openavbRawsockTxSetHdr(txSock, &hdr)) {
+ AVB_LOG_ERROR("TX socket Header Failure");
+ openavbAecpCloseSocket();
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+ return false;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+ return true;
+ }
+
+ AVB_LOG_ERROR("Invalid socket");
+ openavbAecpCloseSocket();
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+ return false;
+}
+
+static void openavbAecpMessageRxFrameParse(U8* payload, int payload_len, hdr_info_t *hdr)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+#if 0
+ AVB_LOGF_DEBUG("openavbAecpMessageRxFrameParse packet data (length %d):", payload_len);
+ AVB_LOG_BUFFER(AVB_LOG_LEVEL_DEBUG, payload, payload_len, 16);
+#endif
+
+ // Save the source address
+ openavb_aecp_AEMCommandResponse_t * openavbAecpCommandResponse = calloc(1, sizeof(openavb_aecp_AEMCommandResponse_t));
+ if (!openavbAecpCommandResponse) { return; }
+ memcpy(openavbAecpCommandResponse->host, hdr->shost, ETH_ALEN);
+
+ U8 *pSrc = payload;
+ {
+ // AVTP Control Header
+ openavb_aecp_control_header_t *pDst = &openavbAecpCommandResponse->headers;
+ BIT_B2DNTOHB(pDst->cd, pSrc, 0x80, 7, 0);
+ BIT_B2DNTOHB(pDst->subtype, pSrc, 0x7f, 0, 1);
+ BIT_B2DNTOHB(pDst->sv, pSrc, 0x80, 7, 0);
+ BIT_B2DNTOHB(pDst->version, pSrc, 0x70, 4, 0);
+ BIT_B2DNTOHB(pDst->message_type, pSrc, 0x0f, 0, 1);
+ BIT_B2DNTOHB(pDst->status, pSrc, 0xf800, 11, 0);
+ BIT_B2DNTOHS(pDst->control_data_length, pSrc, 0x07ff, 0, 2);
+ OCT_B2DMEMCP(pDst->target_entity_id, pSrc);
+ }
+
+ if (openavbAecpCommandResponse->headers.subtype == OPENAVB_AECP_AVTP_SUBTYPE) {
+ // AECP Common PDU Fields
+ openavb_aecp_common_data_unit_t *pDst = &openavbAecpCommandResponse->commonPdu;
+ OCT_B2DMEMCP(pDst->controller_entity_id, pSrc);
+ OCT_B2DNTOHS(pDst->sequence_id, pSrc);
+ }
+ else {
+ free(openavbAecpCommandResponse);
+ return;
+ }
+
+ if (openavbAecpCommandResponse->headers.message_type == OPENAVB_AECP_MESSAGE_TYPE_AEM_COMMAND) {
+ // Entity Model PDU Fields
+ openavb_aecp_entity_model_data_unit_t *pDst = &openavbAecpCommandResponse->entityModelPdu;
+ BIT_B2DNTOHS(pDst->u, pSrc, 0x8000, 15, 0);
+ BIT_B2DNTOHS(pDst->command_type, pSrc, 0x7fff, 0, 2);
+
+ switch (openavbAecpCommandResponse->entityModelPdu.command_type) {
+ case OPENAVB_AEM_COMMAND_CODE_ACQUIRE_ENTITY:
+ {
+ openavb_aecp_command_data_acquire_entity_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.acquireEntityCmd;
+ OCT_B2DNTOHL(pDst->flags, pSrc);
+ OCT_B2DMEMCP(pDst->owner_id, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_LOCK_ENTITY:
+ // No command specific data
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ENTITY_AVAILABLE:
+ // No command specific data
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_CONTROLLER_AVAILABLE:
+ // No command specific data
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_READ_DESCRIPTOR:
+ {
+ openavb_aecp_command_data_read_descriptor_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.readDescriptorCmd;
+ OCT_B2DNTOHS(pDst->configuration_index, pSrc);
+ OCT_B2DNTOHS(pDst->reserved, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_WRITE_DESCRIPTOR:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_CONFIGURATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_CONFIGURATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_STREAM_FORMAT:
+ {
+ openavb_aecp_commandresponse_data_set_stream_format_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.setStreamFormatCmd;
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DMEMCP(pDst->stream_format, pSrc);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_STREAM_FORMAT:
+ {
+ openavb_aecp_command_data_get_stream_format_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.getStreamFormatCmd;
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_VIDEO_FORMAT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_VIDEO_FORMAT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_SENSOR_FORMAT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_SENSOR_FORMAT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_STREAM_INFO:
+ {
+ openavb_aecp_commandresponse_data_set_stream_info_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.setStreamInfoCmd;
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DNTOHL(pDst->flags, pSrc);
+ OCT_B2DMEMCP(pDst->stream_format, pSrc);
+ OCT_B2DMEMCP(pDst->stream_id, pSrc);
+ OCT_B2DNTOHL(pDst->msrp_accumulated_latency, pSrc);
+ OCT_B2DMEMCP(pDst->stream_dest_mac, pSrc);
+ OCT_B2DNTOHB(pDst->msrp_failure_code, pSrc);
+ OCT_B2DNTOHB(pDst->reserved_1, pSrc);
+ OCT_B2DMEMCP(pDst->msrp_failure_bridge_id, pSrc);
+ OCT_B2DNTOHS(pDst->stream_vlan_id, pSrc);
+ OCT_B2DNTOHS(pDst->reserved_2, pSrc);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_STREAM_INFO:
+ {
+ openavb_aecp_command_data_get_stream_info_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.getStreamInfoCmd;
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_NAME:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_NAME:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_ASSOCIATION_ID:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_ASSOCIATION_ID:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_SAMPLING_RATE:
+ {
+ openavb_aecp_commandresponse_data_set_sampling_rate_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.setSamplingRateCmd;
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DMEMCP(pDst->sampling_rate, pSrc);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_SAMPLING_RATE:
+ {
+ openavb_aecp_command_data_get_sampling_rate_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.getSamplingRateCmd;
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_CLOCK_SOURCE:
+ {
+ openavb_aecp_commandresponse_data_set_clock_source_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.setClockSourceCmd;
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DNTOHS(pDst->clock_source_index, pSrc);
+ OCT_B2DNTOHS(pDst->reserved, pSrc);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_CLOCK_SOURCE:
+ {
+ openavb_aecp_command_data_get_clock_source_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.getClockSourceCmd;
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_CONTROL:
+ {
+ U8 *pSrcEnd = pSrc + openavbAecpCommandResponse->headers.control_data_length;
+ openavb_aecp_commandresponse_data_set_control_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.setControlCmd;
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+
+ // Need to get the descriptor to proper parse the values.
+ if (pDst->descriptor_type == OPENAVB_AEM_DESCRIPTOR_CONTROL) {
+ openavb_aem_descriptor_control_t *pDescriptorControl = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pDst->descriptor_type, pDst->descriptor_index);
+ if (pDescriptorControl) {
+ bool bDone = FALSE;
+ pDst->valuesCount = 0;
+ while ((pSrc < pSrcEnd) || bDone) {
+ switch (pDescriptorControl->control_value_type) {
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT8:
+ OCT_B2DNTOHB(pDst->values.linear_int8[pDst->valuesCount++], pSrc);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT16:
+ OCT_B2DNTOHS(pDst->values.linear_int16[pDst->valuesCount++], pSrc);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT32:
+ OCT_B2DNTOHL(pDst->values.linear_int32[pDst->valuesCount++], pSrc);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT64:
+ OCT_B2DMEMCP(&pDst->values.linear_int64[pDst->valuesCount++], pSrc);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_FLOAT:
+ OCT_B2DMEMCP(&pDst->values.linear_float[pDst->valuesCount++], pSrc);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_DOUBLE:
+ OCT_B2DMEMCP(&pDst->values.linear_double[pDst->valuesCount++], pSrc);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_FLOAT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_DOUBLE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_STRING:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_FLOAT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_DOUBLE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_UTF8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_BODE_PLOT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SMPTE_TIME:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SAMPLE_RATE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_GPTP_TIME:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_VENDOR:
+ bDone = TRUE; // Not yet supported
+ break;
+ }
+ }
+ }
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_CONTROL:
+ {
+ openavb_aecp_command_data_get_control_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.getControlCmd;
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_INCREMENT_CONTROL:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DECREMENT_CONTROL:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_SIGNAL_SELECTOR:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_SIGNAL_SELECTOR:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_MIXER:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_MIXER:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_MATRIX:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_MATRIX:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_START_STREAMING:
+ {
+ openavb_aecp_commandresponse_data_start_streaming_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.startStreamingCmd;
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_STOP_STREAMING:
+ {
+ openavb_aecp_commandresponse_data_stop_streaming_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.stopStreamingCmd;
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REGISTER_UNSOLICITED_NOTIFICATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DEREGISTER_UNSOLICITED_NOTIFICATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_IDENTIFY_NOTIFICATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_AVB_INFO:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_AS_PATH:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_COUNTERS:
+ {
+ openavb_aecp_command_data_get_counters_t *pDst = &openavbAecpCommandResponse->entityModelPdu.command_data.getCountersCmd;
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REBOOT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_AUDIO_MAP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ADD_AUDIO_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REMOVE_AUDIO_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_VIDEO_MAP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ADD_VIDEO_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REMOVE_VIDEO_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_SENSOR_MAP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ADD_SENSOR_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REMOVE_SENSOR_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_START_OPERATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ABORT_OPERATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_OPERATION_STATUS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_ADD_KEY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_DELETE_KEY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_GET_KEY_LIST:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_GET_KEY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_ADD_KEY_TO_CHAIN:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_DELETE_KEY_FROM_CHAIN:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_GET_KEYCHAIN_LIST:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_GET_IDENTITY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_ADD_TOKEN:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_DELETE_TOKEN:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTHENTICATE:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DEAUTHENTICATE:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ENABLE_TRANSPORT_SECURITY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DISABLE_TRANSPORT_SECURITY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ENABLE_STREAM_ENCRYPTION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DISABLE_STREAM_ENCRYPTION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_MEMORY_OBJECT_LENGTH:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_MEMORY_OBJECT_LENGTH:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_STREAM_BACKUP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_STREAM_BACKUP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_EXPANSION:
+ break;
+ default:
+ break;
+ }
+
+ if (pSrc - payload <= payload_len) {
+ // Notify the state machine of the command request
+ // The buffer will be deleted once the request is handled.
+ openavbAecpSMEntityModelEntitySet_rcvdCommand(openavbAecpCommandResponse);
+ }
+ else {
+ AVB_LOGF_ERROR("Expected packet of size %d, but received one of size %d. Discarding.", pSrc - payload, payload_len);
+ free(openavbAecpCommandResponse);
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
+
+static void openavbAecpMessageRxFrameReceive(U32 timeoutUsec)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ hdr_info_t hdrInfo;
+ unsigned int offset, len;
+ U8 *pBuf, *pFrame;
+
+ memset(&hdrInfo, 0, sizeof(hdr_info_t));
+
+ pBuf = (U8 *)openavbRawsockGetRxFrame(rxSock, timeoutUsec, &offset, &len);
+ if (pBuf) {
+ pFrame = pBuf + offset;
+
+ offset = openavbRawsockRxParseHdr(rxSock, pBuf, &hdrInfo);
+ {
+#ifndef UBUNTU
+ if (hdrInfo.ethertype == ETHERTYPE_8021Q) {
+ // Oh! Need to look past the VLAN tag
+ U16 vlan_bits = ntohs(*(U16 *)(pFrame + offset));
+ hdrInfo.vlan = TRUE;
+ hdrInfo.vlan_vid = vlan_bits & 0x0FFF;
+ hdrInfo.vlan_pcp = (vlan_bits >> 13) & 0x0007;
+ offset += 2;
+ hdrInfo.ethertype = ntohs(*(U16 *)(pFrame + offset));
+ offset += 2;
+ }
+#endif
+
+ // Make sure that this is an AVTP packet
+ // (Should always be AVTP if it's to our AVTP-specific multicast address)
+ if (hdrInfo.ethertype == ETHERTYPE_AVTP) {
+ // parse the PDU only for AECP messages
+ if (*(pFrame + offset) == (0x80 | OPENAVB_AECP_AVTP_SUBTYPE)) {
+ openavbAecpMessageRxFrameParse(pFrame + offset, len - offset, &hdrInfo);
+ }
+ }
+ else {
+ AVB_LOG_WARNING("Received non-AVTP frame!");
+ AVB_LOGF_DEBUG("Unexpected packet data (length %d):", len);
+ AVB_LOG_BUFFER(AVB_LOG_LEVEL_DEBUG, pFrame, len, 16);
+ }
+ }
+
+ // Release the frame
+ openavbRawsockRelRxFrame(rxSock, pBuf);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
+
+
+void openavbAecpMessageTxFrame(openavb_aecp_AEMCommandResponse_t *AEMCommandResponse)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ U8 *pBuf;
+ U8 *pcontrol_data_length;
+ U8 *pcontrol_data_length_start_marker;
+ U32 size;
+ unsigned int hdrlen = 0;
+
+ pBuf = openavbRawsockGetTxFrame(txSock, TRUE, &size);
+
+ if (!pBuf) {
+ AVB_LOG_ERROR("No TX buffer");
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+ return;
+ }
+
+ if (size < AECP_FRAME_LEN) {
+ AVB_LOG_ERROR("TX buffer too small");
+ openavbRawsockRelTxFrame(txSock, pBuf);
+ pBuf = NULL;
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+ return;
+ }
+
+ memset(pBuf, 0, AECP_FRAME_LEN);
+ openavbRawsockTxFillHdr(txSock, pBuf, &hdrlen);
+
+ // Set the destination address
+ memcpy(pBuf, AEMCommandResponse->host, ETH_ALEN);
+
+ U8 *pDst = pBuf + hdrlen;
+ {
+ // AVTP Control Header
+ openavb_aecp_control_header_t *pSrc = &AEMCommandResponse->headers;
+ BIT_D2BHTONB(pDst, pSrc->cd, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtype, 0, 1);
+ BIT_D2BHTONB(pDst, pSrc->sv, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc->version, 4, 0);
+ BIT_D2BHTONB(pDst, pSrc->message_type, 0, 1);
+ BIT_D2BHTONS(pDst, pSrc->status, 11, 0);
+ pcontrol_data_length = pDst; // Set later
+ BIT_D2BHTONS(pDst, pSrc->control_data_length, 0, 2);
+ OCT_D2BMEMCP(pDst, pSrc->target_entity_id);
+ pcontrol_data_length_start_marker = pDst;
+ }
+
+ {
+ // AECP Common PDU
+ openavb_aecp_common_data_unit_t *pSrc = &AEMCommandResponse->commonPdu;
+ OCT_D2BMEMCP(pDst, pSrc->controller_entity_id);
+ OCT_D2BHTONS(pDst, pSrc->sequence_id);
+ }
+
+ if (AEMCommandResponse->headers.message_type == OPENAVB_AECP_MESSAGE_TYPE_AEM_RESPONSE) {
+ // Entity Model PDU Fields
+ openavb_aecp_entity_model_data_unit_t *pSrc = &AEMCommandResponse->entityModelPdu;
+ BIT_D2BHTONS(pDst, pSrc->u, 15, 0);
+ BIT_D2BHTONS(pDst, pSrc->command_type, 0, 2);
+
+ // Command specific data
+ switch (AEMCommandResponse->entityModelPdu.command_type) {
+ case OPENAVB_AEM_COMMAND_CODE_ACQUIRE_ENTITY:
+ {
+ openavb_aecp_command_data_acquire_entity_t *pSrc = &AEMCommandResponse->entityModelPdu.command_data.acquireEntityRsp;
+ OCT_D2BHTONL(pDst, pSrc->flags);
+ OCT_D2BMEMCP(pDst, pSrc->owner_id);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_LOCK_ENTITY:
+ // No command specific data
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ENTITY_AVAILABLE:
+ // No command specific data
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_CONTROLLER_AVAILABLE:
+ // No command specific data
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_READ_DESCRIPTOR:
+ {
+ openavb_aecp_response_data_read_descriptor_t *pSrc = &AEMCommandResponse->entityModelPdu.command_data.readDescriptorRsp;
+ OCT_D2BHTONS(pDst, pSrc->configuration_index);
+ OCT_D2BHTONS(pDst, pSrc->reserved);
+ OCT_D2BBUFCP(pDst, pSrc->descriptor_data, pSrc->descriptor_length);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_WRITE_DESCRIPTOR:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_CONFIGURATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_CONFIGURATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_STREAM_FORMAT:
+ {
+ openavb_aecp_commandresponse_data_set_stream_format_t *pSrc = &AEMCommandResponse->entityModelPdu.command_data.setStreamFormatRsp;
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->stream_format);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_STREAM_FORMAT:
+ {
+ openavb_aecp_response_data_get_stream_format_t *pSrc = &AEMCommandResponse->entityModelPdu.command_data.getStreamFormatRsp;
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->stream_format);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_VIDEO_FORMAT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_VIDEO_FORMAT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_SENSOR_FORMAT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_SENSOR_FORMAT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_STREAM_INFO:
+ {
+ openavb_aecp_commandresponse_data_set_stream_info_t *pSrc = &AEMCommandResponse->entityModelPdu.command_data.setStreamInfoRsp;
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BHTONL(pDst, pSrc->flags);
+ OCT_D2BMEMCP(pDst, pSrc->stream_format);
+ OCT_D2BMEMCP(pDst, pSrc->stream_id);
+ OCT_D2BHTONL(pDst, pSrc->msrp_accumulated_latency);
+ OCT_D2BMEMCP(pDst, pSrc->stream_dest_mac);
+ OCT_D2BHTONB(pDst, pSrc->msrp_failure_code);
+ OCT_D2BHTONB(pDst, pSrc->reserved_1);
+ OCT_D2BMEMCP(pDst, pSrc->msrp_failure_bridge_id);
+ OCT_D2BHTONS(pDst, pSrc->stream_vlan_id);
+ OCT_D2BHTONS(pDst, pSrc->reserved_2);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_STREAM_INFO:
+ {
+ openavb_aecp_response_data_get_stream_info_t *pSrc = &AEMCommandResponse->entityModelPdu.command_data.getStreamInfoRsp;
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BHTONL(pDst, pSrc->flags);
+ OCT_D2BMEMCP(pDst, pSrc->stream_format);
+ OCT_D2BMEMCP(pDst, pSrc->stream_id);
+ OCT_D2BHTONL(pDst, pSrc->msrp_accumulated_latency);
+ OCT_D2BMEMCP(pDst, pSrc->stream_dest_mac);
+ OCT_D2BHTONB(pDst, pSrc->msrp_failure_code);
+ OCT_D2BHTONB(pDst, pSrc->reserved_1);
+ OCT_D2BMEMCP(pDst, pSrc->msrp_failure_bridge_id);
+ OCT_D2BHTONS(pDst, pSrc->stream_vlan_id);
+ OCT_D2BHTONS(pDst, pSrc->reserved_2);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_NAME:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_NAME:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_ASSOCIATION_ID:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_ASSOCIATION_ID:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_SAMPLING_RATE:
+ {
+ openavb_aecp_commandresponse_data_set_sampling_rate_t *pSrc = &AEMCommandResponse->entityModelPdu.command_data.setSamplingRateRsp;
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->sampling_rate);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_SAMPLING_RATE:
+ {
+ openavb_aecp_response_data_get_sampling_rate_t *pSrc = &AEMCommandResponse->entityModelPdu.command_data.getSamplingRateRsp;
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->sampling_rate);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_CLOCK_SOURCE:
+ {
+ openavb_aecp_commandresponse_data_set_clock_source_t *pSrc = &AEMCommandResponse->entityModelPdu.command_data.setClockSourceRsp;
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BHTONS(pDst, pSrc->clock_source_index);
+ OCT_D2BHTONS(pDst, pSrc->reserved);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_CLOCK_SOURCE:
+ {
+ openavb_aecp_response_data_get_clock_source_t *pSrc = &AEMCommandResponse->entityModelPdu.command_data.getClockSourceRsp;
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BHTONS(pDst, pSrc->clock_source_index);
+ OCT_D2BHTONS(pDst, pSrc->reserved);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_CONTROL:
+ {
+ openavb_aecp_commandresponse_data_set_control_t *pSrc = &AEMCommandResponse->entityModelPdu.command_data.setControlRsp;
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+
+ openavb_aem_descriptor_control_t *pDescriptorControl = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pSrc->descriptor_type, pSrc->descriptor_index);
+ if (pDescriptorControl) {
+ pSrc->valuesCount = 0;
+ int i1;
+ for (i1 = 0; i1 < pSrc->valuesCount; i1++) {
+ switch (pDescriptorControl->control_value_type) {
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT8:
+ OCT_D2BHTONB(pDst, pSrc->values.linear_int8[i1]);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT16:
+ OCT_D2BHTONS(pDst, pSrc->values.linear_int16[i1]);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT32:
+ OCT_D2BHTONL(pDst, pSrc->values.linear_int32[i1]);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT64:
+ OCT_D2BMEMCP(pDst, &pSrc->values.linear_int64[i1]);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_FLOAT:
+ OCT_D2BMEMCP(pDst, &pSrc->values.linear_float[i1]);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_DOUBLE:
+ OCT_D2BMEMCP(pDst, &pSrc->values.linear_double[i1]);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_FLOAT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_DOUBLE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_STRING:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_FLOAT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_DOUBLE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_UTF8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_BODE_PLOT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SMPTE_TIME:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SAMPLE_RATE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_GPTP_TIME:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_VENDOR:
+ break;
+ }
+ }
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_CONTROL:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_INCREMENT_CONTROL:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DECREMENT_CONTROL:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_SIGNAL_SELECTOR:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_SIGNAL_SELECTOR:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_MIXER:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_MIXER:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_MATRIX:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_MATRIX:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_START_STREAMING:
+ {
+ openavb_aecp_commandresponse_data_start_streaming_t *pSrc = &AEMCommandResponse->entityModelPdu.command_data.startStreamingRsp;
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_STOP_STREAMING:
+ {
+ openavb_aecp_commandresponse_data_stop_streaming_t *pSrc = &AEMCommandResponse->entityModelPdu.command_data.stopStreamingRsp;
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REGISTER_UNSOLICITED_NOTIFICATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DEREGISTER_UNSOLICITED_NOTIFICATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_IDENTIFY_NOTIFICATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_AVB_INFO:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_AS_PATH:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_COUNTERS:
+ {
+ openavb_aecp_response_data_get_counters_t *pSrc = &AEMCommandResponse->entityModelPdu.command_data.getCountersRsp;
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BHTONL(pDst, pSrc->counters_valid);
+ OCT_D2BBUFCP(pDst, pSrc->counters_block, pSrc->counters_block_length);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REBOOT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_AUDIO_MAP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ADD_AUDIO_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REMOVE_AUDIO_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_VIDEO_MAP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ADD_VIDEO_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REMOVE_VIDEO_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_SENSOR_MAP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ADD_SENSOR_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REMOVE_SENSOR_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_START_OPERATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ABORT_OPERATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_OPERATION_STATUS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_ADD_KEY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_DELETE_KEY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_GET_KEY_LIST:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_GET_KEY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_ADD_KEY_TO_CHAIN:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_DELETE_KEY_FROM_CHAIN:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_GET_KEYCHAIN_LIST:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_GET_IDENTITY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_ADD_TOKEN:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_DELETE_TOKEN:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTHENTICATE:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DEAUTHENTICATE:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ENABLE_TRANSPORT_SECURITY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DISABLE_TRANSPORT_SECURITY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ENABLE_STREAM_ENCRYPTION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DISABLE_STREAM_ENCRYPTION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_MEMORY_OBJECT_LENGTH:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_MEMORY_OBJECT_LENGTH:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_STREAM_BACKUP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_STREAM_BACKUP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_EXPANSION:
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Set length into buffer
+ BIT_D2BHTONS(pcontrol_data_length, (pDst - pcontrol_data_length_start_marker), 0, 2);
+
+ // Make sure the packet will be at least 64 bytes long.
+ if (pDst - pBuf < 64) { pDst = pBuf + 64; }
+
+#if 0
+ AVB_LOGF_DEBUG("openavbAecpMessageTxFrame packet data (length %d):", pDst - pBuf);
+ AVB_LOG_BUFFER(AVB_LOG_LEVEL_DEBUG, pBuf, pDst - pBuf, 16);
+#endif
+
+ openavbRawsockTxFrameReady(txSock, pBuf, pDst - pBuf, 0);
+ openavbRawsockSend(txSock);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
+
+void* openavbAecpMessageRxThreadFn(void *pv)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ AVB_LOG_DEBUG("AECP Thread Started");
+ while (bRunning) {
+ // Try to get and process an AECP message.
+ openavbAecpMessageRxFrameReceive(MICROSECONDS_PER_SECOND);
+ }
+ AVB_LOG_DEBUG("AECP Thread Done");
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+ return NULL;
+}
+
+openavbRC openavbAecpMessageHandlerStart()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ bRunning = TRUE;
+
+ if (openavbAecpOpenSocket((const char *)gAvdeccCfg.ifname, gAvdeccCfg.vlanID, gAvdeccCfg.vlanPCP)) {
+
+ // Start the RX thread
+ bool errResult;
+ THREAD_CREATE(openavbAecpMessageRxThread, openavbAecpMessageRxThread, NULL, openavbAecpMessageRxThreadFn, NULL);
+ THREAD_CHECK_ERROR(openavbAecpMessageRxThread, "Thread / task creation failed", errResult);
+ if (errResult) {
+ bRunning = FALSE;
+ openavbAecpCloseSocket();
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_FAILURE, AVB_TRACE_AECP);
+ }
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AECP);
+ }
+
+ bRunning = FALSE;
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_FAILURE, AVB_TRACE_AECP);
+}
+
+void openavbAecpMessageHandlerStop()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ if (bRunning) {
+ bRunning = FALSE;
+ THREAD_JOIN(openavbAecpMessageRxThread, NULL);
+ openavbAecpCloseSocket();
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
+
+openavbRC openavbAecpMessageSendUnsolicitedNotificationIfNeeded(openavb_aecp_AEMCommandResponse_t *AEMCommandResponse)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+ // AVDECC_TODO : Currently not implemented. IEEE Std 1722.1-2013 clause 7.5
+ // The basic idea is to inform interested controllers about a change in state of the Entity Model. This change in state
+ // could be from a AEM Command or other interfaces into the Entity Model. For AEM Commands this function will check the CommandResponse
+ // for the Success and correct Message Type and set the Unsolicited flag and sent to interested controllers.
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AECP);
+}
+
+openavbRC openavbAecpMessageSend(openavb_aecp_AEMCommandResponse_t *AEMCommandResponse)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+ openavbAecpMessageTxFrame(AEMCommandResponse);
+ openavbAecpMessageSendUnsolicitedNotificationIfNeeded(AEMCommandResponse);
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AECP);
+}
+
diff --git a/lib/avtp_pipeline/aecp/openavb_aecp_message.h b/lib/avtp_pipeline/aecp/openavb_aecp_message.h
new file mode 100644
index 00000000..225d2312
--- /dev/null
+++ b/lib/avtp_pipeline/aecp/openavb_aecp_message.h
@@ -0,0 +1,50 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AVDECC Enumeration and control protocol (AECP) Message Handler Interface
+ * MODULE SUMMARY : Interface for the AVDECC Enumeration and control protocol (AECP) message handlers
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_AECP_MESSAGE_H
+#define OPENAVB_AECP_MESSAGE_H 1
+
+#include "openavb_avdecc.h"
+
+openavbRC openavbAecpMessageHandlerStart(void);
+
+void openavbAecpMessageHandlerStop(void);
+
+openavbRC openavbAecpMessageSend(openavb_aecp_AEMCommandResponse_t *AEMCommandResponse);
+
+#endif // OPENAVB_AECP_MESSAGE_H
diff --git a/lib/avtp_pipeline/aecp/openavb_aecp_pub.h b/lib/avtp_pipeline/aecp/openavb_aecp_pub.h
new file mode 100644
index 00000000..00a5f2d2
--- /dev/null
+++ b/lib/avtp_pipeline/aecp/openavb_aecp_pub.h
@@ -0,0 +1,42 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AVDECC Enumeration and control protocol (AECP) Public Interface
+ * MODULE SUMMARY : Public interface for the AVDECC Enumeration and control protocol (AECP)
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_AECP_PUB_H
+#define OPENAVB_AECP_PUB_H 1
+
+#endif // OPENAVB_AECP_PUB_H
diff --git a/lib/avtp_pipeline/aecp/openavb_aecp_sm_entity_model_entity.c b/lib/avtp_pipeline/aecp/openavb_aecp_sm_entity_model_entity.c
new file mode 100644
index 00000000..e570f654
--- /dev/null
+++ b/lib/avtp_pipeline/aecp/openavb_aecp_sm_entity_model_entity.c
@@ -0,0 +1,1378 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AVDECC Enumeration and control protocol (AECP) : Entity Model Entity State Machine
+ * MODULE SUMMARY : Implements the AVDECC Enumeration and control protocol (AECP) : Entity Model Entity State Machine
+ * IEEE Std 1722.1-2013 clause 9.2.2.3
+ ******************************************************************
+ */
+
+#include "openavb_platform.h"
+
+#include <errno.h>
+
+#define AVB_LOG_COMPONENT "AECP"
+#include "openavb_log.h"
+
+#include "openavb_aem.h"
+#include "openavb_aecp.h"
+#include "openavb_aecp_message.h"
+#include "openavb_aecp_sm_entity_model_entity.h"
+#include "openavb_list.h"
+
+#include "openavb_avdecc_pipeline_interaction_pub.h"
+#include "openavb_aecp_cmd_get_counters.h"
+
+typedef enum {
+ OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_WAITING,
+ OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_UNSOLICITED_RESPONSE,
+ OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_RECEIVED_COMMAND,
+} openavb_aecp_sm_entity_model_entity_state_t;
+
+extern openavb_aecp_sm_global_vars_t openavbAecpSMGlobalVars;
+openavb_aecp_sm_entity_model_entity_vars_t openavbAecpSMEntityModelEntityVars;
+
+extern MUTEX_HANDLE(openavbAemMutex);
+#define AEM_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAemMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define AEM_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAemMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+MUTEX_HANDLE(openavbAecpQueueMutex);
+#define AECP_QUEUE_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAecpQueueMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define AECP_QUEUE_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAecpQueueMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+MUTEX_HANDLE(openavbAecpSMMutex);
+#define AECP_SM_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAecpSMMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define AECP_SM_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAecpSMMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+SEM_T(openavbAecpSMEntityModelEntityWaitingSemaphore);
+THREAD_TYPE(openavbAecpSMEntityModelEntityThread);
+THREAD_DEFINITON(openavbAecpSMEntityModelEntityThread);
+
+
+static openavb_list_t s_commandQueue = NULL;
+
+// Returns 1 if the queue was not empty before adding the new command,
+// 0 if the queue was empty before adding the new command,
+// or -1 if an error occurred.
+static int addCommandToQueue(openavb_aecp_AEMCommandResponse_t *command)
+{
+ int returnVal;
+
+ if (!s_commandQueue) { return -1; }
+ if (!command) { return -1; }
+
+ AECP_QUEUE_LOCK();
+ // Determine if the queue has something in it.
+ returnVal = (openavbListFirst(s_commandQueue) != NULL ? 1 : 0);
+
+ // Add the command to the end of the linked list.
+ if (openavbListAdd(s_commandQueue, command) == NULL) {
+ returnVal = -1;
+ }
+ AECP_QUEUE_UNLOCK();
+ return (returnVal);
+}
+
+static openavb_aecp_AEMCommandResponse_t * getNextCommandFromQueue(void)
+{
+ openavb_aecp_AEMCommandResponse_t *item = NULL;
+ openavb_list_node_t node;
+
+ if (!s_commandQueue) { return NULL; }
+
+ AECP_QUEUE_LOCK();
+ node = openavbListFirst(s_commandQueue);
+ if (node) {
+ item = openavbListData(node);
+ openavbListDelete(s_commandQueue, node);
+ }
+ AECP_QUEUE_UNLOCK();
+ return item;
+}
+
+
+void acquireEntity()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ openavb_aecp_AEMCommandResponse_t *pCommand = openavbAecpSMEntityModelEntityVars.rcvdCommand;
+ if (!pCommand) {
+ AVB_LOG_ERROR("acquireEntity called without command");
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+ return;
+ }
+
+ pCommand->headers.message_type = OPENAVB_AECP_MESSAGE_TYPE_AEM_RESPONSE;
+
+ if (pCommand->entityModelPdu.command_data.acquireEntityCmd.descriptor_type != OPENAVB_AEM_DESCRIPTOR_ENTITY) {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_SUPPORTED;
+ }
+ else {
+ openavb_avdecc_entity_model_t *pAem = openavbAemGetModel();
+ if (!pAem) {
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+ return;
+ }
+
+ AEM_LOCK();
+ if (pCommand->entityModelPdu.command_data.acquireEntityCmd.flags & OPENAVB_AEM_ACQUIRE_ENTITY_COMMAND_FLAG_RELEASE) {
+ // AVDECC_TODO - need to add mutex for the entity model
+ AVB_LOG_DEBUG("Entity Released");
+ pAem->entityAcquired = FALSE;
+ }
+ else {
+ if (pAem->entityAcquired) {
+ if (memcmp(pAem->acquiredControllerId, pCommand->commonPdu.controller_entity_id, sizeof(pAem->acquiredControllerId))) {
+ // AVDECC_TODO - Per 7.4.1 ACQUIRE_ENTITY Command. Need to add the CONTROLLER_AVAILABLE command and response to ensure the controller is still alive.
+ // For now just respond acquired by a different controller.
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_ENTITY_ACQUIRED;
+ memcpy(pCommand->entityModelPdu.command_data.acquireEntityRsp.owner_id, pAem->acquiredControllerId, sizeof(pCommand->commonPdu.controller_entity_id));
+ }
+ else {
+ // Entity was already acquired by this controller, so indicate a successful acquisition.
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ }
+ else {
+ pAem->entityAcquired = TRUE;
+ memcpy(pAem->acquiredControllerId, pCommand->commonPdu.controller_entity_id, sizeof(pAem->acquiredControllerId));
+ memcpy(pCommand->entityModelPdu.command_data.acquireEntityRsp.owner_id, pCommand->commonPdu.controller_entity_id, sizeof(pCommand->commonPdu.controller_entity_id));
+ AVB_LOGF_DEBUG("Entity Acquired by " ENTITYID_FORMAT, pCommand->entityModelPdu.command_data.acquireEntityRsp.owner_id);
+ }
+ }
+ AEM_UNLOCK();
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
+
+void lockEntity()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ openavb_aecp_AEMCommandResponse_t *pCommand = openavbAecpSMEntityModelEntityVars.rcvdCommand;
+ if (!pCommand) {
+ AVB_LOG_ERROR("lockEntity called without command");
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+ return;
+ }
+
+ pCommand->headers.message_type = OPENAVB_AECP_MESSAGE_TYPE_AEM_RESPONSE;
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_IMPLEMENTED;
+
+ // AVDECC_TODO - needs implementation
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
+
+// Returns TRUE is current rcvdCommand controlID matches the AEM acquire or lock controller id
+bool processCommandCheckRestriction_CorrectController()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+ bool bResult = TRUE;
+
+ openavb_aecp_AEMCommandResponse_t *pCommand = openavbAecpSMEntityModelEntityVars.rcvdCommand;
+ if (!pCommand) {
+ AVB_LOG_ERROR("processCommandCheckRestriction_CorrectController called without command");
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+ return bResult;
+ }
+
+ openavb_avdecc_entity_model_t *pAem = openavbAemGetModel();
+ if (pAem) {
+ AEM_LOCK();
+ if (pAem->entityAcquired) {
+ if (memcmp(pAem->acquiredControllerId, pCommand->commonPdu.controller_entity_id, sizeof(pAem->acquiredControllerId)) == 0) {
+ bResult = TRUE;
+ }
+ else {
+ AVB_LOGF_DEBUG("Access denied to " ENTITYID_FORMAT " as " ENTITYID_FORMAT " already acquired it", pCommand->commonPdu.controller_entity_id, pAem->acquiredControllerId);
+ bResult = FALSE;
+ }
+ }
+ else if (pAem->entityLocked) {
+ if (memcmp(pAem->lockedControllerId, pCommand->commonPdu.controller_entity_id, sizeof(pAem->lockedControllerId)) == 0) {
+ bResult = TRUE;
+ }
+ else {
+ AVB_LOGF_DEBUG("Access denied to " ENTITYID_FORMAT " as " ENTITYID_FORMAT " already locked it", pCommand->commonPdu.controller_entity_id, pAem->lockedControllerId);
+ bResult = FALSE;
+ }
+ }
+ AEM_UNLOCK();
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+ return bResult;
+}
+
+// Returns TRUE the stream_input or stream_output descriptor is currently not running.
+// NOTE: This function is using the last reported state from the client, not the state AVDECC last told the client to be in.
+bool processCommandCheckRestriction_StreamNotRunning(U16 descriptor_type, U16 descriptor_index)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+ bool bResult = TRUE;
+
+ if (descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT ||
+ descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT) {
+ U16 configIdx = openavbAemGetConfigIdx();
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamIO = openavbAemGetDescriptor(configIdx, descriptor_type, descriptor_index);
+ if (pDescriptorStreamIO) {
+ openavbAvdeccMsgStateType_t state = openavbAVDECCGetStreamingState(pDescriptorStreamIO, configIdx);
+ if (state >= OPENAVB_AVDECC_MSG_RUNNING) {
+ bResult = FALSE;
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+ return bResult;
+}
+
+// Process an incoming command and make it the response data on return.
+void processCommand()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ openavb_aecp_AEMCommandResponse_t *pCommand = openavbAecpSMEntityModelEntityVars.rcvdCommand;
+ if (!pCommand) {
+ AVB_LOG_ERROR("processCommand called without command");
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+ return;
+ }
+
+ // Set message type as response
+ pCommand->headers.message_type = OPENAVB_AECP_MESSAGE_TYPE_AEM_RESPONSE;
+
+ // Set to Not Implemented. Will be overridden by commands that are implemented.
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_IMPLEMENTED;
+
+ switch (pCommand->entityModelPdu.command_type) {
+ case OPENAVB_AEM_COMMAND_CODE_ACQUIRE_ENTITY:
+ // Implemented in the acquireEntity() function. Should never get here.
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_LOCK_ENTITY:
+ // Implemented in the lockEntity() function. Should never get here.
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ENTITY_AVAILABLE:
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_CONTROLLER_AVAILABLE:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_READ_DESCRIPTOR:
+ {
+ openavb_aecp_command_data_read_descriptor_t *pCmd = &pCommand->entityModelPdu.command_data.readDescriptorCmd;
+ openavb_aecp_response_data_read_descriptor_t *pRsp = &pCommand->entityModelPdu.command_data.readDescriptorRsp;
+ U16 configuration_index = pCmd->configuration_index;
+ U16 descriptor_type = pCmd->descriptor_type;
+ U16 descriptor_index = pCmd->descriptor_index;
+
+ openavbRC rc = openavbAemSerializeDescriptor(configuration_index, descriptor_type, descriptor_index,
+ sizeof(pRsp->descriptor_data), pRsp->descriptor_data, &pRsp->descriptor_length);
+ if (IS_OPENAVB_FAILURE(rc)) {
+ U8 *pDst = pRsp->descriptor_data;
+
+ // Send a basic response back to the controller.
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+ pRsp->configuration_index = configuration_index;
+ pRsp->reserved = 0;
+ OCT_D2BHTONS(pDst, descriptor_type);
+ OCT_D2BHTONS(pDst, descriptor_index);
+ pRsp->descriptor_length = pDst - pRsp->descriptor_data;
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_WRITE_DESCRIPTOR:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_CONFIGURATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_CONFIGURATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_STREAM_FORMAT:
+ {
+ openavb_aecp_commandresponse_data_set_stream_format_t *pCmd = &pCommand->entityModelPdu.command_data.setStreamFormatCmd;
+ openavb_aecp_commandresponse_data_set_stream_format_t *pRsp = &pCommand->entityModelPdu.command_data.setStreamFormatRsp;
+
+ if (processCommandCheckRestriction_CorrectController()) {
+ if (processCommandCheckRestriction_StreamNotRunning(pCmd->descriptor_type, pCmd->descriptor_index)) {
+ if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT) {
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorStreamInput) {
+ if (memcmp(&pDescriptorStreamInput->current_format, pCmd->stream_format, sizeof(pDescriptorStreamInput->current_format)) == 0) {
+ // No change needed.
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ else {
+ // AVDECC_TODO: Verify that the stream format is supported, and notify the Listener of the change.
+ //memcpy(&pDescriptorStreamInput->current_format, pCmd->stream_format, sizeof(pDescriptorStreamInput->current_format));
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_SUPPORTED;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+ }
+ }
+ else if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT) {
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorStreamOutput) {
+ if (memcmp(&pDescriptorStreamOutput->current_format, pCmd->stream_format, sizeof(pDescriptorStreamOutput->current_format)) == 0) {
+ // No change needed.
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ else {
+ // AVDECC_TODO: Verify that the stream format is supported, and notify the Talker of the change.
+ //memcpy(&pDescriptorStreamOutput->current_format, pCmd->stream_format, sizeof(pDescriptorStreamOutput->current_format));
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_SUPPORTED;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+ }
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_STREAM_IS_RUNNING;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_ENTITY_ACQUIRED;
+ }
+
+ if (pRsp->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT) {
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorStreamInput) {
+ memcpy(pRsp->stream_format, &pDescriptorStreamInput->current_format, sizeof(pRsp->stream_format));
+ }
+ }
+ else if (pRsp->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT) {
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorStreamOutput) {
+ memcpy(pRsp->stream_format, &pDescriptorStreamOutput->current_format, sizeof(pRsp->stream_format));
+ }
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_STREAM_FORMAT:
+ {
+ openavb_aecp_command_data_get_stream_format_t *pCmd = &pCommand->entityModelPdu.command_data.getStreamFormatCmd;
+ openavb_aecp_response_data_get_stream_format_t *pRsp = &pCommand->entityModelPdu.command_data.getStreamFormatRsp;
+
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+
+ if (pRsp->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT) {
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorStreamInput) {
+ openavbAemStreamFormatToBuf(&pDescriptorStreamInput->current_format, pRsp->stream_format);
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ }
+ else if (pRsp->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT) {
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorStreamOutput) {
+ memcpy(pRsp->stream_format, &pDescriptorStreamOutput->current_format, sizeof(pRsp->stream_format));
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_VIDEO_FORMAT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_VIDEO_FORMAT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_SENSOR_FORMAT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_SENSOR_FORMAT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_STREAM_INFO:
+ {
+ openavb_aecp_commandresponse_data_set_stream_info_t *pCmd = &pCommand->entityModelPdu.command_data.setStreamInfoCmd;
+ openavb_aecp_commandresponse_data_set_stream_info_t *pRsp = &pCommand->entityModelPdu.command_data.setStreamInfoRsp;
+
+ if (processCommandCheckRestriction_CorrectController()) {
+ if (processCommandCheckRestriction_StreamNotRunning(pCmd->descriptor_type, pCmd->descriptor_index)) {
+ if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT ||
+ pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT) {
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamIO = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorStreamIO) {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+
+ if ((pCmd->flags & OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_FORMAT_VALID) != 0) {
+ if (memcmp(&pDescriptorStreamIO->current_format, pCmd->stream_format, sizeof(pDescriptorStreamIO->current_format)) != 0) {
+ // AVDECC_TODO: Verify that the stream format is supported, and notify the Listener of the change.
+ //memcpy(&pDescriptorStreamInput->current_format, pCmd->stream_format, sizeof(pDescriptorStreamInput->current_format));
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_SUPPORTED;
+ }
+ }
+
+ // AVDECC_TODO: Add support for ENCRYPTED_PDU.
+ if ((pCmd->flags & OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_ENCRYPTED_PDU) != 0) {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_SUPPORTED;
+ }
+
+ // AVDECC_TODO: Add support for accumulated latency.
+ // For now, just clear the flags and values.
+ pRsp->flags &= ~OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_MSRP_ACC_LAT_VALID;
+ pRsp->msrp_accumulated_latency = 0;
+ pRsp->flags &= ~OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_MSRP_FAILURE_VALID;
+ pRsp->msrp_failure_code = 0;
+ memset(pRsp->msrp_failure_bridge_id, 0, sizeof(pRsp->msrp_failure_bridge_id));
+
+ if (pCommand->headers.status != OPENAVB_AEM_COMMAND_STATUS_SUCCESS) {
+ // As there are already issues, don't bother trying anything following this.
+ }
+ else if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT) {
+ // If the controller is trying to set the streaming information for the Listener, this is a problem.
+ // The Listener gets this information from the Talker when the connection starts, so setting it here makes no sense.
+ // We also ignore the CLASS_A flag (or absence of it), as the Talker will indicate that value as well.
+ if ((pCmd->flags &
+ (OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_ID_VALID |
+ OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_DEST_MAC_VALID |
+ OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_VLAN_ID_VALID)) != 0) {
+ AVB_LOG_ERROR("SET_STREAM_INFO cannot set stream parameters for Listener");
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_BAD_ARGUMENTS;
+ }
+ }
+ else {
+ // Get the streaming values to send to the Talker.
+ // Invalid values used to indicate those that should not be changed.
+ U8 sr_class = ((pCmd->flags & OPENAVB_ACMP_FLAG_CLASS_B) != 0 ? SR_CLASS_B : SR_CLASS_A);
+ U8 stream_id_valid = FALSE;
+ U8 stream_src_mac[6] = {0, 0, 0, 0, 0, 0};
+ U16 stream_uid = 0;
+ U8 stream_dest_valid = FALSE;
+ U8 stream_dest_mac[6] = {0, 0, 0, 0, 0, 0};
+ U8 stream_vlan_id_valid = FALSE;
+ U16 stream_vlan_id = 0;
+ if ((pCmd->flags & OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_ID_VALID) != 0) {
+ stream_id_valid = TRUE;
+ memcpy(stream_src_mac, pCmd->stream_format, 6);
+ stream_uid = ntohs(*(U16*) (pCmd->stream_format + 6));
+ AVB_LOGF_INFO("AVDECC-specified Stream ID " ETH_FORMAT "/%u for Talker", ETH_OCTETS(stream_src_mac), stream_uid);
+ }
+ if ((pCmd->flags & OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_DEST_MAC_VALID) != 0) {
+ stream_dest_valid = TRUE;
+ memcpy(stream_dest_mac, pCmd->stream_dest_mac, 6);
+ AVB_LOGF_INFO("AVDECC-specified Stream Dest Addr " ETH_FORMAT " for Talker", ETH_OCTETS(stream_dest_mac));
+ }
+ if ((pCmd->flags & OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_VLAN_ID_VALID) != 0) {
+ stream_vlan_id_valid = TRUE;
+ stream_vlan_id = pCmd->stream_vlan_id;
+ AVB_LOGF_INFO("AVDECC-specified Stream VLAN ID %u for Talker", stream_vlan_id);
+ }
+
+ // Pass the values to the Talker.
+ if (!openavbAVDECCSetTalkerStreamInfo(
+ pDescriptorStreamIO, sr_class,
+ stream_id_valid, stream_src_mac, stream_uid,
+ stream_dest_valid, stream_dest_mac,
+ stream_vlan_id_valid, stream_vlan_id)) {
+ AVB_LOG_ERROR("SET_STREAM_INFO error setting stream parameters for Talker");
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_SUPPORTED;
+ }
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+ }
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_STREAM_IS_RUNNING;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_ENTITY_ACQUIRED;
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_STREAM_INFO:
+ {
+ openavb_aecp_command_data_get_stream_info_t *pCmd = &pCommand->entityModelPdu.command_data.getStreamInfoCmd;
+ openavb_aecp_response_data_get_stream_info_t *pRsp = &pCommand->entityModelPdu.command_data.getStreamInfoRsp;
+
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+
+ if (pRsp->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT ||
+ pRsp->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT) {
+ U16 configIdx = openavbAemGetConfigIdx();
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamIO = openavbAemGetDescriptor(configIdx, pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorStreamIO && pDescriptorStreamIO->stream) {
+ openavbAvdeccMsgStateType_t clientState = openavbAVDECCGetStreamingState(pDescriptorStreamIO, configIdx);
+
+ // Get the flags for the current status.
+ pRsp->flags = 0;
+ if (pDescriptorStreamIO->fast_connect_status >= OPENAVB_FAST_CONNECT_STATUS_IN_PROGRESS) {
+ pRsp->flags |= OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_FAST_CONNECT;
+ }
+ if (openavbAvdeccGetSaveStateInfo(pDescriptorStreamIO->stream, NULL, NULL, NULL, NULL)) {
+ pRsp->flags |= OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_SAVED_STATE;
+ }
+ if (clientState >= OPENAVB_AVDECC_MSG_RUNNING) {
+ pRsp->flags |= (pDescriptorStreamIO->acmp_flags &
+ (OPENAVB_ACMP_FLAG_CLASS_B |
+ OPENAVB_ACMP_FLAG_FAST_CONNECT |
+ OPENAVB_ACMP_FLAG_SUPPORTS_ENCRYPTED |
+ OPENAVB_ACMP_FLAG_ENCRYPTED_PDU));
+ pRsp->flags |= OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_CONNECTED;
+ if (clientState == OPENAVB_AVDECC_MSG_PAUSED) {
+ pRsp->flags |= OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAMING_WAIT;
+ }
+
+ // For the Listener, use the streaming values we received from the current Talker.
+ if (pRsp->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT) {
+ // Get the Stream ID.
+ memcpy(pRsp->stream_id, pDescriptorStreamIO->acmp_stream_id, 8);
+ if (memcmp(pRsp->stream_id, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) != 0) {
+ pRsp->flags |= OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_ID_VALID;
+ }
+
+ // Get the Destination MAC Address.
+ memcpy(pRsp->stream_dest_mac, pDescriptorStreamIO->acmp_dest_addr, 6);
+ if (memcmp(pRsp->stream_id, "\x00\x00\x00\x00\x00\x00", 6) != 0) {
+ pRsp->flags |= OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_DEST_MAC_VALID;
+ }
+
+ // Get the Stream VLAN ID if the other stream identifiers are valid.
+ if ((pRsp->flags & (OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_ID_VALID | OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_DEST_MAC_VALID)) ==
+ (OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_ID_VALID | OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_DEST_MAC_VALID)) {
+ pRsp->stream_vlan_id = pDescriptorStreamIO->acmp_stream_vlan_id;
+ pRsp->flags |= OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_VLAN_ID_VALID;
+ }
+ }
+ }
+
+ // For the Talker, use the values we are or will use for a connection.
+ if (pRsp->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT) {
+ // Get the Stream ID.
+ if (pDescriptorStreamIO->stream->stream_addr.mac != NULL) {
+ memcpy(pRsp->stream_id, pDescriptorStreamIO->stream->stream_addr.buffer.ether_addr_octet, 6);
+ *(U16*)(pRsp->stream_id) = htons(pDescriptorStreamIO->stream->stream_uid);
+ if (memcmp(pRsp->stream_id, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) != 0) {
+ pRsp->flags |= OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_ID_VALID;
+ }
+ }
+
+ // Get the Destination MAC Address.
+ if (pDescriptorStreamIO->stream->dest_addr.mac != NULL) {
+ memcpy(pRsp->stream_dest_mac, pDescriptorStreamIO->stream->dest_addr.buffer.ether_addr_octet, 6);
+ if (memcmp(pRsp->stream_id, "\x00\x00\x00\x00\x00\x00", 6) != 0) {
+ pRsp->flags |= OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_DEST_MAC_VALID;
+ }
+ }
+
+ // Get the Stream VLAN ID.
+ if (pDescriptorStreamIO->stream->vlan_id != 0) {
+ pRsp->stream_vlan_id = pDescriptorStreamIO->stream->vlan_id;
+ pRsp->flags |= OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_VLAN_ID_VALID;
+ }
+ }
+
+ // AVDECC_TODO: Add TALKER_FAILED flag support.
+
+ // Get the stream format.
+ openavbAemStreamFormatToBuf(&pDescriptorStreamIO->current_format, pRsp->stream_format);
+ pRsp->flags |= OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_FORMAT_VALID;
+
+ // AVDECC_TODO: Add support for msrp_accumulated_latency
+ // AVDECC_TODO: Add support for msrp_failure_bridge_id, and msrp_failure_code
+
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_NAME:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_NAME:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_ASSOCIATION_ID:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_ASSOCIATION_ID:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_SAMPLING_RATE:
+ {
+ openavb_aecp_commandresponse_data_set_sampling_rate_t *pCmd = &pCommand->entityModelPdu.command_data.setSamplingRateCmd;
+ openavb_aecp_commandresponse_data_set_sampling_rate_t *pRsp = &pCommand->entityModelPdu.command_data.setSamplingRateRsp;
+
+ if (processCommandCheckRestriction_CorrectController()) {
+ if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_AUDIO_UNIT) {
+ openavb_aem_descriptor_audio_unit_t *pDescriptorAudioUnit = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorAudioUnit) {
+ if (memcmp(&pDescriptorAudioUnit->current_sampling_rate, pCmd->sampling_rate, sizeof(pDescriptorAudioUnit->current_sampling_rate)) == 0) {
+ // No change needed.
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ else {
+ // AVDECC_TODO: Verify that the sample rate is supported, and notify the Talker/Listener of the change.
+ //memcpy(&pDescriptorAudioUnit->current_sampling_rate, pCmd->sampling_rate, sizeof(pDescriptorAudioUnit->current_sampling_rate));
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_SUPPORTED;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_IMPLEMENTED;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_ENTITY_ACQUIRED;
+ }
+
+ if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_AUDIO_UNIT) {
+ openavb_aem_descriptor_audio_unit_t *pDescriptorAudioUnit = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorAudioUnit) {
+ memcpy(pRsp->sampling_rate, &pDescriptorAudioUnit->current_sampling_rate, sizeof(pRsp->sampling_rate));
+ }
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_SAMPLING_RATE:
+ {
+ openavb_aecp_command_data_get_sampling_rate_t *pCmd = &pCommand->entityModelPdu.command_data.getSamplingRateCmd;
+ openavb_aecp_response_data_get_sampling_rate_t *pRsp = &pCommand->entityModelPdu.command_data.getSamplingRateRsp;
+
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+
+ if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_AUDIO_UNIT) {
+ openavb_aem_descriptor_audio_unit_t *pDescriptorAudioUnit = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorAudioUnit) {
+ U8 *pSrDst = (U8*)(pRsp->sampling_rate);
+ memset(pRsp->sampling_rate, 0, sizeof(pRsp->sampling_rate));
+ BIT_D2BHTONL(pSrDst, pDescriptorAudioUnit->current_sampling_rate.pull, 29, 0);
+ BIT_D2BHTONL(pSrDst, pDescriptorAudioUnit->current_sampling_rate.base, 0, 0);
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_CLOCK_SOURCE:
+ {
+ openavb_aecp_commandresponse_data_set_clock_source_t *pCmd = &pCommand->entityModelPdu.command_data.setClockSourceCmd;
+ openavb_aecp_commandresponse_data_set_clock_source_t *pRsp = &pCommand->entityModelPdu.command_data.setClockSourceRsp;
+
+ if (processCommandCheckRestriction_CorrectController()) {
+ if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_CLOCK_DOMAIN) {
+ openavb_aem_descriptor_clock_domain_t *pDescriptorClockDomain = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorClockDomain) {
+ if (pDescriptorClockDomain->clock_source_index == pCmd->clock_source_index) {
+ // No change needed.
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ else {
+ // AVDECC_TODO: Verify that the clock source is supported, and notify the Talker/Listener of the change.
+ //pDescriptorClockDomain->clock_source_index = pCmd->clock_source_index;
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_SUPPORTED;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_IMPLEMENTED;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_ENTITY_ACQUIRED;
+ }
+
+ if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_CLOCK_DOMAIN) {
+ openavb_aem_descriptor_clock_domain_t *pDescriptorClockDomain = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorClockDomain) {
+ pRsp->clock_source_index = pDescriptorClockDomain->clock_source_index;
+ }
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_CLOCK_SOURCE:
+ {
+ openavb_aecp_command_data_get_clock_source_t *pCmd = &pCommand->entityModelPdu.command_data.getClockSourceCmd;
+ openavb_aecp_response_data_get_clock_source_t *pRsp = &pCommand->entityModelPdu.command_data.getClockSourceRsp;
+
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+
+ if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_CLOCK_DOMAIN) {
+ openavb_aem_descriptor_clock_domain_t *pDescriptorClockDomain = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorClockDomain) {
+ pRsp->clock_source_index = pDescriptorClockDomain->clock_source_index;
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_CONTROL:
+ {
+ openavb_aecp_commandresponse_data_set_control_t *pCmd = &pCommand->entityModelPdu.command_data.setControlCmd;
+ openavb_aecp_commandresponse_data_set_control_t *pRsp = &pCommand->entityModelPdu.command_data.setControlRsp;
+
+ if (processCommandCheckRestriction_CorrectController()) {
+ if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_CONTROL) {
+ openavb_aem_descriptor_control_t *pDescriptorControl = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorControl) {
+ pDescriptorControl->number_of_values = pCmd->valuesCount;
+ int i1;
+ for (i1 = 0; i1 < pCmd->valuesCount; i1++) {
+ switch (pDescriptorControl->control_value_type) {
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT8:
+ pDescriptorControl->value_details.linear_int8[i1].current = pCmd->values.linear_int8[i1];
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT8:
+ pDescriptorControl->value_details.linear_uint8[i1].current = pCmd->values.linear_uint8[i1];
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT16:
+ pDescriptorControl->value_details.linear_int16[i1].current = pCmd->values.linear_int16[i1];
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT16:
+ pDescriptorControl->value_details.linear_uint16[i1].current = pCmd->values.linear_uint16[i1];
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT32:
+ pDescriptorControl->value_details.linear_int32[i1].current = pCmd->values.linear_int32[i1];
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT32:
+ pDescriptorControl->value_details.linear_uint32[i1].current = pCmd->values.linear_uint32[i1];
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT64:
+ pDescriptorControl->value_details.linear_int64[i1].current = pCmd->values.linear_int64[i1];
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT64:
+ pDescriptorControl->value_details.linear_uint64[i1].current = pCmd->values.linear_uint64[i1];
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_FLOAT:
+ pDescriptorControl->value_details.linear_float[i1].current = pCmd->values.linear_float[i1];
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_DOUBLE:
+ pDescriptorControl->value_details.linear_double[i1].current = pCmd->values.linear_double[i1];
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_FLOAT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_DOUBLE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_STRING:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_FLOAT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_DOUBLE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_UTF8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_BODE_PLOT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SMPTE_TIME:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SAMPLE_RATE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_GPTP_TIME:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_VENDOR:
+ break;
+ }
+ }
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_IMPLEMENTED;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_ENTITY_ACQUIRED;
+ }
+
+ // Populate response
+ if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_CONTROL) {
+ openavb_aem_descriptor_control_t *pDescriptorControl = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorControl) {
+ int i1;
+ for (i1 = 0; i1 < pDescriptorControl->number_of_values; i1++) {
+ switch (pDescriptorControl->control_value_type) {
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT8:
+ pRsp->values.linear_int8[i1] = pDescriptorControl->value_details.linear_int8[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT8:
+ pRsp->values.linear_uint8[i1] = pDescriptorControl->value_details.linear_uint8[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT16:
+ pRsp->values.linear_int16[i1] = pDescriptorControl->value_details.linear_int16[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT16:
+ pRsp->values.linear_uint16[i1] = pDescriptorControl->value_details.linear_uint16[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT32:
+ pRsp->values.linear_int32[i1] = pDescriptorControl->value_details.linear_int32[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT32:
+ pRsp->values.linear_uint32[i1] = pDescriptorControl->value_details.linear_uint32[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT64:
+ pRsp->values.linear_int64[i1] = pDescriptorControl->value_details.linear_int64[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT64:
+ pRsp->values.linear_uint64[i1] = pDescriptorControl->value_details.linear_uint64[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_FLOAT:
+ pRsp->values.linear_float[i1] = pDescriptorControl->value_details.linear_float[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_DOUBLE:
+ pRsp->values.linear_double[i1] = pDescriptorControl->value_details.linear_double[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_FLOAT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_DOUBLE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_STRING:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_FLOAT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_DOUBLE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_UTF8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_BODE_PLOT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SMPTE_TIME:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SAMPLE_RATE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_GPTP_TIME:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_VENDOR:
+ break;
+ }
+ }
+ }
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_CONTROL:
+ {
+ openavb_aecp_commandresponse_data_set_control_t *pCmd = &pCommand->entityModelPdu.command_data.setControlCmd;
+ openavb_aecp_commandresponse_data_set_control_t *pRsp = &pCommand->entityModelPdu.command_data.setControlRsp;
+
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+
+ if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_CONTROL) {
+ openavb_aem_descriptor_control_t *pDescriptorControl = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorControl) {
+ int i1;
+ for (i1 = 0; i1 < pDescriptorControl->number_of_values; i1++) {
+ switch (pDescriptorControl->control_value_type) {
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT8:
+ pRsp->values.linear_int8[i1] = pDescriptorControl->value_details.linear_int8[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT8:
+ pRsp->values.linear_uint8[i1] = pDescriptorControl->value_details.linear_uint8[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT16:
+ pRsp->values.linear_int16[i1] = pDescriptorControl->value_details.linear_int16[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT16:
+ pRsp->values.linear_uint16[i1] = pDescriptorControl->value_details.linear_uint16[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT32:
+ pRsp->values.linear_int32[i1] = pDescriptorControl->value_details.linear_int32[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT32:
+ pRsp->values.linear_uint32[i1] = pDescriptorControl->value_details.linear_uint32[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT64:
+ pRsp->values.linear_int64[i1] = pDescriptorControl->value_details.linear_int64[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT64:
+ pRsp->values.linear_uint64[i1] = pDescriptorControl->value_details.linear_uint64[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_FLOAT:
+ pRsp->values.linear_float[i1] = pDescriptorControl->value_details.linear_float[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_DOUBLE:
+ pRsp->values.linear_double[i1] = pDescriptorControl->value_details.linear_double[i1].current;
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_FLOAT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_DOUBLE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_STRING:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_FLOAT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_DOUBLE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_UTF8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_BODE_PLOT:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SMPTE_TIME:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SAMPLE_RATE:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_GPTP_TIME:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_VENDOR:
+ break;
+ }
+ }
+ }
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_INCREMENT_CONTROL:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DECREMENT_CONTROL:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_SIGNAL_SELECTOR:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_SIGNAL_SELECTOR:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_MIXER:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_MIXER:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_MATRIX:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_MATRIX:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_START_STREAMING:
+ {
+ openavb_aecp_commandresponse_data_start_streaming_t *pCmd = &pCommand->entityModelPdu.command_data.startStreamingCmd;
+ //openavb_aecp_commandresponse_data_start_streaming_t *pRsp = &pCommand->entityModelPdu.command_data.startStreamingRsp;
+
+ if (processCommandCheckRestriction_CorrectController()) {
+ if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT) {
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorStreamInput) {
+ openavbAVDECCPauseStream(pDescriptorStreamInput, FALSE);
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+ }
+ }
+ else if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT) {
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorStreamOutput) {
+ openavbAVDECCPauseStream(pDescriptorStreamOutput, FALSE);
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_IMPLEMENTED;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_ENTITY_ACQUIRED;
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_STOP_STREAMING:
+ {
+ openavb_aecp_commandresponse_data_start_streaming_t *pCmd = &pCommand->entityModelPdu.command_data.startStreamingCmd;
+ //openavb_aecp_commandresponse_data_start_streaming_t *pRsp = &pCommand->entityModelPdu.command_data.startStreamingRsp;
+
+ if (processCommandCheckRestriction_CorrectController()) {
+ if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT) {
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorStreamInput) {
+ openavbAVDECCPauseStream(pDescriptorStreamInput, TRUE);
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+ }
+ }
+ else if (pCmd->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT) {
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput = openavbAemGetDescriptor(openavbAemGetConfigIdx(), pCmd->descriptor_type, pCmd->descriptor_index);
+ if (pDescriptorStreamOutput) {
+ openavbAVDECCPauseStream(pDescriptorStreamOutput, TRUE);
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_SUCCESS;
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_NOT_IMPLEMENTED;
+ }
+ }
+ else {
+ pCommand->headers.status = OPENAVB_AEM_COMMAND_STATUS_ENTITY_ACQUIRED;
+ }
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REGISTER_UNSOLICITED_NOTIFICATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DEREGISTER_UNSOLICITED_NOTIFICATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_IDENTIFY_NOTIFICATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_AVB_INFO:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_AS_PATH:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_COUNTERS:
+ {
+ openavb_aecp_command_data_get_counters_t *pCmd = &pCommand->entityModelPdu.command_data.getCountersCmd;
+ openavb_aecp_response_data_get_counters_t *pRsp = &pCommand->entityModelPdu.command_data.getCountersRsp;
+ pCommand->headers.status = openavbAecpCommandGetCountersHandler(pCmd, pRsp);
+ }
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REBOOT:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_AUDIO_MAP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ADD_AUDIO_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REMOVE_AUDIO_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_VIDEO_MAP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ADD_VIDEO_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REMOVE_VIDEO_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_SENSOR_MAP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ADD_SENSOR_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_REMOVE_SENSOR_MAPPINGS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_START_OPERATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ABORT_OPERATION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_OPERATION_STATUS:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_ADD_KEY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_DELETE_KEY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_GET_KEY_LIST:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_GET_KEY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_ADD_KEY_TO_CHAIN:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_DELETE_KEY_FROM_CHAIN:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_GET_KEYCHAIN_LIST:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_GET_IDENTITY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_ADD_TOKEN:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTH_DELETE_TOKEN:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_AUTHENTICATE:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DEAUTHENTICATE:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ENABLE_TRANSPORT_SECURITY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DISABLE_TRANSPORT_SECURITY:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_ENABLE_STREAM_ENCRYPTION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_DISABLE_STREAM_ENCRYPTION:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_MEMORY_OBJECT_LENGTH:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_MEMORY_OBJECT_LENGTH:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_SET_STREAM_BACKUP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_GET_STREAM_BACKUP:
+ break;
+ case OPENAVB_AEM_COMMAND_CODE_EXPANSION:
+ break;
+ default:
+ break;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
+
+void openavbAecpSMEntityModelEntityStateMachine()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+ bool bRunning = TRUE;
+
+ openavb_aecp_sm_entity_model_entity_state_t state = OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_WAITING;
+
+ // Lock such that the mutex is held unless waiting for a semaphore. Synchronous processing of command responses.
+ AECP_SM_LOCK();
+ while (bRunning) {
+ switch (state) {
+ case OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_WAITING:
+ AVB_LOG_DEBUG("State: OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_WAITING");
+ openavbAecpSMEntityModelEntityVars.rcvdAEMCommand = FALSE;
+ openavbAecpSMEntityModelEntityVars.doUnsolicited = FALSE;
+
+ // Wait for a change in state
+ while (state == OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_WAITING && bRunning) {
+ AECP_SM_UNLOCK();
+ SEM_ERR_T(err);
+ SEM_WAIT(openavbAecpSMEntityModelEntityWaitingSemaphore, err);
+ AECP_SM_LOCK();
+
+ if (SEM_IS_ERR_NONE(err)) {
+ if (openavbAecpSMEntityModelEntityVars.doTerminate) {
+ bRunning = FALSE;
+ }
+ else if (openavbAecpSMEntityModelEntityVars.doUnsolicited) {
+ state = OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_UNSOLICITED_RESPONSE;
+ }
+ else if (openavbAecpSMEntityModelEntityVars.rcvdAEMCommand) {
+ state = OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_RECEIVED_COMMAND;
+ }
+ }
+ }
+ break;
+
+ case OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_UNSOLICITED_RESPONSE:
+ AVB_LOG_DEBUG("State: OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_UNSOLICITED_RESPONSE");
+
+ state = OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_WAITING;
+ break;
+
+ case OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_RECEIVED_COMMAND:
+ AVB_LOG_DEBUG("State: OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_RECEIVED_COMMAND");
+
+ while (TRUE) {
+ openavbAecpSMEntityModelEntityVars.rcvdCommand = getNextCommandFromQueue();
+ if (openavbAecpSMEntityModelEntityVars.rcvdCommand == NULL) {
+ break;
+ }
+
+ if (memcmp(openavbAecpSMEntityModelEntityVars.rcvdCommand->headers.target_entity_id,
+ openavbAecpSMGlobalVars.myEntityID,
+ sizeof(openavbAecpSMGlobalVars.myEntityID)) != 0) {
+ // Not intended for us.
+ free(openavbAecpSMEntityModelEntityVars.rcvdCommand);
+ continue;
+ }
+
+ if (openavbAecpSMEntityModelEntityVars.rcvdCommand->entityModelPdu.command_type == OPENAVB_AEM_COMMAND_CODE_ACQUIRE_ENTITY) {
+ acquireEntity();
+ }
+ else if (openavbAecpSMEntityModelEntityVars.rcvdCommand->entityModelPdu.command_type == OPENAVB_AEM_COMMAND_CODE_LOCK_ENTITY) {
+ lockEntity();
+ }
+ else if (openavbAecpSMEntityModelEntityVars.rcvdCommand->entityModelPdu.command_type == OPENAVB_AEM_COMMAND_CODE_ENTITY_AVAILABLE) {
+ // State machine defines just returning the request command. Doing that in the processCommand function for consistency.
+ processCommand();
+ }
+ else {
+ processCommand();
+ }
+
+ openavbAecpMessageSend(openavbAecpSMEntityModelEntityVars.rcvdCommand);
+ free(openavbAecpSMEntityModelEntityVars.rcvdCommand);
+ }
+
+ state = OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_STATE_WAITING;
+ break;
+
+ default:
+ AVB_LOG_ERROR("State: Unknown");
+ bRunning = FALSE; // Unexpected
+ break;
+
+ }
+ }
+ AECP_SM_UNLOCK();
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
+
+void* openavbAecpSMEntityModelEntityThreadFn(void *pv)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+ openavbAecpSMEntityModelEntityStateMachine();
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+ return NULL;
+}
+
+void openavbAecpSMEntityModelEntityStart()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ MUTEX_ATTR_HANDLE(mtq);
+ MUTEX_ATTR_INIT(mtq);
+ MUTEX_ATTR_SET_TYPE(mtq, MUTEX_ATTR_TYPE_DEFAULT);
+ MUTEX_ATTR_SET_NAME(mtq, "openavbAecpQueueMutex");
+ MUTEX_CREATE_ERR();
+ MUTEX_CREATE(openavbAecpQueueMutex, mtq);
+ MUTEX_LOG_ERR("Could not create/initialize 'openavbAecpQueueMutex' mutex");
+
+ MUTEX_ATTR_HANDLE(mta);
+ MUTEX_ATTR_INIT(mta);
+ MUTEX_ATTR_SET_TYPE(mta, MUTEX_ATTR_TYPE_DEFAULT);
+ MUTEX_ATTR_SET_NAME(mta, "openavbAecpSMMutex");
+ MUTEX_CREATE(openavbAecpSMMutex, mta);
+ MUTEX_LOG_ERR("Could not create/initialize 'openavbAecpSMMutex' mutex");
+
+ SEM_ERR_T(err);
+ SEM_INIT(openavbAecpSMEntityModelEntityWaitingSemaphore, 1, err);
+ SEM_LOG_ERR(err);
+
+ // Initialize the linked list (queue).
+ s_commandQueue = openavbListNewList();
+
+ // Start the Advertise Entity State Machine
+ bool errResult;
+ THREAD_CREATE(openavbAecpSMEntityModelEntityThread, openavbAecpSMEntityModelEntityThread, NULL, openavbAecpSMEntityModelEntityThreadFn, NULL);
+ THREAD_CHECK_ERROR(openavbAecpSMEntityModelEntityThread, "Thread / task creation failed", errResult);
+ if (errResult); // Already reported
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
+
+void openavbAecpSMEntityModelEntityStop()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ openavbAecpSMEntityModelEntitySet_doTerminate(TRUE);
+
+ THREAD_JOIN(openavbAecpSMEntityModelEntityThread, NULL);
+
+ // Delete the linked list (queue).
+ openavb_aecp_AEMCommandResponse_t *item;
+ while ((item = getNextCommandFromQueue()) != NULL) {
+ free(item);
+ }
+ openavbListDeleteList(s_commandQueue);
+
+ SEM_ERR_T(err);
+ SEM_DESTROY(openavbAecpSMEntityModelEntityWaitingSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ MUTEX_CREATE_ERR();
+ MUTEX_DESTROY(openavbAecpQueueMutex);
+ MUTEX_LOG_ERR("Could not destroy 'openavbAecpQueueMutex' mutex");
+ MUTEX_DESTROY(openavbAecpSMMutex);
+ MUTEX_LOG_ERR("Could not destroy 'openavbAecpSMMutex' mutex");
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
+
+void openavbAecpSMEntityModelEntitySet_rcvdCommand(openavb_aecp_AEMCommandResponse_t *rcvdCommand)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+
+ if (memcmp(rcvdCommand->headers.target_entity_id,
+ openavbAecpSMGlobalVars.myEntityID,
+ sizeof(openavbAecpSMGlobalVars.myEntityID)) != 0) {
+ // Not intended for us.
+ free(rcvdCommand);
+ return;
+ }
+
+ int result = addCommandToQueue(rcvdCommand);
+ if (result < 0) {
+ AVB_LOG_DEBUG("addCommandToQueue failed");
+ free(rcvdCommand);
+ }
+ else if (result == 0) {
+ // We just added an item to an empty queue.
+ // Notify the machine state thread that something is waiting.
+ AECP_SM_LOCK();
+ openavbAecpSMEntityModelEntityVars.rcvdAEMCommand = TRUE;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAecpSMEntityModelEntityWaitingSemaphore, err);
+ SEM_LOG_ERR(err);
+ AECP_SM_UNLOCK();
+ }
+ else {
+ // We added an item to a non-empty queue.
+ // Assume it will be handled when the other items in the queue are handled.
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
+
+void openavbAecpSMEntityModelEntitySet_unsolicited(openavb_aecp_AEMCommandResponse_t *unsolicited)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+ AECP_SM_LOCK();
+ memcpy(&openavbAecpSMEntityModelEntityVars.unsolicited, unsolicited, sizeof(*unsolicited));
+ openavbAecpSMEntityModelEntityVars.doUnsolicited = TRUE;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAecpSMEntityModelEntityWaitingSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ AECP_SM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
+
+void openavbAecpSMEntityModelEntitySet_doTerminate(bool value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AECP);
+ AECP_SM_LOCK();
+ openavbAecpSMEntityModelEntityVars.doTerminate = value;
+
+ SEM_ERR_T(err);
+ SEM_POST(openavbAecpSMEntityModelEntityWaitingSemaphore, err);
+ SEM_LOG_ERR(err);
+
+ AECP_SM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_AECP);
+}
diff --git a/lib/avtp_pipeline/aecp/openavb_aecp_sm_entity_model_entity.h b/lib/avtp_pipeline/aecp/openavb_aecp_sm_entity_model_entity.h
new file mode 100644
index 00000000..5d234b15
--- /dev/null
+++ b/lib/avtp_pipeline/aecp/openavb_aecp_sm_entity_model_entity.h
@@ -0,0 +1,71 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AVDECC Enumeration and control protocol (AECP) : Entity Model Entity State Machine Interface
+ * MODULE SUMMARY : Interface for the AVDECC Enumeration and control protocol (AECP) : Entity Model Entity State Machine
+ * IEEE Std 1722.1-2013 clause 9.2.2.3
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_H
+#define OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_H 1
+
+#include "openavb_aecp.h"
+
+// State machine vars IEEE Std 1722.1-2013 clause 9.2.2.3.1.2
+typedef struct {
+ openavb_aecp_AEMCommandResponse_t *rcvdCommand;
+ bool rcvdAEMCommand;
+ openavb_aecp_AEMCommandResponse_t unsolicited;
+ bool doUnsolicited;
+
+ // Not part of spec
+ bool doTerminate;
+} openavb_aecp_sm_entity_model_entity_vars_t;
+
+// State machine functions IEEE Std 1722.1-2013 clause 9.2.2.3.1.3
+void acquireEntity(void);
+void lockEntity(void);
+void processCommand(void);
+
+void openavbAecpSMEntityModelEntityStart(void);
+void openavbAecpSMEntityModelEntityStop(void);
+
+// Accessors
+void openavbAecpSMEntityModelEntitySet_rcvdCommand(openavb_aecp_AEMCommandResponse_t *rcvdCommand);
+ // Note: rcvdAEMCommand is set during the call to openavbAecpSMEntityModelEntitySet_rcvdCommand()
+void openavbAecpSMEntityModelEntitySet_unsolicited(openavb_aecp_AEMCommandResponse_t *unsolicited);
+ // Note: doUnsolicited is set during the call to openavbAecpSMEntityModelEntitySet_unsolicited()
+void openavbAecpSMEntityModelEntitySet_doTerminate(bool value);
+
+#endif // OPENAVB_AECP_SM_ENTITY_MODEL_ENTITY_H
diff --git a/lib/avtp_pipeline/aem/CMakeLists.txt b/lib/avtp_pipeline/aem/CMakeLists.txt
new file mode 100644
index 00000000..276e403a
--- /dev/null
+++ b/lib/avtp_pipeline/aem/CMakeLists.txt
@@ -0,0 +1,21 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/aem/openavb_aem.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_entity.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_configuration.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_audio_unit.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_locale.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_strings.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_stream_io.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_jack_io.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_avb_interface.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_clock_source.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_stream_port_io.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_external_port_io.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_audio_cluster.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_audio_map.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_control.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_clock_domain.c
+ ${AVB_SRC_DIR}/aem/openavb_descriptor_locale_strings_handler.c
+ PARENT_SCOPE
+)
+
diff --git a/lib/avtp_pipeline/aem/openavb_aem.c b/lib/avtp_pipeline/aem/openavb_aem.c
new file mode 100644
index 00000000..e9f0f4de
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_aem.c
@@ -0,0 +1,534 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Entity Model
+ * MODULE SUMMARY : Implements the 1722.1 (AVDECC) Entity Model
+ ******************************************************************
+ */
+
+#include "stdlib.h"
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_avdecc.h"
+#include "openavb_aem.h"
+
+MUTEX_HANDLE(openavbAemMutex);
+#define AEM_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(openavbAemMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define AEM_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(openavbAemMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+static openavb_avdecc_entity_model_t *pAemEntityModel = NULL;
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemCreate(openavb_aem_descriptor_entity_t *pDescriptorEntity)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ MUTEX_ATTR_HANDLE(mta);
+ MUTEX_ATTR_INIT(mta);
+ MUTEX_ATTR_SET_TYPE(mta, MUTEX_ATTR_TYPE_DEFAULT);
+ MUTEX_ATTR_SET_NAME(mta, "openavbAemMutex");
+ MUTEX_CREATE_ERR();
+ MUTEX_CREATE(openavbAemMutex, mta);
+ MUTEX_LOG_ERR("Could not create/initialize 'openavbAemMutex' mutex");
+
+ if (!pDescriptorEntity) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_ENTITY_MODEL_MISSING), AVB_TRACE_AEM);
+ }
+
+ if (!pAemEntityModel) {
+ pAemEntityModel = calloc(1, sizeof(*pAemEntityModel));
+ }
+
+ if (!pAemEntityModel) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY), AVB_TRACE_AEM);
+ }
+
+ pAemEntityModel->pDescriptorEntity = pDescriptorEntity;
+ pAemEntityModel->aemConfigurations = openavbArrayNewArray(sizeof(openavb_aem_configuration_t));
+ memset(pAemEntityModel->aemNonTopLevelDescriptorsArray, 0, sizeof(pAemEntityModel->aemNonTopLevelDescriptorsArray));
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDestroy()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+ // AVDECC_TODO all deallocations will occur here
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+bool openavbAemCheckModel(bool bLog)
+{
+ if (!pAemEntityModel || !pAemEntityModel->pDescriptorEntity) {
+ if (bLog) {
+ AVB_RC_LOG(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_ENTITY_MODEL_MISSING);
+ }
+ return FALSE;
+ }
+ return TRUE;
+}
+
+openavbRC openavbAemAddDescriptorToConfiguration(U16 descriptorType, U16 configIdx)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+ int i1;
+
+ // Make sure Entity Model is created
+ if (!openavbAemCheckModel(FALSE)) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_ENTITY_MODEL_MISSING), AVB_TRACE_AEM);
+ }
+
+ if (configIdx == OPENAVB_AEM_DESCRIPTOR_INVALID) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_INVALID_CONFIG_IDX), AVB_TRACE_AEM);
+ }
+ openavb_aem_configuration_t *pConfiguration = openavbArrayDataIdx(pAemEntityModel->aemConfigurations, configIdx);
+ if (!pConfiguration) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_INVALID_CONFIG_IDX), AVB_TRACE_AEM);
+ }
+
+ openavb_aem_descriptor_configuration_t *pConfig = pConfiguration->pDescriptorConfiguration;
+ if (!pConfig) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_INVALID_CONFIG_IDX), AVB_TRACE_AEM);
+ }
+
+ // Check if the new descriptor type is in the configuration array
+ for (i1 = 0; i1 < pConfig->descriptor_counts_count; i1++) {
+ if (pConfig->descriptor_counts[i1].descriptor_type == descriptorType) {
+ // Found this descriptor type so just increase the count.
+ pConfig->descriptor_counts[i1].count++;
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+ }
+ }
+
+ // Update counts
+ pConfig->descriptor_counts[pConfig->descriptor_counts_count].descriptor_type = descriptorType;
+ pConfig->descriptor_counts[pConfig->descriptor_counts_count].count++;
+ pConfig->descriptor_counts_count++;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavb_avdecc_entity_model_t *openavbAemGetModel()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pAemEntityModel;
+}
+
+openavb_array_t openavbAemGetDescriptorArray(U16 configIdx, U16 descriptorType)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_array_t retDescriptors = NULL;
+
+ // Make sure Entity Model is created
+ if (!openavbAemCheckModel(TRUE)) {
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ if (descriptorType == OPENAVB_AEM_DESCRIPTOR_ENTITY) {
+ // There is always only a single Entity Descriptor and therefore there isn't an array. NULL will be returned.
+ }
+ else if (descriptorType == OPENAVB_AEM_DESCRIPTOR_CONFIGURATION) {
+ // The configuration descriptor is a special descriptor and not return by this function. NULL will be returned.
+ }
+ else {
+ if (configIdx != OPENAVB_AEM_DESCRIPTOR_INVALID) {
+ openavb_aem_configuration_t *pConfig = openavbArrayDataIdx(pAemEntityModel->aemConfigurations, configIdx);
+ if (pConfig) {
+ retDescriptors = pConfig->descriptorsArray[descriptorType];
+ }
+ }
+
+ // Search the alternate location for non-top-level descriptors.
+ if (!retDescriptors) {
+ retDescriptors = pAemEntityModel->aemNonTopLevelDescriptorsArray[descriptorType];
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return retDescriptors;
+}
+
+void *openavbAemFindDescriptor(U16 configIdx, U16 descriptorType, U16 descriptorIdx)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ void *retDescriptor = NULL;
+
+ // Make sure Entity Model is created
+ if (!openavbAemCheckModel(TRUE)) {
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ if (descriptorType == OPENAVB_AEM_DESCRIPTOR_ENTITY) {
+ if (pAemEntityModel->pDescriptorEntity &&
+ pAemEntityModel->pDescriptorEntity->descriptor_index == descriptorIdx) {
+ retDescriptor = pAemEntityModel->pDescriptorEntity;
+ }
+ }
+ else if (descriptorType == OPENAVB_AEM_DESCRIPTOR_CONFIGURATION) {
+ if (configIdx != OPENAVB_AEM_DESCRIPTOR_INVALID) {
+ openavb_aem_configuration_t *pConfig = openavbArrayDataIdx(pAemEntityModel->aemConfigurations, configIdx);
+ if (pConfig &&
+ pConfig->pDescriptorConfiguration &&
+ pConfig->pDescriptorConfiguration->descriptor_index == descriptorIdx) {
+ retDescriptor = pConfig->pDescriptorConfiguration;
+ }
+ }
+ }
+ else {
+ openavb_array_t descriptors = NULL;
+ if (configIdx != OPENAVB_AEM_DESCRIPTOR_INVALID) {
+ openavb_aem_configuration_t *pConfig = openavbArrayDataIdx(pAemEntityModel->aemConfigurations, configIdx);
+ if (pConfig) {
+ descriptors = pConfig->descriptorsArray[descriptorType];
+ if (descriptors) {
+ retDescriptor = openavbArrayDataIdx(descriptors, descriptorIdx);
+ }
+ }
+ }
+
+ // Search the alternate location for non-top-level descriptors.
+ if (!retDescriptor) {
+ descriptors = pAemEntityModel->aemNonTopLevelDescriptorsArray[descriptorType];
+ if (descriptors) {
+ retDescriptor = openavbArrayDataIdx(descriptors, descriptorIdx);
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return retDescriptor;
+}
+
+openavbRC openavbAemSerializeDescriptor(U16 configIdx, U16 descriptorType, U16 descriptorIdx, U16 bufSize, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ // Make sure Entity Model is created
+ if (!openavbAemCheckModel(FALSE)) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_ENTITY_MODEL_MISSING), AVB_TRACE_AEM);
+ }
+
+ if (!pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ void *pDescriptor = openavbAemFindDescriptor(configIdx, descriptorType, descriptorIdx);
+ if (pDescriptor) {
+ openavb_aem_descriptor_common_t *pDescriptorCommon = pDescriptor;
+ if (IS_OPENAVB_FAILURE(pDescriptorCommon->descriptorPvtPtr->update(pDescriptor))) {
+ AVB_RC_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_STALE_DATA), AVB_TRACE_AEM);
+ }
+ if (IS_OPENAVB_FAILURE(pDescriptorCommon->descriptorPvtPtr->toBuf(pDescriptor, bufSize, pBuf, descriptorSize))) {
+ AVB_RC_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_GENERIC), AVB_TRACE_AEM);
+ }
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+ }
+
+ AVB_RC_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_UNKNOWN_DESCRIPTOR), AVB_TRACE_AEM);
+}
+
+bool openavbAemAddDescriptorConfiguration(openavb_aem_descriptor_configuration_t *pDescriptor, U16 *pResultIdx)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ // Make sure Entity Model is created
+ if (!openavbAemCheckModel(TRUE)) {
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ if (!pDescriptor || !pResultIdx) {
+ AVB_RC_LOG(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT);
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ // Allocate the new configuration structure
+ openavb_aem_configuration_t *pAemConfiguration = openavbArrayDataNew(pAemEntityModel->aemConfigurations);
+ if (!pAemConfiguration) {
+ AVB_RC_LOG(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY);
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ // Assign the descriptor to the new configuration
+ pAemConfiguration->pDescriptorConfiguration = pDescriptor;
+
+ // Set to return descriptor index and increment the count
+ S32 retIdx = openavbArrayFindData(pAemEntityModel->aemConfigurations, pAemConfiguration);
+ if (retIdx < 0) {
+ return FALSE;
+ }
+ *pResultIdx = retIdx;
+
+ pAemEntityModel->pDescriptorEntity->configurations_count++;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT U16 openavbAemGetConfigIdx()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ // This function does NOT check for errors but at a minimum avoid a crash.
+ if (!pAemEntityModel || !pAemEntityModel->pDescriptorEntity) {
+ AVB_RC_LOG(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_ENTITY_MODEL_MISSING);
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return 0;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pAemEntityModel->pDescriptorEntity->current_configuration;
+}
+
+
+extern DLL_EXPORT bool openavbAemAddDescriptor(void *pDescriptor, U16 configIdx, U16 *pResultIdx)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ // Make sure Entity Model is created
+ if (!openavbAemCheckModel(TRUE)) {
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ if (!pDescriptor || !pResultIdx) {
+ AVB_RC_LOG(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT);
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ openavb_aem_descriptor_common_t *pDescriptorCommon = pDescriptor;
+
+ if (pDescriptorCommon->descriptor_type == OPENAVB_AEM_DESCRIPTOR_ENTITY) {
+ // Entity Descriptors aren't handled in this function.
+ AVB_RC_LOG(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT);
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+ if (pDescriptorCommon->descriptor_type == OPENAVB_AEM_DESCRIPTOR_CONFIGURATION) {
+ // Configuration descriptors have special processing
+ bool result = openavbAemAddDescriptorConfiguration(pDescriptor, pResultIdx);
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return result;
+ }
+
+ openavb_array_t descriptors = NULL;
+ if (pDescriptorCommon->descriptorPvtPtr->bTopLevel) {
+ openavb_aem_configuration_t *pConfig = openavbArrayDataIdx(pAemEntityModel->aemConfigurations, configIdx);
+ if (!pConfig) {
+ AVB_RC_LOG(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT);
+ AVB_LOGF_ERROR("Invalid configuration index %u", configIdx);
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+ descriptors = pConfig->descriptorsArray[pDescriptorCommon->descriptor_type];
+
+ if (!descriptors) {
+ // Create array for this type of descriptor in this configuration
+ AVB_LOGF_DEBUG("Created description array for configuration %u, type 0x%04x", configIdx, pDescriptorCommon->descriptor_type);
+ descriptors = openavbArrayNewArray(pDescriptorCommon->descriptorPvtPtr->size);
+ pConfig->descriptorsArray[pDescriptorCommon->descriptor_type] = descriptors;
+ }
+ } else {
+ descriptors = pAemEntityModel->aemNonTopLevelDescriptorsArray[pDescriptorCommon->descriptor_type];
+
+ if (!descriptors) {
+ // Create array for this type of descriptor in this configuration
+ AVB_LOGF_DEBUG("Created non-top-level description array for type 0x%04x", pDescriptorCommon->descriptor_type);
+ descriptors = openavbArrayNewArray(pDescriptorCommon->descriptorPvtPtr->size);
+ pAemEntityModel->aemNonTopLevelDescriptorsArray[pDescriptorCommon->descriptor_type] = descriptors;
+ }
+ }
+
+ if (descriptors) {
+ if (openavbArrayFindData(descriptors, pDescriptor) >= 0) {
+ AVB_LOGF_ERROR("Attempted to add same descriptor (type 0x%04x) twice", pDescriptorCommon->descriptor_type);
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ openavb_array_elem_t elem = openavbArrayAdd(descriptors, pDescriptor);
+ if (elem) {
+ *pResultIdx = openavbArrayGetIdx(elem);
+ pDescriptorCommon->descriptor_index = *pResultIdx;
+ if (pDescriptorCommon->descriptorPvtPtr->bTopLevel) {
+ if (!IS_OPENAVB_SUCCESS(openavbAemAddDescriptorToConfiguration(pDescriptorCommon->descriptor_type, configIdx))) {
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+}
+
+extern DLL_EXPORT void *openavbAemGetDescriptor(U16 configIdx, U16 descriptorType, U16 descriptorIdx)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+ void *retDescriptor = NULL;
+
+ retDescriptor = openavbAemFindDescriptor(configIdx, descriptorType, descriptorIdx);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return retDescriptor;
+}
+
+extern DLL_EXPORT U16 openavbAemGetDescriptorIndex(U16 configIdx, const void *pDescriptor)
+{
+ const openavb_aem_descriptor_common_t *pDescriptorCommon = pDescriptor;
+ U16 descriptorIdx = 0;
+ void * pTest;
+
+ if (!pDescriptorCommon) { return OPENAVB_AEM_DESCRIPTOR_INVALID; }
+
+ do {
+ pTest = openavbAemFindDescriptor(configIdx, pDescriptorCommon->descriptor_type, descriptorIdx);
+ if (pTest == pDescriptor) { return descriptorIdx; }
+ descriptorIdx++;
+ } while (pTest != NULL);
+
+ return OPENAVB_AEM_DESCRIPTOR_INVALID;
+}
+
+extern DLL_EXPORT bool openavbAemSetString(U8 *pMem, const char *pString)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (pMem && pString) {
+ U32 len = strlen(pString);
+ if (len > OPENAVB_AEM_STRLEN_MAX) {
+ len = OPENAVB_AEM_STRLEN_MAX;
+ } else if (len < OPENAVB_AEM_STRLEN_MAX) {
+ memset(pMem + len, 0, OPENAVB_AEM_STRLEN_MAX - len);
+ }
+ memcpy(pMem, pString, len); // Per 1722.1 it is allowable that the AEM string may not be null terminated.
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+}
+
+extern DLL_EXPORT bool openavbAemIsAcquired()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+ AEM_LOCK();
+ bool bResult = pAemEntityModel->entityAcquired;
+ AEM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return bResult;
+}
+
+extern DLL_EXPORT bool openavbAemIsLocked()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+ AEM_LOCK();
+ bool bResult = pAemEntityModel->entityLocked;
+ AEM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return bResult;
+}
+
+extern DLL_EXPORT bool openavbAemAcquire(bool flag)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+ AEM_LOCK();
+ bool bResult = FALSE;
+ if (flag) {
+ if (!pAemEntityModel->entityAcquired) {
+ *(pAemEntityModel->acquiredControllerId) = (U64)0x0000000000000000L;
+ pAemEntityModel->entityAcquired = TRUE;
+ bResult = TRUE;
+ }
+ }
+ else {
+ if (pAemEntityModel->entityAcquired) {
+ if ((U64)*pAemEntityModel->acquiredControllerId == 0x0000000000000000L) {
+ // Only unacquire if controller ID is zero.
+ pAemEntityModel->entityAcquired = FALSE;
+ bResult = TRUE;
+ }
+ }
+ }
+ AEM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return bResult;
+}
+
+extern DLL_EXPORT bool openavbAemLock(bool flag)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+ AEM_LOCK();
+ bool bResult = FALSE;
+ if (flag) {
+ if (!pAemEntityModel->entityLocked) {
+ *(pAemEntityModel->lockedControllerId) = (U64)0x0000000000000000L;
+ pAemEntityModel->entityLocked = TRUE;
+ bResult = TRUE;
+ }
+ }
+ else {
+ if (pAemEntityModel->entityLocked) {
+ if ((U64)*pAemEntityModel->lockedControllerId == 0x0000000000000000L) {
+ // Only unlock if controller ID is zero.
+ pAemEntityModel->entityLocked = FALSE;
+ bResult = TRUE;
+ }
+ }
+ }
+ AEM_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return bResult;
+}
+
diff --git a/lib/avtp_pipeline/aem/openavb_aem.h b/lib/avtp_pipeline/aem/openavb_aem.h
new file mode 100644
index 00000000..acd8ec33
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_aem.h
@@ -0,0 +1,103 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Entity Model
+ * MODULE SUMMARY : Implements the 1722.1 (AVDECC) Entity Model
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_AEM_H
+#define OPENAVB_AEM_H 1
+
+#include "openavb_array.h"
+#include "openavb_avdecc.h"
+#include "openavb_aem_pub.h"
+#include "openavb_types_pub.h"
+#include "openavb_result_codes.h"
+#include "openavb_endpoint.h"
+
+typedef openavbRC (*openavb_aem_descriptor_to_buf_t)(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize);
+typedef openavbRC (*openavb_aem_descriptor_from_buf_t)(void *pVoidDescriptor, U16 bufLength, U8 *pBuf);
+typedef openavbRC (*openavb_aem_descriptor_update_t)(void *pVoidDescriptor);
+
+struct openavb_descriptor_pvt {
+ U32 size;
+ bool bTopLevel; // See IEEE Std 1722.1-2013 clause 7.2.2 for a list of top level descriptors.
+ openavb_aem_descriptor_to_buf_t toBuf;
+ openavb_aem_descriptor_from_buf_t fromBuf;
+ openavb_aem_descriptor_update_t update;
+};
+
+// Every descriptor must begin with these same members. The structure isn't embedded to make hosting applications cleaner.
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+ U16 descriptor_type;
+ U16 descriptor_index;
+} openavb_aem_descriptor_common_t;
+
+typedef struct {
+ openavb_aem_descriptor_configuration_t *pDescriptorConfiguration;
+ openavb_array_t descriptorsArray[OPENAVB_AEM_DESCRIPTOR_COUNT];
+} openavb_aem_configuration_t;
+
+typedef struct {
+ openavb_aem_descriptor_entity_t *pDescriptorEntity;
+ bool entityAcquired;
+ U8 acquiredControllerId[8];
+ bool entityLocked;
+ U8 lockedControllerId[8];
+
+ openavb_array_t aemConfigurations;
+ openavb_array_t aemNonTopLevelDescriptorsArray[OPENAVB_AEM_DESCRIPTOR_COUNT];
+} openavb_avdecc_entity_model_t;
+
+
+// Create the Entity Model
+openavbRC openavbAemCreate(openavb_aem_descriptor_entity_t *pDescriptorEntity);
+
+// Destory the Entity Model
+openavbRC openavbAemDestroy(void);
+
+// Return the Entity Model
+openavb_avdecc_entity_model_t *openavbAemGetModel(void);
+
+// Checks if the Entity Model is valid
+bool openavbAemCheckModel(bool bLog);
+
+// Return the array of descriptors for a specific descroptor type for the specified configuration.
+openavb_array_t openavbAemGetDescriptorArray(U16 configIdx, U16 descriptorType);
+
+// Serialize a descriptor into a buffer. pBuf is filled with the descriptor data. descriptorSize is set to the size of the data placed into the buffer.
+openavbRC openavbAemSerializeDescriptor(U16 configIdx, U16 descriptorType, U16 descriptorIdx, U16 bufSize, U8 *pBuf, U16 *descriptorSize);
+
+#endif // OPENAVB_AEM_H
diff --git a/lib/avtp_pipeline/aem/openavb_aem_pub.h b/lib/avtp_pipeline/aem/openavb_aem_pub.h
new file mode 100644
index 00000000..b5c206c3
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_aem_pub.h
@@ -0,0 +1,80 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Entity Model Public Interface
+ * MODULE SUMMARY : Public Interface for the AVDECC Entity Model Functionality
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_AEM_PUB_H
+#define OPENAVB_AEM_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+
+typedef struct openavb_descriptor_pvt *openavb_descriptor_pvt_ptr_t;
+
+typedef struct openavb_avdecc_configuration_cfg openavb_avdecc_configuration_cfg_t;
+
+// Before calling any Entity Model functions the AVDECC function openavbAvdeccInitialize() must be called with the Entity Descriptor.
+// The Entity Descriptor is the root of all descriptors and must exist to do most things in AVDECC.
+
+// Gets the current configuration descriptor index for the Entity Model. Error checking is not performed on this function.
+U16 openavbAemGetConfigIdx(void);
+
+// Adds descriptors to the Entity Model. The Configuration Descriptor must be added first.
+bool openavbAemAddDescriptor(void *pDescriptor, U16 configIdx, U16 *pResultIdx);
+
+// Get a pointer to a descriptor in the Entity Model.
+void *openavbAemGetDescriptor(U16 configIdx, U16 descriptorType, U16 descriptorIdx);
+
+// Get the index of the descriptor in the Entity Model, or OPENAVB_AEM_DESCRIPTOR_INVALID if not found.
+U16 openavbAemGetDescriptorIndex(U16 configIdx, const void *pDescriptor);
+
+// Add a string to a standard descriptor U8 [64] string field.
+bool openavbAemSetString(U8 *pMem, const char *pString);
+
+// Checks if the Entity Model is acquired.
+bool openavbAemIsAcquired(void);
+
+// Checks if the Entity Model is locked.
+bool openavbAemIsLocked(void);
+
+// Sets the internal Entity Model acquired flag. Care should be used with this function it can impact controller access.
+bool openavbAemAcquire(bool flag);
+
+// Sets the internal Entity Model acquired flag. Care should be used with this function it can impact controller access.
+bool openavbAemLock(bool flag);
+
+
+#endif // OPENAVB_AEM_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_aem_types_pub.h b/lib/avtp_pipeline/aem/openavb_aem_types_pub.h
new file mode 100644
index 00000000..71c29c28
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_aem_types_pub.h
@@ -0,0 +1,1339 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Entity Model Types
+ * MODULE SUMMARY : AVDECC Entity Model Types
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_AEM_TYPES_PUB_H
+#define OPENAVB_AEM_TYPES_PUB_H 1
+
+#include "openavb_types_pub.h"
+
+#define OPENAVB_AEM_STRLEN_MAX (64)
+
+// Descriptors IEEE Std 1722.1-2013 clause 7.2
+#define OPENAVB_AEM_DESCRIPTOR_ENTITY (0x0000)
+#define OPENAVB_AEM_DESCRIPTOR_CONFIGURATION (0x0001)
+#define OPENAVB_AEM_DESCRIPTOR_AUDIO_UNIT (0x0002)
+#define OPENAVB_AEM_DESCRIPTOR_VIDEO_UNIT (0x0003)
+#define OPENAVB_AEM_DESCRIPTOR_SENSOR_UNIT (0x0004)
+#define OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT (0x0005)
+#define OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT (0x0006)
+#define OPENAVB_AEM_DESCRIPTOR_JACK_INPUT (0x0007)
+#define OPENAVB_AEM_DESCRIPTOR_JACK_OUTPUT (0x0008)
+#define OPENAVB_AEM_DESCRIPTOR_AVB_INTERFACE (0x0009)
+#define OPENAVB_AEM_DESCRIPTOR_CLOCK_SOURCE (0x000a)
+#define OPENAVB_AEM_DESCRIPTOR_MEMORY_OBJECT (0x000b)
+#define OPENAVB_AEM_DESCRIPTOR_LOCALE (0x000c)
+#define OPENAVB_AEM_DESCRIPTOR_STRINGS (0x000d)
+#define OPENAVB_AEM_DESCRIPTOR_STREAM_PORT_INPUT (0x000e)
+#define OPENAVB_AEM_DESCRIPTOR_STREAM_PORT_OUTPUT (0x000f)
+#define OPENAVB_AEM_DESCRIPTOR_EXTERNAL_PORT_INPUT (0x0010)
+#define OPENAVB_AEM_DESCRIPTOR_EXTERNAL_PORT_OUTPUT (0x0011)
+#define OPENAVB_AEM_DESCRIPTOR_INTERNAL_PORT_INPUT (0x0012)
+#define OPENAVB_AEM_DESCRIPTOR_INTERNAL_PORT_OUTPUT (0x0013)
+#define OPENAVB_AEM_DESCRIPTOR_AUDIO_CLUSTER (0x0014)
+#define OPENAVB_AEM_DESCRIPTOR_VIDEO_CLUSTER (0x0015)
+#define OPENAVB_AEM_DESCRIPTOR_SENSOR_CLUSTER (0x0016)
+#define OPENAVB_AEM_DESCRIPTOR_AUDIO_MAP (0x0017)
+#define OPENAVB_AEM_DESCRIPTOR_VIDEO_MAP (0x0018)
+#define OPENAVB_AEM_DESCRIPTOR_SENSOR_MAP (0x0019)
+#define OPENAVB_AEM_DESCRIPTOR_CONTROL (0x001a)
+#define OPENAVB_AEM_DESCRIPTOR_SIGNAL_SELECTOR (0x001b)
+#define OPENAVB_AEM_DESCRIPTOR_MIXER (0x001c)
+#define OPENAVB_AEM_DESCRIPTOR_MATRIX (0x001d)
+#define OPENAVB_AEM_DESCRIPTOR_MATRIX_SIGNAL (0x001e)
+#define OPENAVB_AEM_DESCRIPTOR_SIGNAL_SPLITTER (0x001f)
+#define OPENAVB_AEM_DESCRIPTOR_SIGNAL_COMBINER (0x0020)
+#define OPENAVB_AEM_DESCRIPTOR_SIGNAL_DEMULTIPLEXER (0x0021)
+#define OPENAVB_AEM_DESCRIPTOR_SIGNAL_MULTIPLEXER (0x0022)
+#define OPENAVB_AEM_DESCRIPTOR_SIGNAL_TRANSCODER (0x0023)
+#define OPENAVB_AEM_DESCRIPTOR_CLOCK_DOMAIN (0x0024)
+#define OPENAVB_AEM_DESCRIPTOR_CONTROL_BLOCK (0x0025)
+#define OPENAVB_AEM_DESCRIPTOR_INVALID (0xffff)
+
+// This is the total number of decriptor types
+#define OPENAVB_AEM_DESCRIPTOR_COUNT (OPENAVB_AEM_DESCRIPTOR_CONTROL_BLOCK + 1)
+
+
+// Stream flags IEEE Std 1722.1-2013 clause 7.2.6.1
+#define OPENAVB_AEM_STREAM_FLAG_CLOCK_SYNC_SOURCE (0x0001)
+#define OPENAVB_AEM_STREAM_FLAG_CLASS_A (0x0002)
+#define OPENAVB_AEM_STREAM_FLAG_CLASS_B (0x0004)
+#define OPENAVB_AEM_STREAM_FLAG_SUPPORTS_ENCRYPTED (0x0008)
+#define OPENAVB_AEM_STREAM_FLAG_PRIMARY_BACKUP_SUPPORTED (0x0010)
+#define OPENAVB_AEM_STREAM_FLAG_PRIMARY_BACKUP_VALID (0x0020)
+#define OPENAVB_AEM_STREAM_FLAG_SECONDARY_BACKUP_SUPPORTED (0x0040)
+#define OPENAVB_AEM_STREAM_FLAG_SECONDARY_BACKUP_VALID (0x0080)
+#define OPENAVB_AEM_STREAM_FLAG_TERTIARY_BACKUP_SUPPORTED (0x0100)
+#define OPENAVB_AEM_STREAM_FLAG_TERTIARY_BACKUP_VALID (0x0200)
+
+// Jack Flags IEEE Std 1722.1-2013 clause 7.2.7.1
+#define OPENAVB_AEM_JACK_FLAG_CLOCK_SYNC_SOURCE (0x0001)
+#define OPENAVB_AEM_JACK_FLAG_CAPTIVE (0x0002)
+
+// Jack Types IEEE Std 1722.1-2013 clause 7.2.7.2
+#define OPENAVB_AEM_JACK_TYPE_SPEAKER (0x0000)
+#define OPENAVB_AEM_JACK_TYPE_HEADPHONE (0x0001)
+#define OPENAVB_AEM_JACK_TYPE_ANALOG_MICROPHONE (0x0002)
+#define OPENAVB_AEM_JACK_TYPE_SPDIF (0x0003)
+#define OPENAVB_AEM_JACK_TYPE_ADAT (0x0004)
+#define OPENAVB_AEM_JACK_TYPE_TDIF (0x0005)
+#define OPENAVB_AEM_JACK_TYPE_MADI (0x0006)
+#define OPENAVB_AEM_JACK_TYPE_UNBALANCED_ANALOG (0x0007)
+#define OPENAVB_AEM_JACK_TYPE_BALANCED_ANALOG (0x0008)
+#define OPENAVB_AEM_JACK_TYPE_DIGITAL (0x0009)
+#define OPENAVB_AEM_JACK_TYPE_MIDI (0x000a)
+#define OPENAVB_AEM_JACK_TYPE_AES_EBU (0x000b)
+#define OPENAVB_AEM_JACK_TYPE_COMPOSITE_VIDEO (0x000c)
+#define OPENAVB_AEM_JACK_TYPE_S_VHS_VIDEO (0x000d)
+#define OPENAVB_AEM_JACK_TYPE_COMPONENT_VIDEO (0x000e)
+#define OPENAVB_AEM_JACK_TYPE_DVI (0x000f)
+#define OPENAVB_AEM_JACK_TYPE_HDMI (0x0010)
+#define OPENAVB_AEM_JACK_TYPE_UDI (0x0011)
+#define OPENAVB_AEM_JACK_TYPE_DISPLAYPORT (0x0012)
+#define OPENAVB_AEM_JACK_TYPE_ANTENNA (0x0013)
+#define OPENAVB_AEM_JACK_TYPE_ANALOG_TUNER (0x0014)
+#define OPENAVB_AEM_JACK_TYPE_ETHERNET (0x0015)
+#define OPENAVB_AEM_JACK_TYPE_WIFI (0x0016)
+#define OPENAVB_AEM_JACK_TYPE_USB (0x0017)
+#define OPENAVB_AEM_JACK_TYPE_PCI (0x0018)
+#define OPENAVB_AEM_JACK_TYPE_PCI_E (0x0019)
+#define OPENAVB_AEM_JACK_TYPE_SCSI (0x001a)
+#define OPENAVB_AEM_JACK_TYPE_ATA (0x001b)
+#define OPENAVB_AEM_JACK_TYPE_IMAGER (0x001c)
+#define OPENAVB_AEM_JACK_TYPE_IR (0x001d)
+#define OPENAVB_AEM_JACK_TYPE_THUNDERBOLT (0x001e)
+#define OPENAVB_AEM_JACK_TYPE_SATA (0x001f)
+#define OPENAVB_AEM_JACK_TYPE_SMPTE_LTC (0x0020)
+#define OPENAVB_AEM_JACK_TYPE_DIGITAL_MICROPHONE (0x0021)
+#define OPENAVB_AEM_JACK_TYPE_AUDIO_MEDIA_CLOCK (0x0022)
+#define OPENAVB_AEM_JACK_TYPE_VIDEO_MEDIA_CLOCK (0x0023)
+#define OPENAVB_AEM_JACK_TYPE_GNSS_CLOCK (0x0024)
+#define OPENAVB_AEM_JACK_TYPE_PPS (0x0025)
+#define OPENAVB_AEM_JACK_TYPE_EXPANSION (0xffff)
+
+// Interface Types IEEE Std 1722.1-2013 clause 7.2.8.1
+#define OPENAVB_AEM_INTERFACE_TYPE_GPTP_GRANDMASTER_SUPPORTED (0x0001)
+#define OPENAVB_AEM_INTERFACE_TYPE_GPTP_SUPPORTED (0x0002)
+#define OPENAVB_AEM_INTERFACE_TYPE_SRP_SUPPORTED (0x0004)
+
+// Clock Source Flags IEEE Std 1722.1-2013 clause 7.2.9.1
+#define OPENAVB_AEM_CLOCK_SOURCE_FLAG_STREAM_ID (0x0001)
+#define OPENAVB_AEM_CLOCK_SOURCE_FLAG_LOCAL_ID (0x0002)
+
+// Clock Source Types IEEE Std 1722.1-2013 clause 7.2.9.2
+#define OPENAVB_AEM_CLOCK_SOURCE_TYPE_INTERNAL (0x0000)
+#define OPENAVB_AEM_CLOCK_SOURCE_TYPE_EXTERNAL (0x0001)
+#define OPENAVB_AEM_CLOCK_SOURCE_TYPE_INPUT_STREAM (0x0002)
+#define OPENAVB_AEM_CLOCK_SOURCE_TYPE_EXPANSION (0xffff)
+
+// Memory Object Types IEEE Std 1722.1-2013 clause 7.2.10.1
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_FIRMWARE_IMAGE (0x0000)
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_VENDOR_SPECIFIC (0x0001)
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_CRASH_DUMP (0x0002)
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_LOG_OBJECT (0x0003)
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_AUTOSTART_SETTINGS (0x0004)
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_SNAPSHOT_SETTINGS (0x0005)
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_SVG_MANUFACTURER (0x0006)
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_SVG_ENTITY (0x0007)
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_SVG_GENERIC (0x0008)
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_PNG_MANUFACTURER (0x0009)
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_PNG_ENTITY (0x000a)
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_PNG_GENERIC (0x000b)
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_DAE_MANUFACTURER (0x000c)
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_DAE_ENTITY (0x000d)
+#define OPENAVB_AEM_MEMORY_OBJECT_TYPE_DAE_GENERIC (0x000e)
+
+// Memory Object Operation Types IEEE Std 1722.1-2013 clause 7.2.10.2
+#define OPENAVB_AEM_MEMORY_OBJECT_OPERATION_TYPE_STORE (0x0000)
+#define OPENAVB_AEM_MEMORY_OBJECT_OPERATION_TYPE_STORE_AND_REBOOT (0x0001)
+#define OPENAVB_AEM_MEMORY_OBJECT_OPERATION_TYPE_READ (0x0002)
+#define OPENAVB_AEM_MEMORY_OBJECT_OPERATION_TYPE_ERASE (0x0003)
+#define OPENAVB_AEM_MEMORY_OBJECT_OPERATION_TYPE_UPLOAD (0x0004)
+
+// Port Flags IEEE Std 1722.1-2013 clause 7.2.13.1
+#define OPENAVB_AEM_PORT_FLAG_CLOCK_SYNC_SOURCE (0x0001)
+#define OPENAVB_AEM_PORT_FLAG_ASYNC_SAMPLE_RATE_CONV (0x0002)
+#define OPENAVB_AEM_PORT_FLAG_SYNC_SAMPLE_RATE_CONV (0x0004)
+
+// Audio Cluster Formats IEEE Std 1722.1-2013 clause 7.2.16.1
+#define OPENAVB_AEM_AUDIO_CLUSTER_FORMAT_IEC_60958 (0x00)
+#define OPENAVB_AEM_AUDIO_CLUSTER_FORMAT_MBLA (0x40)
+#define OPENAVB_AEM_AUDIO_CLUSTER_FORMAT_MIDI (0x80)
+#define OPENAVB_AEM_AUDIO_CLUSTER_FORMAT_SMPTE (0x88)
+
+// Video Cluster Formats IEEE Std 1722.1-2013 clause 7.2.17.1
+#define OPENAVB_AEM_VIDEO_CLUSTER_FORMAT_MPEG_PES_FORMAT (0x00)
+#define OPENAVB_AEM_VIDEO_CLUSTER_FORMAT_AVTP_FORMAT (0x01)
+#define OPENAVB_AEM_VIDEO_CLUSTER_FORMAT_RTP_PAYLOAD_FORMAT (0x02)
+#define OPENAVB_AEM_VIDEO_CLUSTER_FORMAT_VENDOR_SPECIFIC_FORMAT (0xfe)
+#define OPENAVB_AEM_VIDEO_CLUSTER_FORMAT_EXPERIMENTAL_FORMAT (0xff)
+
+// Control Value Type Max Counts IEEE Std 1722.1-2013 clause 7.2.22
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT8 (40)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT8 (40)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT16 (25)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT16 (25)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT32 (14)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT32 (14)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT64 (7)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT64 (7)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_FLOAT (14)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_DOUBLE (7)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT8 (400)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT8 (400)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT16 (199)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT16 (199)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT32 (98)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT32 (98)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT64 (48)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT64 (48)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_FLOAT (98)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_DOUBLE (48)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_STRING (199)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT8 (396)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT8 (396)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT16 (196)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT16 (196)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT32 (96)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT32 (96)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT64 (46)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT64 (46)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_FLOAT (96)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_DOUBLE (46)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_UTF8 (1)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_BODE_PLOT (29)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SMPTE_TIME (1)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SAMPLE_RATE (1)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_GPTP_TIME (1)
+#define OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_VENDOR (1)
+
+// Control Value Type Max Sources IEEE Std 1722.1-2013 clause 7.2.24
+#define OPENAVB_AEM_MIXER_VALUE_MAX_SOURCE_CONTROL_LINEAR_INT8 (68)
+#define OPENAVB_AEM_MIXER_VALUE_MAX_SOURCE_CONTROL_LINEAR_UINT8 (68)
+#define OPENAVB_AEM_MIXER_VALUE_MAX_SOURCE_CONTROL_LINEAR_INT16 (67)
+#define OPENAVB_AEM_MIXER_VALUE_MAX_SOURCE_CONTROL_LINEAR_UINT16 (67)
+#define OPENAVB_AEM_MIXER_VALUE_MAX_SOURCE_CONTROL_LINEAR_INT32 (65)
+#define OPENAVB_AEM_MIXER_VALUE_MAX_SOURCE_CONTROL_LINEAR_UINT32 (65)
+#define OPENAVB_AEM_MIXER_VALUE_MAX_SOURCE_CONTROL_LINEAR_INT64 (61)
+#define OPENAVB_AEM_MIXER_VALUE_MAX_SOURCE_CONTROL_LINEAR_UINT64 (61)
+#define OPENAVB_AEM_MIXER_VALUE_MAX_SOURCE_CONTROL_LINEAR_FLOAT (65)
+#define OPENAVB_AEM_MIXER_VALUE_MAX_SOURCE_CONTROL_LINEAR_DOUBLE (61)
+
+// Matrix Control Value Type Max Counts IEEE Std 1722.1-2013 clause 7.2.25
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT32 (14)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_LINEAR_INT64 (7)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT64 (7)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_LINEAR_FLOAT (14)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_LINEAR_DOUBLE (7)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT8 (400)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT8 (400)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT16 (199)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT16 (199)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT32 (98)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT32 (98)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT64 (48)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT64 (48)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_SELECTOR_FLOAT (98)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_SELECTOR_DOUBLE (48)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_UTF8 (1)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_BODE_PLOT (29)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_ARRAY_INT8 (396)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT8 (396)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_ARRAY_INT16 (196)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT16 (196)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_ARRAY_INT32 (96)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT32 (96)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_ARRAY_INT64 (46)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT64 (46)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_ARRAY_FLOAT (96)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_ARRAY_DOUBLE (46)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_SELECTOR_STRING (199)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_SMPTE_TIME (1)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_SAMPLE_RATE (1)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_GPTP_TIME (1)
+#define OPENAVB_AEM_MATRIX_VALUE_MAX_COUNT_CONTROL_VENDOR (1)
+
+// Transcoder Control Value Type Max Counts IEEE Std 1722.1-2013 clause 7.2.31
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_LINEAR_INT8 (41)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT8 (41)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_LINEAR_INT16 (26)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT16 (26)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_LINEAR_INT32 (14)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT32 (14)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_LINEAR_INT64 (8)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT64 (8)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_LINEAR_FLOAT (14)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_LINEAR_DOUBLE (8)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT8 (412)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT8 (412)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT16 (205)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT16 (205)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT32 (101)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT32 (101)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT64 (49)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT64 (49)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_SELECTOR_FLOAT (101)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_SELECTOR_DOUBLE (49)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_ARRAY_INT8 (408)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT8 (408)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_ARRAY_INT16 (202)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT16 (202)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_ARRAY_INT32 (99)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT32 (99)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_ARRAY_INT64 (47)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT64 (47)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_ARRAY_FLOAT (99)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_ARRAY_DOUBLE (47)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_SELECTOR_STRING (205)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_SAMPLE_RATE (1)
+#define OPENAVB_AEM_TRANSCODER_VALUE_MAX_COUNT_CONTROL_VENDOR (1)
+
+// Sample rates IEEE Std 1722.1-2013 clause 7.3.1
+typedef struct {
+ U8 pull;
+ U32 base;
+} openavb_aem_sampling_rate_t;
+
+// Sample rate pull field IEEE Std 1722.1-2013 clause 7.3.1.1
+#define OPENAVB_AEM_SAMPLE_RATE_PULL_MULTI_BASE_FREQ_BY_1_0 (0)
+#define OPENAVB_AEM_SAMPLE_RATE_PULL_MULTI_BASE_FREQ_BY_1_DIV_1_001 (1)
+#define OPENAVB_AEM_SAMPLE_RATE_PULL_MULTI_BASE_FREQ_BY_1_001 (2)
+#define OPENAVB_AEM_SAMPLE_RATE_PULL_MULTI_BASE_FREQ_BY_24_DIV_25 (3)
+#define OPENAVB_AEM_SAMPLE_RATE_PULL_MULTI_BASE_FREQ_BY_25_DIV_24 (4)
+
+// Stream formats : IIDC IEEE Std 1722.1-2013 clause 7.3.2.1.1.1
+typedef struct {
+ U8 sf;
+} openavb_aem_stream_format_iec_61883_iidc_t;
+
+// Stream formats : IIDC IEEE Std 1722.1-2013 clause 7.3.2.1.1.1
+typedef struct {
+ U8 sf;
+ U8 iidc_format;
+ U8 iidc_mode;
+ U8 iidc_rate;
+} openavb_aem_stream_format_iidc_t;
+
+// Stream formats : IEC 61883 IEEE Std 1722.1-2013 clause 7.3.2.1.1.1
+typedef struct {
+ U8 sf;
+ U8 fmt;
+} openavb_aem_stream_format_iec_61883_t;
+
+// Stream formats : IEC 61883-4 IEEE Std 1722.1-2013 clause 7.3.2.1.1.2
+typedef struct {
+ U8 sf;
+ U8 fmt;
+} openavb_aem_stream_format_iec_61883_4_t;
+
+// Stream formats : IEC 61883-6 IEEE Std 1722.1-2013 clause 7.3.2.1.1.4
+typedef struct {
+ U8 sf;
+ U8 fmt;
+ U8 fdf_evt;
+ U8 fdf_sfc;
+ U8 dbs;
+ U8 b;
+ U8 nb;
+} openavb_aem_stream_format_iec_61883_6_t;
+
+// Stream formats : IEC 61883-6 32 bit IEEE Std 1722.1-2013 clause 7.3.2.1.1.4
+typedef struct {
+ U8 sf;
+ U8 fmt;
+ U8 fdf_evt;
+ U8 fdf_sfc;
+ U8 dbs;
+ U8 b;
+ U8 nb;
+} openavb_aem_stream_format_iec_61883_6_32bit_t;
+
+// Stream formats : IEC 61883-6 float IEEE Std 1722.1-2013 clause 7.3.2.1.1.5
+typedef struct {
+ U8 sf;
+ U8 fmt;
+ U8 fdf_evt;
+ U8 fdf_sfc;
+ U8 dbs;
+ U8 b;
+ U8 nb;
+} openavb_aem_stream_format_iec_61883_6_float_t;
+
+// Stream formats : IEC 61883-6 float IEEE Std 1722.1-2013 clause 7.3.2.1.1.6
+typedef struct {
+ U8 sf;
+ U8 fmt;
+ U8 fdf_evt;
+ U8 fdf_sfc;
+ U8 dbs;
+ U8 b;
+ U8 nb;
+ U8 label_iec_60958_cnt;
+ U8 label_mbla_cnt;
+ U8 label_midi_cnt;
+ U8 label_smptecnt;
+} openavb_aem_stream_format_iec_61883_6_am824_t;
+
+// Stream formats : IEC 61883-8 IEEE Std 1722.1-2013 clause 7.3.2.1.1.7
+typedef struct {
+ U8 sf;
+ U8 fmt;
+ U8 video_mode;
+ U8 compress_mode;
+ U8 color_space;
+} openavb_aem_stream_format_iec_61883_8_t;
+
+// Stream formats : AVTP Audio IEEE Std 1722.1-2013 clause 7.3.2.1.3
+typedef struct {
+ U8 nominal_sample_rate;
+ U8 format;
+ U8 bit_depth;
+ U16 channels_per_frame;
+ U16 samples_per_frame;
+} openavb_aem_stream_format_avtp_audio_t;
+
+// Stream formats : AVTP Video IEEE Std 1722.1-2013 clause 7.3.2.1.4
+typedef struct {
+ U8 format;
+} openavb_aem_stream_format_avtp_video_t;
+
+// Stream formats : AVTP Control IEEE Std 1722.1-2013 clause 7.3.2.1.5
+typedef struct {
+ U8 protocol_type;
+ U8 format_id[6];
+} openavb_aem_stream_format_avtp_control_t;
+
+// Stream formats : Vendor IEEE Std 1722.1-2013 clause 7.3.2.1.6
+typedef struct {
+ U8 format_id[6];
+} openavb_aem_stream_format_vendor_t;
+
+// Stream formats : Experimental IEEE Std 1722.1-2013 clause 7.3.2.1.7
+typedef struct {
+} openavb_aem_stream_format_experimental_t;
+
+// Stream formats : Vendor Specific IEEE Std 1722.1-2013 clause 7.3.2.2.1
+typedef struct {
+ U8 format_id[6];
+} openavb_aem_stream_format_vendor_specific_t;
+
+// Stream formats IEEE Std 1722.1-2013 clause 7.3.2
+typedef struct {
+ U8 v;
+ U8 subtype;
+ union {
+ openavb_aem_stream_format_iec_61883_iidc_t iec_61883_iidc;
+ openavb_aem_stream_format_iidc_t iidc;
+ openavb_aem_stream_format_iec_61883_t iec_61883;
+ openavb_aem_stream_format_iec_61883_4_t iec_61883_4;
+ openavb_aem_stream_format_iec_61883_6_32bit_t iec_61883_6;
+ openavb_aem_stream_format_iec_61883_6_32bit_t iec_61883_6_32bit;
+ openavb_aem_stream_format_iec_61883_6_float_t iec_61883_6_float;
+ openavb_aem_stream_format_iec_61883_6_am824_t iec_61883_6_am824;
+ openavb_aem_stream_format_iec_61883_8_t iec_61883_8;
+ openavb_aem_stream_format_avtp_audio_t avtp_audio;
+ openavb_aem_stream_format_avtp_video_t avtp_video;
+ openavb_aem_stream_format_avtp_control_t avtp_control;
+ openavb_aem_stream_format_vendor_t vendor;
+ openavb_aem_stream_format_experimental_t experimental;
+ openavb_aem_stream_format_vendor_specific_t vendor_specific;
+ } subtypes;
+} openavb_aem_stream_format_t;
+
+
+#define OPENAVB_AEM_STREAM_FORMAT_SF_IIDC (0x00)
+#define OPENAVB_AEM_STREAM_FORMAT_SF_IEC_61883 (0x00)
+
+#define OPENAVB_AEM_STREAM_FORMAT_FMT_61883_4 (0x20)
+#define OPENAVB_AEM_STREAM_FORMAT_FMT_61883_6 (0x10)
+#define OPENAVB_AEM_STREAM_FORMAT_FMT_61883_8 (0x01)
+
+#define OPENAVB_AEM_STREAM_FORMAT_FDF_EVT_61883_6_AM824 (0x00)
+#define OPENAVB_AEM_STREAM_FORMAT_FDF_EVT_61883_6_32BITS (0x06)
+#define OPENAVB_AEM_STREAM_FORMAT_FDF_EVT_61883_6_FLOAT (0x04)
+
+
+// Stream formats IEEE Std 1722.1-2013 clause 7.3.2.1
+#define OPENAVB_AEM_STREAM_FORMAT_61883_IIDC_SUBTYPE (0x00)
+#define OPENAVB_AEM_STREAM_FORMAT_MMA_SUBTYPE (0x01)
+#define OPENAVB_AEM_STREAM_FORMAT_AVTP_AUDIO_SUBTYPE (0x02)
+#define OPENAVB_AEM_STREAM_FORMAT_AVTP_VIDEO_SUBTYPE (0x03)
+#define OPENAVB_AEM_STREAM_FORMAT_AVTP_CONTROL_SUBTYPE (0x04)
+#define OPENAVB_AEM_STREAM_FORMAT_VENDOR_SUBTYPE (0x6f)
+#define OPENAVB_AEM_STREAM_FORMAT_EXPERIMENTAL_SUBTYPE (0x7f)
+
+// AVTP Audio Stream Sample Rates IEEE Std 1722.1-2013 7.3.2.1.3
+#define OPENAVB_AEM_AUDIO_STREAM_SAMPLE_RATE_NOT_SPECIFIED (0x0)
+#define OPENAVB_AEM_AUDIO_STREAM_SAMPLE_RATE_8_KHZ (0x1)
+#define OPENAVB_AEM_AUDIO_STREAM_SAMPLE_RATE_16_KHZ (0x2)
+#define OPENAVB_AEM_AUDIO_STREAM_SAMPLE_RATE_32_KHZ (0x3)
+#define OPENAVB_AEM_AUDIO_STREAM_SAMPLE_RATE_44_1_KHZ (0x4)
+#define OPENAVB_AEM_AUDIO_STREAM_SAMPLE_RATE_48_KHZ (0x5)
+#define OPENAVB_AEM_AUDIO_STREAM_SAMPLE_RATE_88_2_KHZ (0x6)
+#define OPENAVB_AEM_AUDIO_STREAM_SAMPLE_RATE_96_KHZ (0x7)
+#define OPENAVB_AEM_AUDIO_STREAM_SAMPLE_RATE_176_4_KHZ (0x8)
+#define OPENAVB_AEM_AUDIO_STREAM_SAMPLE_RATE_192_KHZ (0x9)
+
+// AVTP Audio Stream Format IEEE Std 1722.1-2013 7.3.2.1.3
+#define OPENAVB_AEM_AUDIO_STREAM_FORMAT_NOT_SPECIFIED (0)
+#define OPENAVB_AEM_AUDIO_STREAM_FORMAT_FLOAT (1)
+#define OPENAVB_AEM_AUDIO_STREAM_FORMAT_32BIT_INTEGER (2)
+#define OPENAVB_AEM_AUDIO_STREAM_FORMAT_24BIT_PACKED_INTEGER (3)
+#define OPENAVB_AEM_AUDIO_STREAM_FORMAT_16BIT_INTEGER (4)
+
+// AVTP Video Stream Format IEEE Std 1722.1-2013 7.3.2.1.4
+#define OPENAVB_AEM_VIDEO_STREAM_FORMAT_RESERVED (0x00)
+#define OPENAVB_AEM_VIDEO_STREAM_FORMAT_AVTP_FORMAT (0x01)
+#define OPENAVB_AEM_VIDEO_STREAM_FORMAT_RTP_PAYLOAD_TYPE (0x02)
+#define OPENAVB_AEM_VIDEO_STREAM_FORMAT_VENDOR_SPECIFIC (0xfe)
+#define OPENAVB_AEM_VIDEO_STREAM_FORMAT_EXPERIMENTAL (0xff)
+
+// AVTP Control Stream Format IEEE Std 1722.1-2013 7.3.2.1.5
+#define OPENAVB_AEM_CONTROL_STREAM_FORMAT_AUTOMOTIVE (0)
+#define OPENAVB_AEM_CONTROL_STREAM_FORMAT_TSCS (3)
+#define OPENAVB_AEM_CONTROL_STREAM_FORMAT_VENDOR_DEFINED (15)
+
+// Control Value Units IEEE Std 1722.1-2013 clause 7.3.3
+#define OPENAVB_AEM_UNIT_UNITLESS (0x00)
+#define OPENAVB_AEM_UNIT_UNITLESS_COUNT (0x01)
+#define OPENAVB_AEM_UNIT_UNITLESS_PERCENT (0x02)
+#define OPENAVB_AEM_UNIT_UNITLESS_FSTOP (0x03)
+#define OPENAVB_AEM_UNIT_TIME_SECONDS (0x08)
+#define OPENAVB_AEM_UNIT_TIME_MINUTES (0x09)
+#define OPENAVB_AEM_UNIT_TIME_HOURS (0x0a)
+#define OPENAVB_AEM_UNIT_TIME_DAYS (0x0b)
+#define OPENAVB_AEM_UNIT_TIME_MONTHS (0x0c)
+#define OPENAVB_AEM_UNIT_TIME_YEARS (0x0d)
+#define OPENAVB_AEM_UNIT_TIME_SAMPLES (0x0e)
+#define OPENAVB_AEM_UNIT_TIME_FRAMES (0x0f)
+#define OPENAVB_AEM_UNIT_FREQUENCY_HERTZ (0x10)
+#define OPENAVB_AEM_UNIT_FREQUENCY_SEMITONES (0x11)
+#define OPENAVB_AEM_UNIT_FREQUENCY_CENTS (0x12)
+#define OPENAVB_AEM_UNIT_FREQUENCY_OCTAVES (0x13)
+#define OPENAVB_AEM_UNIT_FREQUENCY_FPS (0x14)
+#define OPENAVB_AEM_UNIT_DISTANCE_METRES (0x18)
+#define OPENAVB_AEM_UNIT_TEMPERATURE_KELVIN (0x20)
+#define OPENAVB_AEM_UNIT_MASS_GRAMS (0x28)
+#define OPENAVB_AEM_UNIT_VOLTAGE_VOLTS (0x30)
+#define OPENAVB_AEM_UNIT_VOLTAGE_DBV (0x31)
+#define OPENAVB_AEM_UNIT_VOLTAGE_DBU (0x32)
+#define OPENAVB_AEM_UNIT_CURRENT_AMPS (0x38)
+#define OPENAVB_AEM_UNIT_POWER_WATTS (0x40)
+#define OPENAVB_AEM_UNIT_POWER_DBM (0x41)
+#define OPENAVB_AEM_UNIT_POWER_DBW (0x42)
+#define OPENAVB_AEM_UNIT_PRESSURE_PASCALS (0x48)
+#define OPENAVB_AEM_UNIT_MEMORY_BITS (0x50)
+#define OPENAVB_AEM_UNIT_MEMORY_BYTES (0x51)
+#define OPENAVB_AEM_UNIT_MEMORY_KIBIBYTES (0x52)
+#define OPENAVB_AEM_UNIT_MEMORY_MEBIBYTES (0x53)
+#define OPENAVB_AEM_UNIT_MEMORY_GIBIBYTES (0x54)
+#define OPENAVB_AEM_UNIT_MEMORY_TEBIBYTES (0x55)
+#define OPENAVB_AEM_UNIT_BANDWIDTH_BITS_PER_SEC (0x58)
+#define OPENAVB_AEM_UNIT_BANDWIDTH_BYTES_PER_SEC (0x59)
+#define OPENAVB_AEM_UNIT_BANDWIDTH_KIBIBYTES_PER_SEC (0x5a)
+#define OPENAVB_AEM_UNIT_BANDWIDTH_MEBIBYTES_PER_SEC (0x5b)
+#define OPENAVB_AEM_UNIT_BANDWIDTH_GIGIBYTES_PER_SEC (0x5c)
+#define OPENAVB_AEM_UNIT_BANDWIDTH_TEBIBYTES_PER_SEC (0x5d)
+#define OPENAVB_AEM_UNIT_LUMINOSITY_CANDELAS (0x60)
+#define OPENAVB_AEM_UNIT_ENERGY_JOULES (0x68)
+#define OPENAVB_AEM_UNIT_ANGLE_RADIANS (0x70)
+#define OPENAVB_AEM_UNIT_FORCE_NEWTONS (0x78)
+#define OPENAVB_AEM_UNIT_RESISTANCE_OHMS (0x80)
+#define OPENAVB_AEM_UNIT_VELOCITY_METRES_PER_SEC (0x88)
+#define OPENAVB_AEM_UNIT_VELOCITY_RADIANS_PER_SEC (0x89)
+#define OPENAVB_AEM_UNIT_ACCELERATION_METRES_PER_SEC_SQUARED (0x90)
+#define OPENAVB_AEM_UNIT_ACCELERATION_RADIANS_PER_SEC_SQUARED (0x91)
+#define OPENAVB_AEM_UNIT_MAGNETIC_FLUX_TESLAS (0x98)
+#define OPENAVB_AEM_UNIT_AREA_METRES_SQUARED (0xa0)
+#define OPENAVB_AEM_UNIT_VOLUME_METRES_CUBED (0xa8)
+#define OPENAVB_AEM_UNIT_VOLUME_LITRES (0xa9)
+#define OPENAVB_AEM_UNIT_LOUDNESS_DB (0xb0)
+#define OPENAVB_AEM_UNIT_LOUDNESS_DB_PEAK (0xb1)
+#define OPENAVB_AEM_UNIT_LOUDNESS_DB_RMS (0xb2)
+#define OPENAVB_AEM_UNIT_LOUDNESS_DBFS (0xb3)
+#define OPENAVB_AEM_UNIT_LOUDNESS_DBFS_PEAK (0xb4)
+#define OPENAVB_AEM_UNIT_LOUDNESS_DBFS_RMS (0xb5)
+#define OPENAVB_AEM_UNIT_LOUDNESS_DBTP (0xb6)
+#define OPENAVB_AEM_UNIT_LOUDNESS_DB_SPL_A (0xb7)
+#define OPENAVB_AEM_UNIT_LOUDNESS_DB_Z (0xb8)
+#define OPENAVB_AEM_UNIT_LOUDNESS_DB_SPL_C (0xb9)
+#define OPENAVB_AEM_UNIT_LOUDNESS_DB_SPL (0xba)
+#define OPENAVB_AEM_UNIT_LOUDNESS_LU (0xbb)
+#define OPENAVB_AEM_UNIT_LOUDNESS_LUFS (0xbc)
+#define OPENAVB_AEM_UNIT_LOUDNESS_DB_A (0xbd)
+
+// Control Types IEEE Std 1722.1-2013 clause 7.3.4
+#define OPENAVB_AEM_CONTROL_TYPE_ENABLE (0x90e0f00000000000ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_IDENTIFY (0x90e0f00000000001ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_MUTE (0x90e0f00000000002ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_INVERT (0x90e0f00000000003ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_GAIN (0x90e0f00000000004ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_ATTENUATE (0x90e0f00000000005ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_DELAY (0x90e0f00000000006ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_SRC_MODE (0x90e0f00000000007ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_SNAPSHOT (0x90e0f00000000008ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_POW_LINE_FREQ (0x90e0f00000000009ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_POWER_STATUS (0x90e0f0000000000aULL)
+#define OPENAVB_AEM_CONTROL_TYPE_FAN_STATUS (0x90e0f0000000000bULL)
+#define OPENAVB_AEM_CONTROL_TYPE_TEMPERATURE (0x90e0f0000000000cULL)
+#define OPENAVB_AEM_CONTROL_TYPE_ALTITUDE (0x90e0f0000000000dULL)
+#define OPENAVB_AEM_CONTROL_TYPE_ABSOLUTE_HUMIDITY (0x90e0f0000000000eULL)
+#define OPENAVB_AEM_CONTROL_TYPE_RELATIVE_HUMIDITY (0x90e0f0000000000fULL)
+#define OPENAVB_AEM_CONTROL_TYPE_ORIENTATION (0x90e0f00000000010ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_VELOCITY (0x90e0f00000000011ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_ACCELERATION (0x90e0f00000000012ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_FILTER_RESPONSE (0x90e0f00000000013ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_PANPOT (0x90e0f00000010000ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_PHANTOM (0x90e0f00000010001ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_AUDIO_SCALE (0x90e0f00000010002ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_AUDIO_METERS (0x90e0f00000010003ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_AUDIO_SPECTRUM (0x90e0f00000010004ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_SCANNING_MODE (0x90e0f00000020000ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_AUTO_EXP_MODE (0x90e0f00000020001ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_AUTO_EXP_PRIO (0x90e0f00000020002ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_EXP_TIME (0x90e0f00000020003ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_FOCUS (0x90e0f00000020004ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_FOCUS_AUTO (0x90e0f00000020005ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_IRIS (0x90e0f00000020006ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_ZOOM (0x90e0f00000020007ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_PRIVACY (0x90e0f00000020008ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_BACKLIGHT (0x90e0f00000020009ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_BRIGHTNESS (0x90e0f0000002000aULL)
+#define OPENAVB_AEM_CONTROL_TYPE_CONTRAST (0x90e0f0000002000bULL)
+#define OPENAVB_AEM_CONTROL_TYPE_HUE (0x90e0f0000002000cULL)
+#define OPENAVB_AEM_CONTROL_TYPE_SATURATION (0x90e0f0000002000dULL)
+#define OPENAVB_AEM_CONTROL_TYPE_SHARPNESS (0x90e0f0000002000eULL)
+#define OPENAVB_AEM_CONTROL_TYPE_GAMMA (0x90e0f0000002000fULL)
+#define OPENAVB_AEM_CONTROL_TYPE_WHITE_BAL_TEMP (0x90e0f00000020010ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_WHITE_BAL_TEMP_AUTO (0x90e0f00000020011ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_WHITE_BAL_COMP (0x90e0f00000020012ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_WHITE_BAL_COMP_AUTO (0x90e0f00000020013ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_DIGITAL_ZOOM (0x90e0f00000020014ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_PLAYLIST (0x90e0f00000030000ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_PLAYLIST_NAME (0x90e0f00000030001ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_DISK (0x90e0f00000030002ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_DISK_NAME (0x90e0f00000030003ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_TRACK (0x90e0f00000030004ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_TRACK_NAME (0x90e0f00000030005ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_SPEED (0x90e0f00000030006ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_SAMPLE_POSITION (0x90e0f00000030007ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_PLAYBACK_TRANSPORT (0x90e0f00000030008ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_RECORD_TRANSPORT (0x90e0f00000030009ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_FREQUENCY (0x90e0f00000040000ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_MODULATION (0x90e0f00000040001ULL)
+#define OPENAVB_AEM_CONTROL_TYPE_POLARIZATION (0x90e0f00000040002ULL)
+
+// Sample Rate Convertor (SRC_MODE) Mode IEEE Std 1722.1-2013 clause 7.3.4.8
+#define OPENAVB_AEM_CONTROL_TYPE_SRC_MODE_OFF (0x00)
+#define OPENAVB_AEM_CONTROL_TYPE_SRC_MODE_SYNCHRONOUS (0x01)
+#define OPENAVB_AEM_CONTROL_TYPE_SRC_MODE_ASYNCHRONOUS (0x02)
+
+// Snapshot Control (SNAPSHOT) IEEE Std 1722.1-2013 clause 7.3.4.9
+#define OPENAVB_AEM_CONTROL_TYPE_SNAPSHOT_CAPTURE (0x0000)
+#define OPENAVB_AEM_CONTROL_TYPE_SNAPSHOT_RECALL (0x0001)
+#define OPENAVB_AEM_CONTROL_TYPE_SNAPSHOT_ERASE (0x0002)
+
+// Power Line Frequency Control (POW_LINE_FREQ) IEEE Std 1722.1-2013 clause 7.3.4.10
+#define OPENAVB_AEM_CONTROL_TYPE_POW_LINE_FREQ_FIFTY_HERTZ (50)
+#define OPENAVB_AEM_CONTROL_TYPE_POW_LINE_FREQ_SIXTY_HERTZ (60)
+
+// Auto Exposure Mode Control (AUTO_EXP_MODE) IEEE Std 1722.1-2013 clause 7.3.4.27
+#define OPENAVB_AEM_CONTROL_TYPE_AUTO_EXP_MODE_MANUAL (0x01)
+#define OPENAVB_AEM_CONTROL_TYPE_AUTO_EXP_MODE_AUTO (0x11)
+#define OPENAVB_AEM_CONTROL_TYPE_AUTO_EXP_MODE_SHUTTER_PRIO (0x21)
+#define OPENAVB_AEM_CONTROL_TYPE_AUTO_EXP_MODE_APER_PRIO (0x31)
+
+// Media Disk Selection Control (MEDIA_DISK) IEEE Std 1722.1-2013 clause 7.3.4.49
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_DISK_CHOOSE (0x0000)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_DISK_PREVIOUS (0x0001)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_DISK_NEXT (0x0002)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_DISK_OPEN (0x0003)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_DISK_CLOSE (0x0004)
+
+// Media Playback Transport Control (MEDIA_PLAYBACK_TRANSPORT) IEEE Std 1722.1-2013 clause 7.3.4.55
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_PLAYBACK_TRANSPORT_STOP (0x0000)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_PLAYBACK_TRANSPORT_PLAY (0x0001)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_PLAYBACK_TRANSPORT_PAUSE (0x0002)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_PLAYBACK_TRANSPORT_UNPAUSE (0x0003)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_PLAYBACK_TRANSPORT_SCAN_FORWARD (0x0004)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_PLAYBACK_TRANSPORT_SCAN_BACKWARD (0x0005)
+
+// Media Record Transport Control (MEDIA_RECORD_TRANSPORT) IEEE Std 1722.1-2013 clause 7.3.4.56
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_RECORD_TRANSPORT_STOP (0x0000)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_RECORD_TRANSPORT_PLAY (0x0001)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_RECORD_TRANSPORT_PAUSE (0x0002)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_RECORD_TRANSPORT_UNPAUSE (0x0003)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_RECORD_TRANSPORT_SCAN_FORWARD (0x0004)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_RECORD_TRANSPORT_SCAN_BACKWARD (0x0005)
+#define OPENAVB_AEM_CONTROL_TYPE_MEDIA_RECORD_TRANSPORT_RECORD (0x0006)
+
+// Modulation Control (MODULATION) IEEE Std 1722.1-2013 clause 7.3.4.58
+#define OPENAVB_AEM_CONTROL_TYPE_MODULATION_AMPLITUDE_MODULATION (0x00)
+#define OPENAVB_AEM_CONTROL_TYPE_MODULATION_FREQUENCY_MODULATION (0x01)
+#define OPENAVB_AEM_CONTROL_TYPE_MODULATION_PHASE_MODULATION (0x02)
+
+// Polarization Control (POLARIZATION) IEEE Std 1722.1-2013 clause 7.3.4.59
+#define OPENAVB_AEM_CONTROL_TYPE_POLARIZATION_VERTICAL (0x00)
+#define OPENAVB_AEM_CONTROL_TYPE_POLARIZATION_HORIZONTAL (0x01)
+#define OPENAVB_AEM_CONTROL_TYPE_POLARIZATION_LEFT_HAND_CIRCULAR (0x02)
+#define OPENAVB_AEM_CONTROL_TYPE_POLARIZATION_RIGHT_HAND_CIRCULAR (0x03)
+
+// Control_value_type IEEE Std 1722.1-2013 clause 7.3.5.1
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT8 (0x0000)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT8 (0x0001)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT16 (0x0002)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT16 (0x0003)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT32 (0x0004)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT32 (0x0005)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT64 (0x0006)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT64 (0x0007)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_FLOAT (0x0008)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_DOUBLE (0x0009)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT8 (0x000a)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT8 (0x000b)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT16 (0x000c)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT16 (0x000d)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT32 (0x000e)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT32 (0x000f)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT64 (0x0010)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT64 (0x0011)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_FLOAT (0x0012)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_DOUBLE (0x0013)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_STRING (0x0014)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT8 (0x0015)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT8 (0x0016)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT16 (0x0017)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT16 (0x0018)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT32 (0x0019)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT32 (0x001a)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT64 (0x001b)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT64 (0x001c)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_FLOAT (0x001d)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_DOUBLE (0x001e)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_UTF8 (0x001f)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_BODE_PLOT (0x0020)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SMPTE_TIME (0x0021)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SAMPLE_RATE (0x0022)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_GPTP_TIME (0x0023)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_VENDOR (0x3ffe)
+#define OPENAVB_AEM_CONTROL_VALUE_TYPE_EXPANSION (0x3fff)
+
+// Localized String default values IEEE Std 1722.1-2013 clause 7.3.6
+#define OPENAVB_AEM_NO_STRING_OFFSET (0x1fff)
+#define OPENAVB_AEM_NO_STRING_INDEX (7)
+
+// Localized String Reference IEEE Std 1722.1-2013 clause 7.3.6
+typedef struct {
+ U16 offset;
+ U8 index;
+} openavb_aem_string_ref_t;
+
+// Control value formats IEEE Std 1722.1-2013 clause 7.3.5.2
+// Values format for Linear Value Types (CONTROL_LINEAR_INT8 to CONTROL_LINEAR_DOUBLE) IEEE Std 1722.1-2013 clause 7.3.5.2.1
+typedef struct {
+ S8 minimum;
+ S8 maximum;
+ S8 step;
+ S8 default_value;
+ S8 current;
+ U16 unit;
+ openavb_aem_string_ref_t string;
+} openavb_aem_control_value_format_control_linear_int8_t;
+
+typedef struct {
+ U8 minimum;
+ U8 maximum;
+ U8 step;
+ U8 default_value;
+ U8 current;
+ U16 unit;
+ openavb_aem_string_ref_t string;
+} openavb_aem_control_value_format_control_linear_uint8_t;
+
+typedef struct {
+ S16 minimum;
+ S16 maximum;
+ S16 step;
+ S16 default_value;
+ S16 current;
+ U16 unit;
+ openavb_aem_string_ref_t string;
+} openavb_aem_control_value_format_control_linear_int16_t;
+
+typedef struct {
+ U16 minimum;
+ U16 maximum;
+ U16 step;
+ U16 default_value;
+ U16 current;
+ U16 unit;
+ openavb_aem_string_ref_t string;
+} openavb_aem_control_value_format_control_linear_uint16_t;
+
+typedef struct {
+ S32 minimum;
+ S32 maximum;
+ S32 step;
+ S32 default_value;
+ S32 current;
+ U16 unit;
+ openavb_aem_string_ref_t string;
+} openavb_aem_control_value_format_control_linear_int32_t;
+
+typedef struct {
+ U32 minimum;
+ U32 maximum;
+ U32 step;
+ U32 default_value;
+ U32 current;
+ U16 unit;
+ openavb_aem_string_ref_t string;
+} openavb_aem_control_value_format_control_linear_uint32_t;
+
+typedef struct {
+ S64 minimum;
+ S64 maximum;
+ S64 step;
+ S64 default_value;
+ S64 current;
+ U16 unit;
+ openavb_aem_string_ref_t string;
+} openavb_aem_control_value_format_control_linear_int64_t;
+
+typedef struct {
+ U64 minimum;
+ U64 maximum;
+ U64 step;
+ U64 default_value;
+ U64 current;
+ U16 unit;
+ openavb_aem_string_ref_t string;
+} openavb_aem_control_value_format_control_linear_uint64_t;
+
+typedef struct {
+ float minimum;
+ float maximum;
+ float step;
+ float default_value;
+ float current;
+ U16 unit;
+ openavb_aem_string_ref_t string;
+} openavb_aem_control_value_format_control_linear_float_t;
+
+typedef struct {
+ double minimum;
+ double maximum;
+ double step;
+ double default_value;
+ double current;
+ U16 unit;
+ openavb_aem_string_ref_t string;
+} openavb_aem_control_value_format_control_linear_double_t;
+
+
+// Values format for Selector Value Types (CONTROL_SELECTOR_INT8 to CONTROL_SELECTOR_STRING) IEEE Std 1722.1-2013 clause 7.3.5.2.2
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_selector_int8_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_selector_uint8_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_selector_int16_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_selector_uint16_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_selector_int32_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_selector_uint32_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_selector_int64_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_selector_uint64_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_selector_float_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_selector_double_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_selector_string_t;
+
+
+// Values format for Array Value Types (CONTROL_ARRAY_INT8 to CONTROL_ARRAY_ARRAY_DOUBLE) IEEE Std 1722.1-2013 clause 7.3.5.2.3
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_array_int8_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_array_uint8_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_array_int16_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_array_uint16_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_array_int32_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_array_uint32_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_array_int64_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_array_uint64_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_array_float_t;
+
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_array_double_t;
+
+
+// Values format for UTF-8 String Value Type (CONTROL_UTF8) IEEE Std 1722.1-2013 clause 7.3.5.2.4
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_utf8_t;
+
+// Values format for Bode Plot Value Type (CONTROL_BODE_PLOT) IEEE Std 1722.1-2013 clause 7.3.5.2.5
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_bode_plot_t;
+
+// Values format for SMPTE Time Type (CONTROL_SMPTE_TIME) IEEE Std 1722.1-2013 clause 7.3.5.2.6
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_smpte_time_t;
+
+// Values format for Sample Rate Type (CONTROL_SAMPLE_RATE) IEEE Std 1722.1-2013 clause 7.3.5.2.7
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_sample_rate_t;
+
+// Values format for gPTP Time Type (CONTROL_GPTP_TIME) IEEE Std 1722.1-2013 clause 7.3.5.2.8
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_gptp_time_t;
+
+// Values format for Vendor Defined Type (CONTROL_VENDOR) IEEE Std 1722.1-2013 clause 7.3.5.2.9
+typedef struct {
+ // AVDECC_TODO
+} openavb_aem_control_value_format_control_vendor_t;
+
+
+// Content Protection for Video Cluster Format Specific fields IEEE Std 1722.1-2013 clause 7.3.7.1.1
+#define OPENAVB_AEM_VIDEO_CLUSTER_PROTECTION_NONE (0x0)
+#define OPENAVB_AEM_VIDEO_CLUSTER_PROTECTION_HDCP (0x1)
+#define OPENAVB_AEM_VIDEO_CLUSTER_PROTECTION_DTCP (0x2)
+#define OPENAVB_AEM_VIDEO_CLUSTER_PROTECTION_AES_ENCRYPTION (0x3)
+
+// Profiles for MPEG Elementary Streams IEEE Std 1722.1-2013 clause 7.3.7.2.1
+#define OPENAVB_AEM_MPEG_PROFILE_H264_CBP (0x00)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_BP (0x01)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_MP (0x02)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_XP (0x03)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_HIP (0x04)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_PHIP (0x05)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_HI10P (0x06)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_HI422P (0x07)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_HI444PP (0x08)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_HI10I (0x09)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_HI422I (0x0a)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_HI444I (0x0b)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_CAVLC44I (0x0c)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_SBP (0x0d)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_SHP (0x0e)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_SHI (0x0f)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_STHP (0x10)
+#define OPENAVB_AEM_MPEG_PROFILE_H264_MVHP (0x11)
+#define OPENAVB_AEM_MPEG_PROFILE_MPEG2_SP (0x12)
+#define OPENAVB_AEM_MPEG_PROFILE_MPEG2_MP (0x13)
+#define OPENAVB_AEM_MPEG_PROFILE_MPEG2_SNR (0x14)
+#define OPENAVB_AEM_MPEG_PROFILE_MPEG2_SPATIAL (0x15)
+#define OPENAVB_AEM_MPEG_PROFILE_MPEG2_HP (0x16)
+#define OPENAVB_AEM_MPEG_PROFILE_MPEG2_422 (0x17)
+#define OPENAVB_AEM_MPEG_PROFILE_MPEG2_MVP (0x18)
+#define OPENAVB_AEM_MPEG_PROFILE_MPEG1_LAYER2 (0x80)
+#define OPENAVB_AEM_MPEG_PROFILE_MPEG1_LAYER3 (0x81)
+#define OPENAVB_AEM_MPEG_PROFILE_MPEG2_LAYER2 (0x82)
+#define OPENAVB_AEM_MPEG_PROFILE_MPEG2_LAYER3 (0x83)
+#define OPENAVB_AEM_MPEG_PROFILE_DOLBY_DIGITAL (0x84)
+#define OPENAVB_AEM_MPEG_PROFILE_DOLBY_DIGITAL_PLUS (0x85)
+#define OPENAVB_AEM_MPEG_PROFILE_DOLBY_DIGITAL_TRUEHD (0x86)
+#define OPENAVB_AEM_MPEG_PROFILE_DOLBY_PRO_LOGIC_II (0x87)
+#define OPENAVB_AEM_MPEG_PROFILE_DOLBY_DIGITAL_EX (0x88)
+#define OPENAVB_AEM_MPEG_PROFILE_DOLBY_DIGITAL_SURROUND_EX (0x89)
+#define OPENAVB_AEM_MPEG_PROFILE_DOLBY_DIGITAL_LIVE (0x8a)
+#define OPENAVB_AEM_MPEG_PROFILE_DTS_5_1 (0x8b)
+#define OPENAVB_AEM_MPEG_PROFILE_DTS_ES_MATRIX (0x8c)
+#define OPENAVB_AEM_MPEG_PROFILE_DTS_ES_DISCRETE (0x8d)
+#define OPENAVB_AEM_MPEG_PROFILE_DTS_NEO_6 (0x8e)
+#define OPENAVB_AEM_MPEG_PROFILE_DTS_NEO_X (0x8f)
+#define OPENAVB_AEM_MPEG_PROFILE_DTS_96_24 (0x90)
+#define OPENAVB_AEM_MPEG_PROFILE_DTS_HD (0x91)
+#define OPENAVB_AEM_MPEG_PROFILE_DTS_HD_MASTER (0x92)
+#define OPENAVB_AEM_MPEG_PROFILE_DTS_INTERACTIVE (0x93)
+#define OPENAVB_AEM_MPEG_PROFILE_DTS_NEO_PC (0x94)
+#define OPENAVB_AEM_MPEG_PROFILE_AAC_LC (0x95)
+#define OPENAVB_AEM_MPEG_PROFILE_AAC_MAIN (0x96)
+#define OPENAVB_AEM_MPEG_PROFILE_AAC_LD (0x97)
+#define OPENAVB_AEM_MPEG_PROFILE_AAC_HE (0x98)
+#define OPENAVB_AEM_MPEG_PROFILE_AAC_HE2 (0x99)
+
+// Levels for H.264 Profiles IEEE Std 1722.1-2013 clause 7.3.7.2.2.1
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_1 (0x00)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_1B (0x01)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_1_1 (0x02)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_1_2 (0x03)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_1_3 (0x01)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_2 (0x05)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_2_1 (0x06)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_2_2 (0x07)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_3 (0x08)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_3_1 (0x09)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_3_2 (0x0a)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_4 (0x0b)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_4_1 (0x0c)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_4_2 (0x0d)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_5 (0x0e)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_5_1 (0x0f)
+#define OPENAVB_AEM_PROFILE_LEVEL_H264_5_2 (0x10)
+
+// Levels for MPEG2 Profiles IEEE Std 1722.1-2013 clause 7.3.7.2.2.2
+#define OPENAVB_AEM_PROFILE_LEVEL_MPEG2_LL (0x00)
+#define OPENAVB_AEM_PROFILE_LEVEL_MPEG2_ML (0x01)
+#define OPENAVB_AEM_PROFILE_LEVEL_MPEG2_H_14 (0x02)
+#define OPENAVB_AEM_PROFILE_LEVEL_MPEG2_HL (0x03)
+
+// Audio Profiles MPEG_PES_FORMAT Compressed Audio sample rates IEEE Std 1722.1-2013 clause 7.3.7.2.3
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_SAMPLE_RATE_8K (0x0)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_SAMPLE_RATE_16K (0x1)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_SAMPLE_RATE_22K05 (0x2)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_SAMPLE_RATE_24K (0x3)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_SAMPLE_RATE_32K (0x4)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_SAMPLE_RATE_44K1 (0x5)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_SAMPLE_RATE_48K (0x6)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_SAMPLE_RATE_96K (0x7)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_SAMPLE_RATE_192K (0x8)
+
+// Audio Profiles MPEG_PES_FORMAT Compressed Audio channel options IEEE Std 1722.1-2013 clause 7.3.7.2.3
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_MONO (0x00)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_STEREO (0x01)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_STEREO_JOINED (0x02)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_DUAL_CHANNEL (0x03)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_2_1 (0x04)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_3_0 (0x05)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_3_1 (0x06)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_4_0 (0x07)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_4_1 (0x08)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_5_0 (0x09)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_5_1 (0x0a)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_6_0 (0x0b)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_6_1 (0x0c)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_7_0 (0x0d)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_7_1 (0x0e)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_8_0 (0x0f)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_10_1 (0x10)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_CHANNEL_OPTION_OTHER (0x1f)
+
+// Audio Profiles MPEG_PES_FORMAT Compressed Audio bitrates IEEE Std 1722.1-2013 clause 7.3.7.2.3
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_VARIABLE_BIT_RATE (0x00)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_16_KB_PER_SEC (0x01)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_24_KB_PER_SEC (0x02)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_32_KB_PER_SEC (0x03)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_40_KB_PER_SEC (0x01)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_48_KB_PER_SEC (0x05)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_56_KB_PER_SEC (0x06)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_64_KB_PER_SEC (0x07)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_80_KB_PER_SEC (0x08)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_96_KB_PER_SEC (0x09)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_112_KB_PER_SEC (0x0a)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_128_KB_PER_SEC (0x0b)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_144_KB_PER_SEC (0x0c)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_160_KB_PER_SEC (0x0d)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_192_KB_PER_SEC (0x0e)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_224_KB_PER_SEC (0x0f)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_256_KB_PER_SEC (0x10)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_288_KB_PER_SEC (0x11)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_320_KB_PER_SEC (0x12)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_352_KB_PER_SEC (0x13)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_384_KB_PER_SEC (0x14)
+#define OPENAVB_AEM_MPEG_PES_FORMAT_COMPRESSED_AUDIO_BITRATE_OTHER (0x7f)
+
+// RTP Payload Subtypes IEEE Std 1722.1-2013 clause 7.3.7.4.1
+#define OPENAVB_AEM_RTP_PAYLOAD_SUBTYPE_RTP_MJPEG (0x0000)
+#define OPENAVB_AEM_RTP_PAYLOAD_SUBTYPE_RTP_H264 (0x0001)
+#define OPENAVB_AEM_RTP_PAYLOAD_SUBTYPE_RTP_JPEG200 (0x0002)
+
+// Video Cluster Color Space IEEE Std 1722.1-2013 clause 7.3.10
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_MONO8 (0x0000)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_MONO12_PACKED (0x0001)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_MONO16 (0x0002)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_MONO16_SIGNED (0x0003)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_YUV411_PACKED (0x0004)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_YUV422_PACKED (0x0005)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_YUV444_PACKED (0x0006)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_RGB_PACKED (0x0007)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_RGB16 (0x0008)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_RGB16_SIGNED (0x0009)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_BAYERGR8 (0x000a)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_BAYERGR12_PACKED (0x000b)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_BAYERGR16 (0x000c)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_BAYERRG8 (0x000d)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_BAYERRG12_PACKED (0x000e)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_BAYERRG16 (0x000f)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_BAYERGB8 (0x0010)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_BAYERGB12_PACKED (0x0011)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_BAYERGB16 (0x0012)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_BAYERBG8 (0x0013)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_BAYERBG12_PACKED (0x0014)
+#define OPENAVB_AEM_VIDEP_CLUSTER_COLOR_SPACE_BAYERBG16 (0x0015)
+
+// Command Codes IEEE Std 1722.1-2013 clause 7.4
+#define OPENAVB_AEM_COMMAND_CODE_ACQUIRE_ENTITY (0x0000)
+#define OPENAVB_AEM_COMMAND_CODE_LOCK_ENTITY (0x0001)
+#define OPENAVB_AEM_COMMAND_CODE_ENTITY_AVAILABLE (0x0002)
+#define OPENAVB_AEM_COMMAND_CODE_CONTROLLER_AVAILABLE (0x0003)
+#define OPENAVB_AEM_COMMAND_CODE_READ_DESCRIPTOR (0x0004)
+#define OPENAVB_AEM_COMMAND_CODE_WRITE_DESCRIPTOR (0x0005)
+#define OPENAVB_AEM_COMMAND_CODE_SET_CONFIGURATION (0x0006)
+#define OPENAVB_AEM_COMMAND_CODE_GET_CONFIGURATION (0x0007)
+#define OPENAVB_AEM_COMMAND_CODE_SET_STREAM_FORMAT (0x0008)
+#define OPENAVB_AEM_COMMAND_CODE_GET_STREAM_FORMAT (0x0009)
+#define OPENAVB_AEM_COMMAND_CODE_SET_VIDEO_FORMAT (0x000a)
+#define OPENAVB_AEM_COMMAND_CODE_GET_VIDEO_FORMAT (0x000b)
+#define OPENAVB_AEM_COMMAND_CODE_SET_SENSOR_FORMAT (0x000c)
+#define OPENAVB_AEM_COMMAND_CODE_GET_SENSOR_FORMAT (0x000d)
+#define OPENAVB_AEM_COMMAND_CODE_SET_STREAM_INFO (0x000e)
+#define OPENAVB_AEM_COMMAND_CODE_GET_STREAM_INFO (0x000f)
+#define OPENAVB_AEM_COMMAND_CODE_SET_NAME (0x0010)
+#define OPENAVB_AEM_COMMAND_CODE_GET_NAME (0x0011)
+#define OPENAVB_AEM_COMMAND_CODE_SET_ASSOCIATION_ID (0x0012)
+#define OPENAVB_AEM_COMMAND_CODE_GET_ASSOCIATION_ID (0x0013)
+#define OPENAVB_AEM_COMMAND_CODE_SET_SAMPLING_RATE (0x0014)
+#define OPENAVB_AEM_COMMAND_CODE_GET_SAMPLING_RATE (0x0015)
+#define OPENAVB_AEM_COMMAND_CODE_SET_CLOCK_SOURCE (0x0016)
+#define OPENAVB_AEM_COMMAND_CODE_GET_CLOCK_SOURCE (0x0017)
+#define OPENAVB_AEM_COMMAND_CODE_SET_CONTROL (0x0018)
+#define OPENAVB_AEM_COMMAND_CODE_GET_CONTROL (0x0019)
+#define OPENAVB_AEM_COMMAND_CODE_INCREMENT_CONTROL (0x001a)
+#define OPENAVB_AEM_COMMAND_CODE_DECREMENT_CONTROL (0x001b)
+#define OPENAVB_AEM_COMMAND_CODE_SET_SIGNAL_SELECTOR (0x001c)
+#define OPENAVB_AEM_COMMAND_CODE_GET_SIGNAL_SELECTOR (0x001d)
+#define OPENAVB_AEM_COMMAND_CODE_SET_MIXER (0x001e)
+#define OPENAVB_AEM_COMMAND_CODE_GET_MIXER (0x001f)
+#define OPENAVB_AEM_COMMAND_CODE_SET_MATRIX (0x0020)
+#define OPENAVB_AEM_COMMAND_CODE_GET_MATRIX (0x0021)
+#define OPENAVB_AEM_COMMAND_CODE_START_STREAMING (0x0022)
+#define OPENAVB_AEM_COMMAND_CODE_STOP_STREAMING (0x0023)
+#define OPENAVB_AEM_COMMAND_CODE_REGISTER_UNSOLICITED_NOTIFICATION (0x0024)
+#define OPENAVB_AEM_COMMAND_CODE_DEREGISTER_UNSOLICITED_NOTIFICATION (0x0025)
+#define OPENAVB_AEM_COMMAND_CODE_IDENTIFY_NOTIFICATION (0x0026)
+#define OPENAVB_AEM_COMMAND_CODE_GET_AVB_INFO (0x0027)
+#define OPENAVB_AEM_COMMAND_CODE_GET_AS_PATH (0x0028)
+#define OPENAVB_AEM_COMMAND_CODE_GET_COUNTERS (0x0029)
+#define OPENAVB_AEM_COMMAND_CODE_REBOOT (0x002a)
+#define OPENAVB_AEM_COMMAND_CODE_GET_AUDIO_MAP (0x002b)
+#define OPENAVB_AEM_COMMAND_CODE_ADD_AUDIO_MAPPINGS (0x002c)
+#define OPENAVB_AEM_COMMAND_CODE_REMOVE_AUDIO_MAPPINGS (0x002d)
+#define OPENAVB_AEM_COMMAND_CODE_GET_VIDEO_MAP (0x002e)
+#define OPENAVB_AEM_COMMAND_CODE_ADD_VIDEO_MAPPINGS (0x002f)
+#define OPENAVB_AEM_COMMAND_CODE_REMOVE_VIDEO_MAPPINGS (0x0030)
+#define OPENAVB_AEM_COMMAND_CODE_GET_SENSOR_MAP (0x0031)
+#define OPENAVB_AEM_COMMAND_CODE_ADD_SENSOR_MAPPINGS (0x0032)
+#define OPENAVB_AEM_COMMAND_CODE_REMOVE_SENSOR_MAPPINGS (0x0033)
+#define OPENAVB_AEM_COMMAND_CODE_START_OPERATION (0x0034)
+#define OPENAVB_AEM_COMMAND_CODE_ABORT_OPERATION (0x0035)
+#define OPENAVB_AEM_COMMAND_CODE_OPERATION_STATUS (0x0036)
+#define OPENAVB_AEM_COMMAND_CODE_AUTH_ADD_KEY (0x0037)
+#define OPENAVB_AEM_COMMAND_CODE_AUTH_DELETE_KEY (0x0038)
+#define OPENAVB_AEM_COMMAND_CODE_AUTH_GET_KEY_LIST (0x0039)
+#define OPENAVB_AEM_COMMAND_CODE_AUTH_GET_KEY (0x003a)
+#define OPENAVB_AEM_COMMAND_CODE_AUTH_ADD_KEY_TO_CHAIN (0x003b)
+#define OPENAVB_AEM_COMMAND_CODE_AUTH_DELETE_KEY_FROM_CHAIN (0x003c)
+#define OPENAVB_AEM_COMMAND_CODE_AUTH_GET_KEYCHAIN_LIST (0x003d)
+#define OPENAVB_AEM_COMMAND_CODE_AUTH_GET_IDENTITY (0x003e)
+#define OPENAVB_AEM_COMMAND_CODE_AUTH_ADD_TOKEN (0x003f)
+#define OPENAVB_AEM_COMMAND_CODE_AUTH_DELETE_TOKEN (0x0040)
+#define OPENAVB_AEM_COMMAND_CODE_AUTHENTICATE (0x0041)
+#define OPENAVB_AEM_COMMAND_CODE_DEAUTHENTICATE (0x0042)
+#define OPENAVB_AEM_COMMAND_CODE_ENABLE_TRANSPORT_SECURITY (0x0043)
+#define OPENAVB_AEM_COMMAND_CODE_DISABLE_TRANSPORT_SECURITY (0x0044)
+#define OPENAVB_AEM_COMMAND_CODE_ENABLE_STREAM_ENCRYPTION (0x0045)
+#define OPENAVB_AEM_COMMAND_CODE_DISABLE_STREAM_ENCRYPTION (0x0046)
+#define OPENAVB_AEM_COMMAND_CODE_SET_MEMORY_OBJECT_LENGTH (0x0047)
+#define OPENAVB_AEM_COMMAND_CODE_GET_MEMORY_OBJECT_LENGTH (0x0048)
+#define OPENAVB_AEM_COMMAND_CODE_SET_STREAM_BACKUP (0x0049)
+#define OPENAVB_AEM_COMMAND_CODE_GET_STREAM_BACKUP (0x004a)
+#define OPENAVB_AEM_COMMAND_CODE_EXPANSION (0x7fff)
+
+// Command Status IEEE Std 1722.1-2013 clause 7.4
+#define OPENAVB_AEM_COMMAND_STATUS_SUCCESS (0)
+#define OPENAVB_AEM_COMMAND_STATUS_NOT_IMPLEMENTED (1)
+#define OPENAVB_AEM_COMMAND_STATUS_NO_SUCH_DESCRIPTOR (2)
+#define OPENAVB_AEM_COMMAND_STATUS_ENTITY_LOCKED (3)
+#define OPENAVB_AEM_COMMAND_STATUS_ENTITY_ACQUIRED (4)
+#define OPENAVB_AEM_COMMAND_STATUS_NOT_AUTHENTICATED (5)
+#define OPENAVB_AEM_COMMAND_STATUS_AUTHENTICATION_DISABLED (6)
+#define OPENAVB_AEM_COMMAND_STATUS_BAD_ARGUMENTS (7)
+#define OPENAVB_AEM_COMMAND_STATUS_NO_RESOURCES (8)
+#define OPENAVB_AEM_COMMAND_STATUS_IN_PROGRESS (9)
+#define OPENAVB_AEM_COMMAND_STATUS_ENTITY_MISBEHAVING (10)
+#define OPENAVB_AEM_COMMAND_STATUS_NOT_SUPPORTED (11)
+#define OPENAVB_AEM_COMMAND_STATUS_STREAM_IS_RUNNING (12)
+
+// ACQUIRE_ENTITY Command Flags IEEE Std 1722.1-2013 clause 7.4.1
+#define OPENAVB_AEM_ACQUIRE_ENTITY_COMMAND_FLAG_PERSISTENT (0x00000001)
+#define OPENAVB_AEM_ACQUIRE_ENTITY_COMMAND_FLAG_RELEASE (0x80000000)
+
+// LOCK ENTITY Command Flags IEEE Std 1722.1-2013 clause 7.4.2
+#define OPENAVB_AEM_LOCK_ENTITY_COMMAND_FLAG_UNLOCK (ox00000001)
+
+// SET_STREAM_INFO Command Flags IEEE Std 1722.1-2013 clause 7.4.15
+#define OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_CLASS_B (0x00000001)
+#define OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_FAST_CONNECT (0x00000002)
+#define OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_SAVED_STATE (0x00000004)
+#define OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAMING_WAIT (0x00000008)
+#define OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_ENCRYPTED_PDU (0x00000010)
+#define OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_VLAN_ID_VALID (0x02000000)
+#define OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_CONNECTED (0x04000000)
+#define OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_MSRP_FAILURE_VALID (0x08000000)
+#define OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_DEST_MAC_VALID (0x10000000)
+#define OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_MSRP_ACC_LAT_VALID (0x20000000)
+#define OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_ID_VALID (0x40000000)
+#define OPENAVB_AEM_SET_STREAM_INFO_COMMAND_FLAG_STREAM_FORMAT_VALID (0x80000000)
+
+// SET_MATRIX Command Direction IEEE Std 1722.1-2013 clause 7.4.33
+#define OPENAVB_AEM_SET_MATRIX_COMMAND_DIRECTION_HORIZONTAL (0)
+#define OPENAVB_AEM_SET_MATRIX_COMMAND_DIRECTION_VERTICAL (1)
+
+// GET_AVB_INFO Command Flags IEEE Std 1722.1-2013 clause 7.4.40
+#define OPENAVB_AEM_GET_AVB_INFO_COMMAND_FLAG_AS_CAPABLE (0x01)
+#define OPENAVB_AEM_GET_AVB_INFO_COMMAND_GPTP_ENABLED (0x02)
+#define OPENAVB_AEM_GET_AVB_INFO_COMMAND_SRP_ENABLED (0x04)
+
+// GET_COUNTERS Command ENTITY Counters IEEE Std 1722.1-2013 clause 7.4.42
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_8 (0x01000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_7 (0x02000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_6 (0x04000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_5 (0x08000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_4 (0x10000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_3 (0x20000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_2 (0x40000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_ENTITY_COUNTER_ENTITY_SPECIFIC_1 (0x80000000)
+
+// GET_COUNTERS Command AVB_INTERFACE Counters IEEE Std 1722.1-2013 clause 7.4.42
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_LINK_UP (0x00000001)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_LINK_DOWN (0x00000002)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_FRAMES_TX (0x00000004)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_FRAMES_RX (0x00000008)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_RX_CRC_ERROR (0x00000010)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_GPTP_GM_CHANGED (0x00000020)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_ENTITY_SPECIFIC_8 (0x01000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_ENTITY_SPECIFIC_7 (0x02000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_ENTITY_SPECIFIC_6 (0x04000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_ENTITY_SPECIFIC_5 (0x08000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_ENTITY_SPECIFIC_4 (0x10000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_ENTITY_SPECIFIC_3 (0x20000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_ENTITY_SPECIFIC_2 (0x40000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_AVB_INTERFACE_COUNTER_ENTITY_SPECIFIC_1 (0x80000000)
+
+// GET_COUNTERS Command CLOCK_DOMAIN Counters IEEE Std 1722.1-2013 clause 7.4.42
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_LOCKED (0x00000001)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_UNLOCKED (0x00000002)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_ENTITY_SPECIFIC_1 (0x01000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_ENTITY_SPECIFIC_2 (0x02000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_ENTITY_SPECIFIC_3 (0x04000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_ENTITY_SPECIFIC_4 (0x08000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_ENTITY_SPECIFIC_5 (0x10000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_ENTITY_SPECIFIC_6 (0x20000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_ENTITY_SPECIFIC_7 (0x40000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_ENTITY_SPECIFIC_8 (0x80000000)
+
+// GET_COUNTERS Command STREAM_INPUT Counters IEEE Std 1722.1-2013 clause 7.4.42
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_MEDIA_LOCKED (0x00000001)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_MEDIA_UNLOCKED (0x00000002)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_STREAM_RESET (0x00000004)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_SEQ_NUM_MISMATCH (0x00000008)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_MEDIA_RESET (0x00000010)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_TIMESTAMP_UNCERTAIN (0x00000020)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_TIMESTAMP_VALID (0x00000040)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_TIMESTAMP_NOT_VALID (0x00000080)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_UNSUPPORTED_FORMAT (0x00000100)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_LATE_TIMESTAMP (0x00000200)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_EARLY_TIMESTAMP (0x00000400)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_FRAMES_RX (0x00000800)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_FRAMES_TX (0x00001000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_ENTITY_SPECIFIC_8 (0x01000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_ENTITY_SPECIFIC_7 (0x02000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_ENTITY_SPECIFIC_6 (0x04000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_ENTITY_SPECIFIC_5 (0x08000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_ENTITY_SPECIFIC_4 (0x10000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_ENTITY_SPECIFIC_3 (0x20000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_ENTITY_SPECIFIC_2 (0x40000000)
+#define OPENAVB_AEM_GET_COUNTERS_COMMAND_STREAM_INPUT_COUNTER_ENTITY_SPECIFIC_1 (0x80000000)
+
+#endif // OPENAVB_AEM_TYPES_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_audio_cluster.c b/lib/avtp_pipeline/aem/openavb_descriptor_audio_cluster.c
new file mode 100644
index 00000000..b3addd1a
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_audio_cluster.c
@@ -0,0 +1,179 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Audio Cluster Descriptor
+ * MODULE SUMMARY : Implements the AVDECC Audio Cluster IEEE Std 1722.1-2013 clause 7.2.16
+ ******************************************************************
+ */
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_audio_cluster.h"
+
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemDescriptorAudioClusterToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_audio_cluster_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_AUDIO_CLUSTER_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_audio_cluster_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->object_name);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.index, 0, 2);
+ OCT_D2BHTONS(pDst, pSrc->signal_type);
+ OCT_D2BHTONS(pDst, pSrc->signal_index);
+ OCT_D2BHTONS(pDst, pSrc->signal_output);
+ OCT_D2BHTONL(pDst, pSrc->path_latency);
+ OCT_D2BHTONL(pDst, pSrc->block_latency);
+ OCT_D2BHTONS(pDst, pSrc->channel_count);
+ OCT_D2BHTONB(pDst, pSrc->format);
+
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorAudioClusterFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_audio_cluster_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_AUDIO_CLUSTER_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_audio_cluster_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DMEMCP(pDst->object_name, pSrc);
+ BIT_B2DNTOHS(pDst->localized_description.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->localized_description.index, pSrc, 0x0007, 0, 2);
+ OCT_B2DNTOHS(pDst->signal_type, pSrc);
+ OCT_B2DNTOHS(pDst->signal_index, pSrc);
+ OCT_B2DNTOHS(pDst->signal_output, pSrc);
+ OCT_B2DNTOHL(pDst->path_latency, pSrc);
+ OCT_B2DNTOHL(pDst->block_latency, pSrc);
+ OCT_B2DNTOHS(pDst->channel_count, pSrc);
+ OCT_B2DNTOHB(pDst->format, pSrc);
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorAudioClusterUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_audio_cluster_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_audio_cluster_t *openavbAemDescriptorAudioClusterNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_audio_cluster_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_audio_cluster_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = FALSE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorAudioClusterToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorAudioClusterFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorAudioClusterUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_AUDIO_CLUSTER;
+
+ // Default to no localized strings.
+ pDescriptor->localized_description.offset = OPENAVB_AEM_NO_STRING_OFFSET;
+ pDescriptor->localized_description.index = OPENAVB_AEM_NO_STRING_INDEX;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_audio_cluster.h b/lib/avtp_pipeline/aem/openavb_descriptor_audio_cluster.h
new file mode 100644
index 00000000..b1a5d9b5
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_audio_cluster.h
@@ -0,0 +1,46 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Audio Cluster Descriptor
+ * MODULE SUMMARY : Interface for the Audio Cluster Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_AUDIO_CLUSTER_H
+#define OPENAVB_DESCRIPTOR_AUDIO_CLUSTER_H 1
+
+#include "openavb_descriptor_audio_cluster_pub.h"
+
+#define OPENAVB_DESCRIPTOR_AUDIO_CLUSTER_BASE_LENGTH (87)
+
+#endif // OPENAVB_DESCRIPTOR_AUDIO_CLUSTER_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_audio_cluster_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_audio_cluster_pub.h
new file mode 100644
index 00000000..4708f030
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_audio_cluster_pub.h
@@ -0,0 +1,65 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Audio Cluster Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the Audio Cluster Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_AUDIO_CLUSTER_PUB_H
+#define OPENAVB_DESCRIPTOR_AUDIO_CLUSTER_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+
+// AUDIO CLUSTER Descriptor IEEE Std 1722.1-2013 clause 7.2.16
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type; // Set internally
+ U16 descriptor_index; // Set internally
+ U8 object_name[OPENAVB_AEM_STRLEN_MAX];
+ openavb_aem_string_ref_t localized_description;
+ U16 signal_type;
+ U16 signal_index;
+ U16 signal_output;
+ U32 path_latency;
+ U32 block_latency;
+ U16 channel_count;
+ U8 format;
+} openavb_aem_descriptor_audio_cluster_t;
+
+openavb_aem_descriptor_audio_cluster_t *openavbAemDescriptorAudioClusterNew(void);
+
+#endif // OPENAVB_DESCRIPTOR_AUDIO_CLUSTER_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_audio_map.c b/lib/avtp_pipeline/aem/openavb_descriptor_audio_map.c
new file mode 100644
index 00000000..514e1909
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_audio_map.c
@@ -0,0 +1,180 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Audio Map Descriptor
+ * MODULE SUMMARY : Implements the AVDECC Audio Map IEEE Std 1722.1-2013 clause 7.2.19
+ ******************************************************************
+ */
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_audio_map.h"
+
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemDescriptorAudioMapToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_audio_map_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_AUDIO_MAP_BASE_LENGTH + (pDescriptor->number_of_mappings * OPENAVB_DESCRIPTOR_AUDIO_MAP_AUDIO_MAPPING_FORMAT_LENGTH)) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_audio_map_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BHTONS(pDst, pSrc->mappings_offset);
+ OCT_D2BHTONS(pDst, pSrc->number_of_mappings);
+
+ int i1;
+ for (i1 = 0; i1 < pSrc->number_of_mappings; i1++) {
+ OCT_D2BHTONS(pDst, pSrc->mapping_formats[i1].mapping_stream_index);
+ OCT_D2BHTONS(pDst, pSrc->mapping_formats[i1].mapping_stream_channel);
+ OCT_D2BHTONS(pDst, pSrc->mapping_formats[i1].mapping_cluster_offset);
+ OCT_D2BHTONS(pDst, pSrc->mapping_formats[i1].mapping_cluster_channel);
+ }
+
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorAudioMapFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_audio_map_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_AUDIO_MAP_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_audio_map_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DNTOHS(pDst->mappings_offset, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_mappings, pSrc);
+
+ if (bufLength < OPENAVB_DESCRIPTOR_AUDIO_MAP_BASE_LENGTH + (pDescriptor->number_of_mappings * OPENAVB_DESCRIPTOR_AUDIO_MAP_AUDIO_MAPPING_FORMAT_LENGTH)) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ int i1;
+ for (i1 = 0; i1 < pDst->number_of_mappings; i1++) {
+ OCT_B2DNTOHS(pDst->mapping_formats[i1].mapping_stream_index, pSrc);
+ OCT_B2DNTOHS(pDst->mapping_formats[i1].mapping_stream_channel, pSrc);
+ OCT_B2DNTOHS(pDst->mapping_formats[i1].mapping_cluster_offset, pSrc);
+ OCT_B2DNTOHS(pDst->mapping_formats[i1].mapping_cluster_channel, pSrc);
+ }
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorAudioMapUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_audio_map_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_audio_map_t *openavbAemDescriptorAudioMapNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_audio_map_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_audio_map_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = FALSE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorAudioMapToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorAudioMapFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorAudioMapUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_AUDIO_MAP;
+ pDescriptor->mappings_offset = OPENAVB_DESCRIPTOR_AUDIO_MAP_BASE_LENGTH;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_audio_map.h b/lib/avtp_pipeline/aem/openavb_descriptor_audio_map.h
new file mode 100644
index 00000000..7eba7ff1
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_audio_map.h
@@ -0,0 +1,47 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Audio Map Descriptor
+ * MODULE SUMMARY : Interface for the Audio Map Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_AUDIO_MAP_H
+#define OPENAVB_DESCRIPTOR_AUDIO_MAP_H 1
+
+#include "openavb_descriptor_audio_map_pub.h"
+
+#define OPENAVB_DESCRIPTOR_AUDIO_MAP_BASE_LENGTH (8)
+#define OPENAVB_DESCRIPTOR_AUDIO_MAP_AUDIO_MAPPING_FORMAT_LENGTH (8)
+
+#endif // OPENAVB_DESCRIPTOR_AUDIO_MAP_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_audio_map_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_audio_map_pub.h
new file mode 100644
index 00000000..902ff71e
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_audio_map_pub.h
@@ -0,0 +1,69 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Audio Map Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the Audio Map Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_AUDIO_MAP_PUB_H
+#define OPENAVB_DESCRIPTOR_AUDIO_MAP_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+
+#define OPENAVB_DESCRIPTOR_AUDIO_MAP_MAX_SAMPLING_RATES (62)
+
+// AUDIO UNIT Descriptor : Audio Mappings Format IEEE Std 1722.1-2013 clause 7.2.19.1
+typedef struct {
+ U16 mapping_stream_index;
+ U16 mapping_stream_channel;
+ U16 mapping_cluster_offset;
+ U16 mapping_cluster_channel;
+} openavb_aem_descriptor_audio_map_audio_mapping_format_t;
+
+// AUDIO MAP Descriptor IEEE Std 1722.1-2013 clause 7.2.19
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type; // Set internally
+ U16 descriptor_index; // Set internally
+ U16 mappings_offset;
+ U16 number_of_mappings;
+ openavb_aem_descriptor_audio_map_audio_mapping_format_t mapping_formats[OPENAVB_DESCRIPTOR_AUDIO_MAP_MAX_SAMPLING_RATES];
+} openavb_aem_descriptor_audio_map_t;
+
+openavb_aem_descriptor_audio_map_t *openavbAemDescriptorAudioMapNew();
+
+#endif // OPENAVB_DESCRIPTOR_AUDIO_MAP_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_audio_unit.c b/lib/avtp_pipeline/aem/openavb_descriptor_audio_unit.c
new file mode 100644
index 00000000..0f6fdb4a
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_audio_unit.c
@@ -0,0 +1,297 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Audio Unit Descriptor
+ * MODULE SUMMARY : Implements the AVDECC Audio Unit IEEE Std 1722.1-2013 clause 7.2.3
+ ******************************************************************
+ */
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_audio_unit.h"
+
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemDescriptorAudioUnitToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_audio_unit_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_AUDIO_UNIT_BASE_LENGTH + (pDescriptor->sampling_rates_count * OPENAVB_DESCRIPTOR_AUDIO_UNIT_SAMPLING_RATE_LENGTH)) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_audio_unit_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->object_name);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.index, 0, 2);
+ OCT_D2BHTONS(pDst, pSrc->clock_domain_index);
+ OCT_D2BHTONS(pDst, pSrc->number_of_stream_input_ports);
+ OCT_D2BHTONS(pDst, pSrc->base_stream_input_port);
+ OCT_D2BHTONS(pDst, pSrc->number_of_stream_output_ports);
+ OCT_D2BHTONS(pDst, pSrc->base_stream_output_port);
+ OCT_D2BHTONS(pDst, pSrc->number_of_external_input_ports);
+ OCT_D2BHTONS(pDst, pSrc->base_external_input_port);
+ OCT_D2BHTONS(pDst, pSrc->number_of_external_output_ports);
+ OCT_D2BHTONS(pDst, pSrc->base_external_output_port);
+ OCT_D2BHTONS(pDst, pSrc->number_of_internal_input_ports);
+ OCT_D2BHTONS(pDst, pSrc->base_internal_input_port);
+ OCT_D2BHTONS(pDst, pSrc->number_of_internal_output_ports);
+ OCT_D2BHTONS(pDst, pSrc->base_internal_output_port);
+ OCT_D2BHTONS(pDst, pSrc->number_of_controls);
+ OCT_D2BHTONS(pDst, pSrc->base_control);
+ OCT_D2BHTONS(pDst, pSrc->number_of_signal_selectors);
+ OCT_D2BHTONS(pDst, pSrc->base_signal_selector);
+ OCT_D2BHTONS(pDst, pSrc->number_of_mixers);
+ OCT_D2BHTONS(pDst, pSrc->base_mixer);
+ OCT_D2BHTONS(pDst, pSrc->number_of_matrices);
+ OCT_D2BHTONS(pDst, pSrc->base_matrix);
+ OCT_D2BHTONS(pDst, pSrc->number_of_splitters);
+ OCT_D2BHTONS(pDst, pSrc->base_splitter);
+ OCT_D2BHTONS(pDst, pSrc->number_of_combiners);
+ OCT_D2BHTONS(pDst, pSrc->base_combiner);
+ OCT_D2BHTONS(pDst, pSrc->number_of_demultiplexers);
+ OCT_D2BHTONS(pDst, pSrc->base_demultiplexer);
+ OCT_D2BHTONS(pDst, pSrc->number_of_multiplexers);
+ OCT_D2BHTONS(pDst, pSrc->base_multiplexer);
+ OCT_D2BHTONS(pDst, pSrc->number_of_transcoders);
+ OCT_D2BHTONS(pDst, pSrc->base_transcoder);
+ OCT_D2BHTONS(pDst, pSrc->number_of_control_blocks);
+ OCT_D2BHTONS(pDst, pSrc->base_control_block);
+ BIT_D2BHTONL(pDst, pSrc->current_sampling_rate.pull, 29, 0);
+ BIT_D2BHTONL(pDst, pSrc->current_sampling_rate.base, 0, 4);
+ OCT_D2BHTONS(pDst, pSrc->sampling_rates_offset);
+ OCT_D2BHTONS(pDst, pSrc->sampling_rates_count);
+
+ int i1;
+ for (i1 = 0; i1 < pSrc->sampling_rates_count; i1++) {
+ BIT_D2BHTONL(pDst, pSrc->sampling_rates[i1].pull, 29, 0);
+ BIT_D2BHTONL(pDst, pSrc->sampling_rates[i1].base, 0, 4);
+ }
+
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorAudioUnitFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_audio_unit_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_AUDIO_UNIT_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_audio_unit_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DMEMCP(pDst->object_name, pSrc);
+ BIT_B2DNTOHS(pDst->localized_description.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->localized_description.index, pSrc, 0x0007, 0, 2);
+ OCT_B2DNTOHS(pDst->clock_domain_index, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_stream_input_ports, pSrc);
+ OCT_B2DNTOHS(pDst->base_stream_input_port, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_stream_output_ports, pSrc);
+ OCT_B2DNTOHS(pDst->base_stream_output_port, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_external_input_ports, pSrc);
+ OCT_B2DNTOHS(pDst->base_external_input_port, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_external_output_ports, pSrc);
+ OCT_B2DNTOHS(pDst->base_external_output_port, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_internal_input_ports, pSrc);
+ OCT_B2DNTOHS(pDst->base_internal_input_port, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_internal_output_ports, pSrc);
+ OCT_B2DNTOHS(pDst->base_internal_output_port, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_controls, pSrc);
+ OCT_B2DNTOHS(pDst->base_control, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_signal_selectors, pSrc);
+ OCT_B2DNTOHS(pDst->base_signal_selector, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_mixers, pSrc);
+ OCT_B2DNTOHS(pDst->base_mixer, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_matrices, pSrc);
+ OCT_B2DNTOHS(pDst->base_matrix, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_splitters, pSrc);
+ OCT_B2DNTOHS(pDst->base_splitter, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_combiners, pSrc);
+ OCT_B2DNTOHS(pDst->base_combiner, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_demultiplexers, pSrc);
+ OCT_B2DNTOHS(pDst->base_demultiplexer, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_multiplexers, pSrc);
+ OCT_B2DNTOHS(pDst->base_multiplexer, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_transcoders, pSrc);
+ OCT_B2DNTOHS(pDst->base_transcoder, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_control_blocks, pSrc);
+ OCT_B2DNTOHS(pDst->base_control_block, pSrc);
+ BIT_B2DNTOHL(pDst->current_sampling_rate.pull, pSrc, 0xe0000000, 29, 0);
+ BIT_B2DNTOHL(pDst->current_sampling_rate.base, pSrc, 0x1fffffff, 0, 2);
+ OCT_B2DNTOHS(pDst->sampling_rates_offset, pSrc);
+ OCT_B2DNTOHS(pDst->sampling_rates_count, pSrc);
+
+ if (bufLength < OPENAVB_DESCRIPTOR_AUDIO_UNIT_BASE_LENGTH + (pDescriptor->sampling_rates_count * OPENAVB_DESCRIPTOR_AUDIO_UNIT_SAMPLING_RATE_LENGTH)) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ int i1;
+ for (i1 = 0; i1 < pDst->sampling_rates_count; i1++) {
+ BIT_B2DNTOHL(pDst->sampling_rates[i1].pull, pSrc, 0xe0000000, 29, 0);
+ BIT_B2DNTOHL(pDst->sampling_rates[i1].base, pSrc, 0x1fffffff, 0, 2);
+ }
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorAudioUnitUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_audio_unit_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_audio_unit_t *openavbAemDescriptorAudioUnitNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_audio_unit_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_audio_unit_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = TRUE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorAudioUnitToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorAudioUnitFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorAudioUnitUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_AUDIO_UNIT;
+ pDescriptor->sampling_rates_offset = OPENAVB_DESCRIPTOR_AUDIO_UNIT_BASE_LENGTH;
+
+ // Default to no localized strings.
+ pDescriptor->localized_description.offset = OPENAVB_AEM_NO_STRING_OFFSET;
+ pDescriptor->localized_description.index = OPENAVB_AEM_NO_STRING_INDEX;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorAudioUnitInitialize(openavb_aem_descriptor_audio_unit_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig)
+{
+ (void) nConfigIdx;
+ if (!pDescriptor || !pConfig) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // Specify a name.
+ sprintf((char *)(pDescriptor->object_name), "Audio Unit %u", pDescriptor->descriptor_index);
+
+ // Add the port information.
+ if (pConfig->stream->role == AVB_ROLE_TALKER) {
+ // There will be one stream output port.
+ pDescriptor->number_of_stream_output_ports = 1;
+ pDescriptor->base_stream_output_port = 0;
+ }
+ else if (pConfig->stream->role == AVB_ROLE_LISTENER) {
+ // There will be one stream input port.
+ pDescriptor->number_of_stream_input_ports = 1;
+ pDescriptor->base_stream_input_port = 0;
+ }
+ // AVDECC_TODO - Once implemented, add support for External and Internal ports.
+
+ // AVDECC_TODO - Once implemented, add support for mixers, matrices, splitters, combiners, demultiplexers, multiplexers, transcoders, and control blocks.
+
+ // AVDECC_TODO - Add the sample rate information. Should this be done in openavbAemDescriptorAudioUnitUpdate() instead?
+ // AVDECC_TODO - Merge the configurations instead of overwriting it
+ pDescriptor->current_sampling_rate.pull = 0;
+ pDescriptor->current_sampling_rate.base = pConfig->stream->current_sampling_rate;
+ pDescriptor->sampling_rates_offset = OPENAVB_DESCRIPTOR_AUDIO_UNIT_BASE_LENGTH;
+ pDescriptor->sampling_rates_count = pConfig->stream->sampling_rates_count;
+ int i = 0;
+ while (i < OPENAVB_DESCRIPTOR_AUDIO_UNIT_MAX_SAMPLING_RATES && pConfig->stream->sampling_rates[i] != 0)
+ {
+ pDescriptor->sampling_rates[i].pull = 0;
+ pDescriptor->sampling_rates[i].base = pConfig->stream->sampling_rates[i];
+ i++;
+ }
+
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_audio_unit.h b/lib/avtp_pipeline/aem/openavb_descriptor_audio_unit.h
new file mode 100644
index 00000000..9e999530
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_audio_unit.h
@@ -0,0 +1,47 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Audio Unit Descriptor
+ * MODULE SUMMARY : Interface for the Audio Unit Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_AUDIO_UNIT_H
+#define OPENAVB_DESCRIPTOR_AUDIO_UNIT_H 1
+
+#include "openavb_descriptor_audio_unit_pub.h"
+
+#define OPENAVB_DESCRIPTOR_AUDIO_UNIT_BASE_LENGTH (144)
+#define OPENAVB_DESCRIPTOR_AUDIO_UNIT_SAMPLING_RATE_LENGTH (4)
+
+#endif // OPENAVB_DESCRIPTOR_AUDIO_UNIT_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_audio_unit_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_audio_unit_pub.h
new file mode 100644
index 00000000..6b368728
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_audio_unit_pub.h
@@ -0,0 +1,99 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Audio Unit Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the Audio Unit Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_AUDIO_UNIT_PUB_H
+#define OPENAVB_DESCRIPTOR_AUDIO_UNIT_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+
+#define OPENAVB_DESCRIPTOR_AUDIO_UNIT_MAX_SAMPLING_RATES (91)
+
+// AUDIO UNIT Descriptor IEEE Std 1722.1-2013 clause 7.2.3
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type; // Set internally
+ U16 descriptor_index; // Set internally
+ U8 object_name[OPENAVB_AEM_STRLEN_MAX];
+ openavb_aem_string_ref_t localized_description;
+ U16 clock_domain_index;
+ U16 number_of_stream_input_ports;
+ U16 base_stream_input_port;
+ U16 number_of_stream_output_ports;
+ U16 base_stream_output_port;
+ U16 number_of_external_input_ports;
+ U16 base_external_input_port;
+ U16 number_of_external_output_ports;
+ U16 base_external_output_port;
+ U16 number_of_internal_input_ports;
+ U16 base_internal_input_port;
+ U16 number_of_internal_output_ports;
+ U16 base_internal_output_port;
+ U16 number_of_controls;
+ U16 base_control;
+ U16 number_of_signal_selectors;
+ U16 base_signal_selector;
+ U16 number_of_mixers;
+ U16 base_mixer;
+ U16 number_of_matrices;
+ U16 base_matrix;
+ U16 number_of_splitters;
+ U16 base_splitter;
+ U16 number_of_combiners;
+ U16 base_combiner;
+ U16 number_of_demultiplexers;
+ U16 base_demultiplexer;
+ U16 number_of_multiplexers;
+ U16 base_multiplexer;
+ U16 number_of_transcoders;
+ U16 base_transcoder;
+ U16 number_of_control_blocks;
+ U16 base_control_block;
+ openavb_aem_sampling_rate_t current_sampling_rate;
+ U16 sampling_rates_offset;
+ U16 sampling_rates_count;
+ openavb_aem_sampling_rate_t sampling_rates[OPENAVB_DESCRIPTOR_AUDIO_UNIT_MAX_SAMPLING_RATES];
+} openavb_aem_descriptor_audio_unit_t;
+
+openavb_aem_descriptor_audio_unit_t *openavbAemDescriptorAudioUnitNew(void);
+
+bool openavbAemDescriptorAudioUnitInitialize(openavb_aem_descriptor_audio_unit_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig);
+
+#endif // OPENAVB_DESCRIPTOR_AUDIO_UNIT_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_avb_interface.c b/lib/avtp_pipeline/aem/openavb_descriptor_avb_interface.c
new file mode 100644
index 00000000..366f11e4
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_avb_interface.c
@@ -0,0 +1,244 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC AVB Interface Descriptor
+ * MODULE SUMMARY : Implements the AVDECC AVB Interface IEEE Std 1722.1-2013 clause 7.2.8
+ ******************************************************************
+ */
+
+#include "openavb_platform.h"
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_avb_interface.h"
+
+#ifndef AVB_PTP_AVAILABLE
+#include "openavb_grandmaster_osal_pub.h"
+#endif // !AVB_PTP_AVAILABLE
+
+extern openavb_avdecc_cfg_t gAvdeccCfg;
+
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemDescriptorAvbInterfaceToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_avb_interface_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_AVB_INTERFACE_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_avb_interface_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->object_name);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.index, 0, 2);
+ OCT_D2BMEMCP(pDst, pSrc->mac_address);
+ OCT_D2BHTONS(pDst, pSrc->interface_flags);
+ OCT_D2BMEMCP(pDst, pSrc->clock_identity);
+ OCT_D2BHTONB(pDst, pSrc->priority1);
+ OCT_D2BHTONB(pDst, pSrc->clock_class);
+ OCT_D2BHTONS(pDst, pSrc->offset_scaled_log_variance);
+ OCT_D2BHTONB(pDst, pSrc->clock_accuracy);
+ OCT_D2BHTONB(pDst, pSrc->priority2);
+ OCT_D2BHTONB(pDst, pSrc->domain_number);
+ OCT_D2BHTONB(pDst, pSrc->log_sync_interval);
+ OCT_D2BHTONB(pDst, pSrc->log_announce_interval);
+ OCT_D2BHTONB(pDst, pSrc->log_pdelay_interval);
+ OCT_D2BHTONS(pDst, pSrc->port_number);
+
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorAvbInterfaceFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_avb_interface_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_AVB_INTERFACE_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_avb_interface_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DMEMCP(pDst->object_name, pSrc);
+ BIT_B2DNTOHS(pDst->localized_description.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->localized_description.index, pSrc, 0x0007, 0, 2);
+ OCT_B2DMEMCP(pDst->mac_address, pSrc);
+ OCT_B2DNTOHS(pDst->interface_flags, pSrc);
+ OCT_B2DMEMCP(pDst->clock_identity, pSrc);
+ OCT_B2DNTOHB(pDst->priority1, pSrc);
+ OCT_B2DNTOHB(pDst->clock_class, pSrc);
+ OCT_B2DNTOHS(pDst->offset_scaled_log_variance, pSrc);
+ OCT_B2DNTOHB(pDst->clock_accuracy, pSrc);
+ OCT_B2DNTOHB(pDst->priority2, pSrc);
+ OCT_B2DNTOHB(pDst->domain_number, pSrc);
+ OCT_B2DNTOHB(pDst->log_sync_interval, pSrc);
+ OCT_B2DNTOHB(pDst->log_announce_interval, pSrc);
+ OCT_B2DNTOHB(pDst->log_pdelay_interval, pSrc);
+ OCT_B2DNTOHS(pDst->port_number, pSrc);
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorAvbInterfaceUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_avb_interface_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // Make the Clock Identity the same as the Entity Id.
+ // Just use the first entity descriptor from the first configuration, as they should all be the same.
+ openavb_aem_descriptor_entity_t *pEntityDescriptor =
+ (openavb_aem_descriptor_entity_t *) openavbAemGetDescriptor(0, OPENAVB_AEM_DESCRIPTOR_ENTITY, 0);
+ if (pEntityDescriptor) {
+ memcpy(pDescriptor->clock_identity, pEntityDescriptor->entity_id, sizeof(pDescriptor->clock_identity));
+ }
+
+#ifndef AVB_PTP_AVAILABLE
+ // Get the current grandmaster information.
+ if (!osalClockGrandmasterGetInterface(
+ pDescriptor->clock_identity,
+ &pDescriptor->priority1,
+ &pDescriptor->clock_class,
+ &pDescriptor->offset_scaled_log_variance,
+ &pDescriptor->clock_accuracy,
+ &pDescriptor->priority2,
+ &pDescriptor->domain_number,
+ &pDescriptor->log_sync_interval,
+ &pDescriptor->log_announce_interval,
+ &pDescriptor->log_pdelay_interval,
+ &pDescriptor->port_number))
+ {
+ AVB_LOG_ERROR("osalClockGrandmasterGetInterface failure");
+ }
+#endif // !AVB_PTP_AVAILABLE
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_avb_interface_t *openavbAemDescriptorAvbInterfaceNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_avb_interface_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_avb_interface_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = TRUE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorAvbInterfaceToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorAvbInterfaceFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorAvbInterfaceUpdate;
+
+ strncpy((char *) pDescriptor->object_name, gAvdeccCfg.ifname, sizeof(pDescriptor->object_name));
+ memcpy(pDescriptor->mac_address, gAvdeccCfg.ifmac, sizeof(pDescriptor->mac_address));
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_AVB_INTERFACE;
+
+ // Default to supporting all the interfaces.
+ pDescriptor->interface_flags =
+ OPENAVB_AEM_INTERFACE_TYPE_GPTP_GRANDMASTER_SUPPORTED |
+ OPENAVB_AEM_INTERFACE_TYPE_GPTP_SUPPORTED |
+ OPENAVB_AEM_INTERFACE_TYPE_SRP_SUPPORTED;
+
+ // Default to no localized strings.
+ pDescriptor->localized_description.offset = OPENAVB_AEM_NO_STRING_OFFSET;
+ pDescriptor->localized_description.index = OPENAVB_AEM_NO_STRING_INDEX;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorAvbInterfaceInitialize(openavb_aem_descriptor_avb_interface_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig)
+{
+ (void) nConfigIdx;
+ if (!pDescriptor || !pConfig) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_avb_interface.h b/lib/avtp_pipeline/aem/openavb_descriptor_avb_interface.h
new file mode 100644
index 00000000..093656c7
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_avb_interface.h
@@ -0,0 +1,46 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC AVB Interface Descriptor
+ * MODULE SUMMARY : Interface for the AVB Interface Desciptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_AVB_INTERFACE_H
+#define OPENAVB_DESCRIPTOR_AVB_INTERFACE_H 1
+
+#include "openavb_descriptor_avb_interface_pub.h"
+
+#define OPENAVB_DESCRIPTOR_AVB_INTERFACE_BASE_LENGTH (98)
+
+#endif // OPENAVB_DESCRIPTOR_AVB_INTERFACE_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_avb_interface_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_avb_interface_pub.h
new file mode 100644
index 00000000..c2c17fed
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_avb_interface_pub.h
@@ -0,0 +1,73 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC AVB Interface Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the AVB Interface Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_AVB_INTERFACE_PUB_H
+#define OPENAVB_DESCRIPTOR_AVB_INTERFACE_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+
+// AVB INTERFACE Descriptor IEEE Std 1722.1-2013 clause 7.2.8
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type; // Set internally
+ U16 descriptor_index; // Set internally
+ U8 object_name[OPENAVB_AEM_STRLEN_MAX]; // Set internally
+ openavb_aem_string_ref_t localized_description;
+ U8 mac_address[6]; // Set internally
+ U16 interface_flags;
+ U8 clock_identity[8];
+ U8 priority1;
+ U8 clock_class;
+ S16 offset_scaled_log_variance;
+ U8 clock_accuracy;
+ U8 priority2;
+ U8 domain_number;
+ S8 log_sync_interval;
+ S8 log_announce_interval;
+ S8 log_pdelay_interval;
+ U16 port_number;
+} openavb_aem_descriptor_avb_interface_t;
+
+openavb_aem_descriptor_avb_interface_t *openavbAemDescriptorAvbInterfaceNew(void);
+
+bool openavbAemDescriptorAvbInterfaceInitialize(openavb_aem_descriptor_avb_interface_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig);
+
+#endif // OPENAVB_DESCRIPTOR_AVB_INTERFACE_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_clock_domain.c b/lib/avtp_pipeline/aem/openavb_descriptor_clock_domain.c
new file mode 100644
index 00000000..7f0e4018
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_clock_domain.c
@@ -0,0 +1,209 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Clock Domain Descriptor
+ * MODULE SUMMARY : Implements the AVDECC Clock Domain IEEE Std 1722.1-2013 clause 7.2.32
+ ******************************************************************
+ */
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_clock_domain.h"
+
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemDescriptorClockDomainToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_clock_domain_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_BASE_LENGTH + (pDescriptor->clock_sources_count * OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_CLOCK_SOURCE_LENGTH)) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_clock_domain_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->object_name);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.index, 0, 2);
+ OCT_D2BHTONS(pDst, pSrc->clock_source_index);
+ OCT_D2BHTONS(pDst, pSrc->clock_sources_offset);
+ OCT_D2BHTONS(pDst, pSrc->clock_sources_count);
+
+ int i1;
+ for (i1 = 0; i1 < pSrc->clock_sources_count; i1++) {
+ OCT_D2BHTONS(pDst, pSrc->clock_sources[i1]);
+ }
+
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorClockDomainFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_clock_domain_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_clock_domain_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DMEMCP(pDst->object_name, pSrc);
+ BIT_B2DNTOHS(pDst->localized_description.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->localized_description.index, pSrc, 0x0007, 0, 2);
+ OCT_B2DNTOHS(pDst->clock_source_index, pSrc);
+ OCT_B2DNTOHS(pDst->clock_sources_offset, pSrc);
+ OCT_B2DNTOHS(pDst->clock_sources_count, pSrc);
+
+ if (bufLength < OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_BASE_LENGTH + (pDescriptor->clock_sources_count * OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_CLOCK_SOURCE_LENGTH)) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ int i1;
+ for (i1 = 0; i1 < pDst->clock_sources_count; i1++) {
+ OCT_B2DNTOHS(pDst->clock_sources[i1], pSrc);
+ }
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorClockDomainUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_clock_domain_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_clock_domain_t *openavbAemDescriptorClockDomainNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_clock_domain_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_clock_domain_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = TRUE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorClockDomainToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorClockDomainFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorClockDomainUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_CLOCK_DOMAIN;
+ pDescriptor->clock_sources_offset = OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_BASE_LENGTH;
+
+ // Default to no localized strings.
+ pDescriptor->localized_description.offset = OPENAVB_AEM_NO_STRING_OFFSET;
+ pDescriptor->localized_description.index = OPENAVB_AEM_NO_STRING_INDEX;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorClockDomainInitialize(openavb_aem_descriptor_clock_domain_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig)
+{
+ int i;
+ openavb_aem_descriptor_clock_source_t *pClockSourceDescriptor;
+
+ if (!pDescriptor || !pConfig) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // Specify a name.
+ strcpy((char *)(pDescriptor->object_name), "Clock Domain");
+
+ // Add all the current clocks for this configuration to this domain.
+ for (i = 0; i < OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_MAX_CLOCK_SOURCES; ++i) {
+ pClockSourceDescriptor =
+ (openavb_aem_descriptor_clock_source_t *) openavbAemGetDescriptor(nConfigIdx, OPENAVB_AEM_DESCRIPTOR_CLOCK_SOURCE, i);
+ if (pClockSourceDescriptor == NULL) { break; }
+ pDescriptor->clock_sources[i] = pClockSourceDescriptor->descriptor_index;
+ pDescriptor->clock_sources_count = i + 1;
+ }
+
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_clock_domain.h b/lib/avtp_pipeline/aem/openavb_descriptor_clock_domain.h
new file mode 100644
index 00000000..7d30bd42
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_clock_domain.h
@@ -0,0 +1,47 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Clock Domain Descriptor
+ * MODULE SUMMARY : Interface for the Clock Domain Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_H
+#define OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_H 1
+
+#include "openavb_descriptor_clock_domain_pub.h"
+
+#define OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_BASE_LENGTH (76)
+#define OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_CLOCK_SOURCE_LENGTH (2)
+
+#endif // OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_clock_domain_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_clock_domain_pub.h
new file mode 100644
index 00000000..6458a41d
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_clock_domain_pub.h
@@ -0,0 +1,66 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Clock Domain Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the Clock Domain Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_PUB_H
+#define OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+
+#define OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_MAX_CLOCK_SOURCES (249)
+
+// CLOCK DOMAIN Descriptor IEEE Std 1722.1-2013 clause 7.2.32
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type; // Set internally
+ U16 descriptor_index; // Set internally
+ U8 object_name[OPENAVB_AEM_STRLEN_MAX];
+ openavb_aem_string_ref_t localized_description;
+ U16 clock_source_index;
+ U16 clock_sources_offset;
+ U16 clock_sources_count;
+ U16 clock_sources[OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_MAX_CLOCK_SOURCES];
+} openavb_aem_descriptor_clock_domain_t;
+
+openavb_aem_descriptor_clock_domain_t *openavbAemDescriptorClockDomainNew(void);
+
+bool openavbAemDescriptorClockDomainInitialize(openavb_aem_descriptor_clock_domain_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig);
+
+#endif // OPENAVB_DESCRIPTOR_CLOCK_DOMAIN_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_clock_source.c b/lib/avtp_pipeline/aem/openavb_descriptor_clock_source.c
new file mode 100644
index 00000000..3246607a
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_clock_source.c
@@ -0,0 +1,205 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Clock Source Descriptor
+ * MODULE SUMMARY : Implements the AVDECC Clock Source IEEE Std 1722.1-2013 clause 7.2.9
+ ******************************************************************
+ */
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_clock_source.h"
+
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemDescriptorClockSourceToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_clock_source_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_CLOCK_SOURCE_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_clock_source_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->object_name);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.index, 0, 2);
+ OCT_D2BHTONS(pDst, pSrc->clock_source_flags);
+ OCT_D2BHTONS(pDst, pSrc->clock_source_type);
+ OCT_D2BMEMCP(pDst, pSrc->clock_source_identifier);
+ OCT_D2BHTONS(pDst, pSrc->clock_source_location_type);
+ OCT_D2BHTONS(pDst, pSrc->clock_source_location_index);
+
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorClockSourceFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_clock_source_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_CLOCK_SOURCE_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_clock_source_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DMEMCP(pDst->object_name, pSrc);
+ BIT_B2DNTOHS(pDst->localized_description.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->localized_description.index, pSrc, 0x0007, 0, 2);
+ OCT_B2DNTOHS(pDst->clock_source_flags, pSrc);
+ OCT_B2DNTOHS(pDst->clock_source_type, pSrc);
+ OCT_B2DMEMCP(pDst->clock_source_identifier, pSrc);
+ OCT_B2DNTOHS(pDst->clock_source_location_type, pSrc);
+ OCT_B2DNTOHS(pDst->clock_source_location_index, pSrc);
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorClockSourceUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_clock_source_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_clock_source_t *openavbAemDescriptorClockSourceNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_clock_source_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_clock_source_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = TRUE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorClockSourceToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorClockSourceFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorClockSourceUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_CLOCK_SOURCE;
+
+ // Default to no localized strings.
+ pDescriptor->localized_description.offset = OPENAVB_AEM_NO_STRING_OFFSET;
+ pDescriptor->localized_description.index = OPENAVB_AEM_NO_STRING_INDEX;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorClockSourceInitialize(openavb_aem_descriptor_clock_source_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig)
+{
+ (void) nConfigIdx;
+ if (!pDescriptor || !pConfig) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO: These values need to be verified.
+ if (pConfig->stream->role == AVB_ROLE_TALKER)
+ {
+ // Make this an internal clock.
+ strcpy((char *) pDescriptor->object_name, "Internal Clock");
+ pDescriptor->clock_source_flags = 0;
+ pDescriptor->clock_source_type = OPENAVB_AEM_CLOCK_SOURCE_TYPE_INTERNAL;
+ pDescriptor->clock_source_location_type = OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT;
+ pDescriptor->clock_source_location_index = 0;
+ }
+ else if (pConfig->stream->role == AVB_ROLE_LISTENER)
+ {
+ // Use the Talker's clock.
+ strcpy((char *) pDescriptor->object_name, "Input Stream");
+ pDescriptor->clock_source_flags = OPENAVB_AEM_CLOCK_SOURCE_FLAG_STREAM_ID;
+ pDescriptor->clock_source_type = OPENAVB_AEM_CLOCK_SOURCE_TYPE_INPUT_STREAM;
+ memcpy(pDescriptor->clock_source_identifier, pConfig->stream->stream_addr.buffer.ether_addr_octet, ETH_ALEN);
+ pDescriptor->clock_source_location_type = OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT;
+ pDescriptor->clock_source_location_index = 0;
+ }
+
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_clock_source.h b/lib/avtp_pipeline/aem/openavb_descriptor_clock_source.h
new file mode 100644
index 00000000..29f9dd13
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_clock_source.h
@@ -0,0 +1,46 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Clock Source Descriptor
+ * MODULE SUMMARY : Interface for the Clock Source Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_CLOCK_SOURCE_H
+#define OPENAVB_DESCRIPTOR_CLOCK_SOURCE_H 1
+
+#include "openavb_descriptor_clock_source_pub.h"
+
+#define OPENAVB_DESCRIPTOR_CLOCK_SOURCE_BASE_LENGTH (86)
+
+#endif // OPENAVB_DESCRIPTOR_CLOCK_SOURCE_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_clock_source_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_clock_source_pub.h
new file mode 100644
index 00000000..10b2b723
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_clock_source_pub.h
@@ -0,0 +1,65 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Clock Source Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the Clock Source Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_CLOCK_SOURCE_PUB_H
+#define OPENAVB_DESCRIPTOR_CLOCK_SOURCE_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+
+// CLOCK SOURCE Descriptor IEEE Std 1722.1-2013 clause 7.2.9
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type; // Set internally
+ U16 descriptor_index; // Set internally
+ U8 object_name[OPENAVB_AEM_STRLEN_MAX];
+ openavb_aem_string_ref_t localized_description;
+ U16 clock_source_flags;
+ U16 clock_source_type;
+ U8 clock_source_identifier[8];
+ U16 clock_source_location_type;
+ U16 clock_source_location_index;
+} openavb_aem_descriptor_clock_source_t;
+
+openavb_aem_descriptor_clock_source_t *openavbAemDescriptorClockSourceNew(void);
+
+bool openavbAemDescriptorClockSourceInitialize(openavb_aem_descriptor_clock_source_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig);
+
+#endif // OPENAVB_DESCRIPTOR_CLOCK_SOURCE_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_configuration.c b/lib/avtp_pipeline/aem/openavb_descriptor_configuration.c
new file mode 100644
index 00000000..aaa442fa
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_configuration.c
@@ -0,0 +1,197 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Configuration Descriptor
+ * MODULE SUMMARY : Implements the AVDECC Configuration Descriptor IEEE Std 1722.1-2013 clause 7.2.1
+ ******************************************************************
+ */
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_configuration.h"
+
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemDescriptorConfigurationToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_configuration_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_CONFIGURATION_BASE_LENGTH + (pDescriptor->descriptor_counts_count * sizeof(*pDescriptor->descriptor_counts))) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_configuration_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->object_name);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.index, 0, 2);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_counts_count);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_counts_offset);
+
+ int i1;
+ for (i1 = 0; i1 < pSrc->descriptor_counts_count; i1++) {
+ OCT_D2BHTONS(pDst, pSrc->descriptor_counts[i1].descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_counts[i1].count);
+ }
+
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorConfigurationFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_configuration_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_CONFIGURATION_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_configuration_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DMEMCP(pDst->object_name, pSrc);
+ BIT_B2DNTOHS(pDst->localized_description.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->localized_description.index, pSrc, 0x0007, 0, 2);
+ OCT_B2DNTOHS(pDst->descriptor_counts_count, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_counts_offset, pSrc);
+
+ if (bufLength < OPENAVB_DESCRIPTOR_CONFIGURATION_BASE_LENGTH + (pDescriptor->descriptor_counts_count * sizeof(*pDescriptor->descriptor_counts))) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ int i1;
+ for (i1 = 0; i1 < pDst->descriptor_counts_count; i1++) {
+ OCT_B2DNTOHS(pDst->descriptor_counts[i1].descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_counts[i1].count, pSrc);
+ }
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorConfigurationUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_configuration_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_configuration_t *openavbAemDescriptorConfigurationNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_configuration_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_configuration_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = TRUE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorConfigurationToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorConfigurationFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorConfigurationUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_CONFIGURATION;
+ pDescriptor->descriptor_counts_offset = OPENAVB_DESCRIPTOR_CONFIGURATION_BASE_LENGTH;
+
+ // Default to no localized strings.
+ pDescriptor->localized_description.offset = OPENAVB_AEM_NO_STRING_OFFSET;
+ pDescriptor->localized_description.index = OPENAVB_AEM_NO_STRING_INDEX;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorConfigurationInitialize(openavb_aem_descriptor_configuration_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig)
+{
+ (void) nConfigIdx;
+ if (!pDescriptor || !pConfig) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ openavbAemSetString(pDescriptor->object_name, pConfig->friendly_name);
+
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_configuration.h b/lib/avtp_pipeline/aem/openavb_descriptor_configuration.h
new file mode 100644
index 00000000..1b804c4f
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_configuration.h
@@ -0,0 +1,46 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Configuration Descriptor
+ * MODULE SUMMARY : Interface for the Configuration Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_CONFIGURATION_H
+#define OPENAVB_DESCRIPTOR_CONFIGURATION_H 1
+
+#include "openavb_descriptor_configuration_pub.h"
+
+#define OPENAVB_DESCRIPTOR_CONFIGURATION_BASE_LENGTH (74)
+
+#endif // OPENAVB_DESCRIPTOR_CONFIGURATION_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_configuration_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_configuration_pub.h
new file mode 100644
index 00000000..2b6c71ff
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_configuration_pub.h
@@ -0,0 +1,70 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Entity Model : Configuration Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the Configuration Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_CONFIGURATION_PUB_H
+#define OPENAVB_DESCRIPTOR_CONFIGURATION_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+
+#define OPENAVB_DESCRIPTOR_CONFIGURATION_MAX_DESCRIPTOR_COUNTS (108)
+
+// CONFIGURATION Descriptor IEEE Std 1722.1-2013 clause 7.2.2
+typedef struct {
+ U16 descriptor_type;
+ U16 count;
+} openavb_aem_descriptor_configuration_descriptor_counts_t;
+
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type; // Set internally
+ U16 descriptor_index; // Set internally
+ U8 object_name[OPENAVB_AEM_STRLEN_MAX];
+ openavb_aem_string_ref_t localized_description;
+ U16 descriptor_counts_count; // Set internally
+ U16 descriptor_counts_offset; // Set internally
+ openavb_aem_descriptor_configuration_descriptor_counts_t descriptor_counts[OPENAVB_DESCRIPTOR_CONFIGURATION_MAX_DESCRIPTOR_COUNTS]; // Set internally
+} openavb_aem_descriptor_configuration_t;
+
+openavb_aem_descriptor_configuration_t *openavbAemDescriptorConfigurationNew(void);
+
+bool openavbAemDescriptorConfigurationInitialize(openavb_aem_descriptor_configuration_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig);
+
+#endif // OPENAVB_DESCRIPTOR_CONFIGURATION_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_control.c b/lib/avtp_pipeline/aem/openavb_descriptor_control.c
new file mode 100644
index 00000000..a432fe4c
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_control.c
@@ -0,0 +1,502 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Control Descriptor
+ * MODULE SUMMARY : Implements the AVDECC Control IEEE Std 1722.1-2013 clause 7.2.32
+ ******************************************************************
+ */
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_control.h"
+
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemDescriptorControlToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_control_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_CONTROL_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_control_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->object_name);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.index, 0, 2);
+ OCT_D2BHTONL(pDst, pSrc->block_latency);
+ OCT_D2BHTONL(pDst, pSrc->control_latency);
+ OCT_D2BHTONS(pDst, pSrc->control_domain);
+ OCT_D2BHTONS(pDst, pSrc->control_value_type);
+ OCT_D2BMEMCP(pDst, &pSrc->control_type);
+ OCT_D2BHTONL(pDst, pSrc->reset_time);
+ OCT_D2BHTONS(pDst, pSrc->values_offset);
+ OCT_D2BHTONS(pDst, pSrc->number_of_values);
+ OCT_D2BHTONS(pDst, pSrc->signal_type);
+ OCT_D2BHTONS(pDst, pSrc->signal_index);
+ OCT_D2BHTONS(pDst, pSrc->signal_output);
+
+ int i1;
+ for (i1 = 0; i1 < pSrc->number_of_values; i1++) {
+ switch (pSrc->control_value_type) {
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT8:
+ OCT_D2BHTONB(pDst, pSrc->value_details.linear_int8[i1].minimum);
+ OCT_D2BHTONB(pDst, pSrc->value_details.linear_int8[i1].maximum);
+ OCT_D2BHTONB(pDst, pSrc->value_details.linear_int8[i1].step);
+ OCT_D2BHTONB(pDst, pSrc->value_details.linear_int8[i1].default_value);
+ OCT_D2BHTONB(pDst, pSrc->value_details.linear_int8[i1].current);
+ OCT_D2BHTONS(pDst, pSrc->value_details.linear_int8[i1].unit);
+ BIT_D2BHTONS(pDst, pSrc->value_details.linear_int8[i1].string.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->value_details.linear_int8[i1].string.index, 0, 2);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT16:
+ OCT_D2BHTONS(pDst, pSrc->value_details.linear_int16[i1].minimum);
+ OCT_D2BHTONS(pDst, pSrc->value_details.linear_int16[i1].maximum);
+ OCT_D2BHTONS(pDst, pSrc->value_details.linear_int16[i1].step);
+ OCT_D2BHTONS(pDst, pSrc->value_details.linear_int16[i1].default_value);
+ OCT_D2BHTONS(pDst, pSrc->value_details.linear_int16[i1].current);
+ OCT_D2BHTONS(pDst, pSrc->value_details.linear_int16[i1].unit);
+ BIT_D2BHTONS(pDst, pSrc->value_details.linear_int16[i1].string.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->value_details.linear_int16[i1].string.index, 0, 2);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT32:
+ OCT_D2BHTONL(pDst, pSrc->value_details.linear_int32[i1].minimum);
+ OCT_D2BHTONL(pDst, pSrc->value_details.linear_int32[i1].maximum);
+ OCT_D2BHTONL(pDst, pSrc->value_details.linear_int32[i1].step);
+ OCT_D2BHTONL(pDst, pSrc->value_details.linear_int32[i1].default_value);
+ OCT_D2BHTONL(pDst, pSrc->value_details.linear_int32[i1].current);
+ OCT_D2BHTONL(pDst, pSrc->value_details.linear_int32[i1].unit);
+ BIT_D2BHTONS(pDst, pSrc->value_details.linear_int32[i1].string.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->value_details.linear_int32[i1].string.index, 0, 2);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT64:
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_int64[i1].minimum);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_int64[i1].maximum);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_int64[i1].step);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_int64[i1].default_value);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_int64[i1].current);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_int64[i1].unit);
+ BIT_D2BHTONS(pDst, pSrc->value_details.linear_int64[i1].string.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->value_details.linear_int64[i1].string.index, 0, 2);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_FLOAT:
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_float[i1].minimum);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_float[i1].maximum);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_float[i1].step);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_float[i1].default_value);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_float[i1].current);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_float[i1].unit);
+ BIT_D2BHTONS(pDst, pSrc->value_details.linear_float[i1].string.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->value_details.linear_float[i1].string.index, 0, 2);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_DOUBLE:
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_double[i1].minimum);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_double[i1].maximum);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_double[i1].step);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_double[i1].default_value);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_double[i1].current);
+ OCT_D2BMEMCP(pDst, &pSrc->value_details.linear_double[i1].unit);
+ BIT_D2BHTONS(pDst, pSrc->value_details.linear_double[i1].string.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->value_details.linear_double[i1].string.index, 0, 2);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT8:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT8:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT16:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT16:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT32:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT32:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT64:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT64:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_FLOAT:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_DOUBLE:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_STRING:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT8:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT8:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT16:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT16:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT32:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT32:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT64:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT64:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_FLOAT:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_DOUBLE:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_UTF8:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_BODE_PLOT:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SMPTE_TIME:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SAMPLE_RATE:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_GPTP_TIME:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_VENDOR:
+ // AVDECC_TODO
+ break;
+ }
+ }
+
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorControlFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_control_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_CONTROL_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_control_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DMEMCP(pDst->object_name, pSrc);
+ BIT_B2DNTOHS(pDst->localized_description.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->localized_description.index, pSrc, 0x0007, 0, 2);
+ OCT_B2DNTOHL(pDst->block_latency, pSrc);
+ OCT_B2DNTOHL(pDst->control_latency, pSrc);
+ OCT_B2DNTOHS(pDst->control_domain, pSrc);
+ OCT_B2DNTOHS(pDst->control_value_type, pSrc);
+ OCT_B2DMEMCP(&pDst->control_type, pSrc);
+ OCT_B2DNTOHL(pDst->reset_time, pSrc);
+ OCT_B2DNTOHS(pDst->values_offset, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_values, pSrc);
+ OCT_B2DNTOHS(pDst->signal_type, pSrc);
+ OCT_B2DNTOHS(pDst->signal_index, pSrc);
+ OCT_B2DNTOHS(pDst->signal_output, pSrc);
+
+
+ int i1;
+ for (i1 = 0; i1 < pDst->number_of_values; i1++) {
+ switch (pDst->control_value_type) {
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT8:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT8:
+ OCT_B2DNTOHB(pDst->value_details.linear_int8[i1].minimum, pSrc);
+ OCT_B2DNTOHB(pDst->value_details.linear_int8[i1].maximum, pSrc);
+ OCT_B2DNTOHB(pDst->value_details.linear_int8[i1].step, pSrc);
+ OCT_B2DNTOHB(pDst->value_details.linear_int8[i1].default_value, pSrc);
+ OCT_B2DNTOHB(pDst->value_details.linear_int8[i1].current, pSrc);
+ OCT_B2DNTOHB(pDst->value_details.linear_int8[i1].unit, pSrc);
+ BIT_B2DNTOHS(pDst->value_details.linear_int8[i1].string.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->value_details.linear_int8[i1].string.index, pSrc, 0x0007, 0, 2);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT16:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT16:
+ OCT_B2DNTOHS(pDst->value_details.linear_int16[i1].minimum, pSrc);
+ OCT_B2DNTOHS(pDst->value_details.linear_int16[i1].maximum, pSrc);
+ OCT_B2DNTOHS(pDst->value_details.linear_int16[i1].step, pSrc);
+ OCT_B2DNTOHS(pDst->value_details.linear_int16[i1].default_value, pSrc);
+ OCT_B2DNTOHS(pDst->value_details.linear_int16[i1].current, pSrc);
+ OCT_B2DNTOHS(pDst->value_details.linear_int16[i1].unit, pSrc);
+ BIT_B2DNTOHS(pDst->value_details.linear_int16[i1].string.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->value_details.linear_int16[i1].string.index, pSrc, 0x0007, 0, 2);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT32:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT32:
+ OCT_B2DNTOHL(pDst->value_details.linear_int32[i1].minimum, pSrc);
+ OCT_B2DNTOHL(pDst->value_details.linear_int32[i1].maximum, pSrc);
+ OCT_B2DNTOHL(pDst->value_details.linear_int32[i1].step, pSrc);
+ OCT_B2DNTOHL(pDst->value_details.linear_int32[i1].default_value, pSrc);
+ OCT_B2DNTOHL(pDst->value_details.linear_int32[i1].current, pSrc);
+ OCT_B2DNTOHL(pDst->value_details.linear_int32[i1].unit, pSrc);
+ BIT_B2DNTOHS(pDst->value_details.linear_int32[i1].string.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->value_details.linear_int32[i1].string.index, pSrc, 0x0007, 0, 2);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_INT64:
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_UINT64:
+ OCT_B2DMEMCP(&pDst->value_details.linear_int64[i1].minimum, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_int64[i1].maximum, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_int64[i1].step, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_int64[i1].default_value, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_int64[i1].current, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_int64[i1].unit, pSrc);
+ BIT_B2DNTOHS(pDst->value_details.linear_int64[i1].string.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->value_details.linear_int64[i1].string.index, pSrc, 0x0007, 0, 2);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_FLOAT:
+ OCT_B2DMEMCP(&pDst->value_details.linear_float[i1].minimum, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_float[i1].maximum, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_float[i1].step, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_float[i1].default_value, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_float[i1].current, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_float[i1].unit, pSrc);
+ BIT_B2DNTOHS(pDst->value_details.linear_float[i1].string.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->value_details.linear_float[i1].string.index, pSrc, 0x0007, 0, 2);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_LINEAR_DOUBLE:
+ OCT_B2DMEMCP(&pDst->value_details.linear_double[i1].minimum, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_double[i1].maximum, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_double[i1].step, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_double[i1].default_value, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_double[i1].current, pSrc);
+ OCT_B2DMEMCP(&pDst->value_details.linear_double[i1].unit, pSrc);
+ BIT_B2DNTOHS(pDst->value_details.linear_double[i1].string.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->value_details.linear_double[i1].string.index, pSrc, 0x0007, 0, 2);
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT8:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT8:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT16:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT16:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT32:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT32:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_INT64:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_UINT64:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_FLOAT:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_DOUBLE:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SELECTOR_STRING:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT8:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT8:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT16:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT16:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT32:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT32:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_INT64:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_UINT64:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_FLOAT:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_ARRAY_DOUBLE:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_UTF8:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_BODE_PLOT:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SMPTE_TIME:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_SAMPLE_RATE:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_GPTP_TIME:
+ // AVDECC_TODO
+ break;
+ case OPENAVB_AEM_CONTROL_VALUE_TYPE_CONTROL_VENDOR:
+ // AVDECC_TODO
+ break;
+ }
+ }
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorControlUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_control_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_control_t *openavbAemDescriptorControlNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_control_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_control_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = TRUE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorControlToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorControlFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorControlUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_CONTROL;
+ pDescriptor->values_offset = OPENAVB_DESCRIPTOR_CONTROL_BASE_LENGTH;
+
+ // Default to no localized strings.
+ pDescriptor->localized_description.offset = OPENAVB_AEM_NO_STRING_OFFSET;
+ pDescriptor->localized_description.index = OPENAVB_AEM_NO_STRING_INDEX;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorDescriptorControlInitialize(openavb_aem_descriptor_control_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig)
+{
+ (void) nConfigIdx;
+ if (!pDescriptor || !pConfig) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_control.h b/lib/avtp_pipeline/aem/openavb_descriptor_control.h
new file mode 100644
index 00000000..6635e248
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_control.h
@@ -0,0 +1,46 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Control Descriptor
+ * MODULE SUMMARY : Interface for the Control Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_CONTROL_H
+#define OPENAVB_DESCRIPTOR_CONTROL_H 1
+
+#include "openavb_descriptor_control_pub.h"
+
+#define OPENAVB_DESCRIPTOR_CONTROL_BASE_LENGTH (104)
+
+#endif // OPENAVB_DESCRIPTOR_CONTROL_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_control_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_control_pub.h
new file mode 100644
index 00000000..e0a6a0f4
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_control_pub.h
@@ -0,0 +1,111 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Control Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the Control Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_CONTROL_PUB_H
+#define OPENAVB_DESCRIPTOR_CONTROL_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+
+// CONTROL Descriptor IEEE Std 1722.1-2013 clause 7.2.22
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type; // Set internally
+ U16 descriptor_index; // Set internally
+ U8 object_name[OPENAVB_AEM_STRLEN_MAX];
+ openavb_aem_string_ref_t localized_description;
+ U32 block_latency;
+ U32 control_latency;
+ U16 control_domain;
+ U16 control_value_type;
+ U64 control_type;
+ U32 reset_time;
+ U16 values_offset;
+ U16 number_of_values;
+ U16 signal_type;
+ U16 signal_index;
+ U16 signal_output;
+ union {
+ openavb_aem_control_value_format_control_linear_int8_t linear_int8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT8];
+ openavb_aem_control_value_format_control_linear_uint8_t linear_uint8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT8];
+ openavb_aem_control_value_format_control_linear_int16_t linear_int16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT16];
+ openavb_aem_control_value_format_control_linear_uint16_t linear_uint16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT16];
+ openavb_aem_control_value_format_control_linear_int32_t linear_int32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT32];
+ openavb_aem_control_value_format_control_linear_uint32_t linear_uint32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT32];
+ openavb_aem_control_value_format_control_linear_int64_t linear_int64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_INT64];
+ openavb_aem_control_value_format_control_linear_uint64_t linear_uint64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_UINT64];
+ openavb_aem_control_value_format_control_linear_float_t linear_float[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_FLOAT];
+ openavb_aem_control_value_format_control_linear_double_t linear_double[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_LINEAR_DOUBLE];
+ openavb_aem_control_value_format_control_selector_int8_t selector_int8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT8];
+ openavb_aem_control_value_format_control_selector_uint8_t selector_uint8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT8];
+ openavb_aem_control_value_format_control_selector_int16_t selector_int16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT16];
+ openavb_aem_control_value_format_control_selector_uint16_t selector_uint16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT16];
+ openavb_aem_control_value_format_control_selector_int32_t selector_int32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT32];
+ openavb_aem_control_value_format_control_selector_uint32_t selector_uint32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT32];
+ openavb_aem_control_value_format_control_selector_int64_t selector_int64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_INT64];
+ openavb_aem_control_value_format_control_selector_uint64_t selector_uint64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_UINT64];
+ openavb_aem_control_value_format_control_selector_float_t selector_float[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_FLOAT];
+ openavb_aem_control_value_format_control_selector_double_t selector_double[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_DOUBLE];
+ openavb_aem_control_value_format_control_selector_string_t selector_string[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SELECTOR_STRING];
+ openavb_aem_control_value_format_control_array_int8_t array_int8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT8];
+ openavb_aem_control_value_format_control_array_uint8_t array_uint8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT8];
+ openavb_aem_control_value_format_control_array_int16_t array_int16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT16];
+ openavb_aem_control_value_format_control_array_uint16_t array_uint16[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT16];
+ openavb_aem_control_value_format_control_array_int32_t array_int32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT32];
+ openavb_aem_control_value_format_control_array_uint32_t array_uint32[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT32];
+ openavb_aem_control_value_format_control_array_int64_t array_int64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_INT64];
+ openavb_aem_control_value_format_control_array_uint64_t array_uint64[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_UINT64];
+ openavb_aem_control_value_format_control_array_float_t array_float[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_FLOAT];
+ openavb_aem_control_value_format_control_array_double_t array_double[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_ARRAY_DOUBLE];
+ openavb_aem_control_value_format_control_utf8_t utf8[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_UTF8];
+ openavb_aem_control_value_format_control_bode_plot_t bode_plot[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_BODE_PLOT];
+ openavb_aem_control_value_format_control_smpte_time_t smpte_time[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SMPTE_TIME];
+ openavb_aem_control_value_format_control_sample_rate_t sample_rate[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_SAMPLE_RATE];
+ openavb_aem_control_value_format_control_gptp_time_t gptp_time[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_GPTP_TIME];
+ openavb_aem_control_value_format_control_vendor_t vendor[OPENAVB_AEM_VALUE_MAX_COUNT_CONTROL_VENDOR];
+ } value_details;
+} openavb_aem_descriptor_control_t;
+
+
+openavb_aem_descriptor_control_t *openavbAemDescriptorControlNew(void);
+
+bool openavbAemDescriptorDescriptorControlInitialize(openavb_aem_descriptor_control_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig);
+
+#endif // OPENAVB_DESCRIPTOR_CONTROL_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_entity.c b/lib/avtp_pipeline/aem/openavb_descriptor_entity.c
new file mode 100644
index 00000000..6e0e4666
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_entity.c
@@ -0,0 +1,411 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Entity Descriptor
+ * MODULE SUMMARY : Implements the AVDECC Entity Descriptor IEEE Std 1722.1-2013 clause 7.2.1
+ ******************************************************************
+ */
+
+#include "openavb_platform.h"
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_entity.h"
+
+extern openavb_avdecc_cfg_t gAvdeccCfg;
+
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemDescriptorEntityToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_entity_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_ENTITY_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_entity_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->entity_id);
+ OCT_D2BMEMCP(pDst, pSrc->entity_model_id);
+ OCT_D2BHTONL(pDst, pSrc->entity_capabilities);
+ OCT_D2BHTONS(pDst, pSrc->talker_stream_sources);
+ OCT_D2BHTONS(pDst, pSrc->talker_capabilities);
+ OCT_D2BHTONS(pDst, pSrc->listener_stream_sinks);
+ OCT_D2BHTONS(pDst, pSrc->listener_capabilities);
+ OCT_D2BHTONL(pDst, pSrc->controller_capabilities);
+ OCT_D2BHTONL(pDst, pSrc->available_index);
+ OCT_D2BMEMCP(pDst, pSrc->association_id);
+ OCT_D2BMEMCP(pDst, pSrc->entity_name);
+ BIT_D2BHTONS(pDst, pSrc->vendor_name_string.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->vendor_name_string.index, 0, 2);
+ BIT_D2BHTONS(pDst, pSrc->model_name_string.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->model_name_string.index, 0, 2);
+ OCT_D2BMEMCP(pDst, pSrc->firmware_version);
+ OCT_D2BMEMCP(pDst, pSrc->group_name);
+ OCT_D2BMEMCP(pDst, pSrc->serial_number);
+ OCT_D2BHTONS(pDst, pSrc->configurations_count);
+ OCT_D2BHTONS(pDst, pSrc->current_configuration);
+
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorEntityFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_entity_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_ENTITY_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_entity_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DMEMCP(pDst->entity_id, pSrc);
+ OCT_B2DMEMCP(pDst->entity_model_id, pSrc);
+ OCT_B2DNTOHL(pDst->entity_capabilities, pSrc);
+ OCT_B2DNTOHS(pDst->talker_stream_sources, pSrc);
+ OCT_B2DNTOHS(pDst->talker_capabilities, pSrc);
+ OCT_B2DNTOHS(pDst->listener_stream_sinks, pSrc);
+ OCT_B2DNTOHS(pDst->listener_capabilities, pSrc);
+ OCT_B2DNTOHL(pDst->controller_capabilities, pSrc);
+ OCT_B2DNTOHL(pDst->available_index, pSrc);
+ OCT_B2DMEMCP(pDst->association_id, pSrc);
+ OCT_B2DMEMCP(pDst->entity_name, pSrc);
+ BIT_B2DNTOHS(pDst->vendor_name_string.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->vendor_name_string.index, pSrc, 0x0007, 0, 2);
+ BIT_B2DNTOHS(pDst->model_name_string.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->model_name_string.index, pSrc, 0x0007, 0, 2);
+ OCT_B2DMEMCP(pDst->firmware_version, pSrc);
+ OCT_B2DMEMCP(pDst->group_name, pSrc);
+ OCT_B2DMEMCP(pDst->serial_number, pSrc);
+ OCT_B2DNTOHS(pDst->configurations_count, pSrc);
+ OCT_B2DNTOHS(pDst->current_configuration, pSrc);
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorEntityUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_entity_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_entity_t *openavbAemDescriptorEntityNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_entity_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(openavb_aem_descriptor_entity_t));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor->descriptorPvtPtr, 0, sizeof(*pDescriptor->descriptorPvtPtr));
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_entity_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = TRUE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorEntityToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorEntityFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorEntityUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_ENTITY;
+ pDescriptor->descriptor_index = 0;
+
+ // Default to no localized strings.
+ pDescriptor->vendor_name_string.offset = OPENAVB_AEM_NO_STRING_OFFSET;
+ pDescriptor->vendor_name_string.index = OPENAVB_AEM_NO_STRING_INDEX;
+ pDescriptor->model_name_string.offset = OPENAVB_AEM_NO_STRING_OFFSET;
+ pDescriptor->model_name_string.index = OPENAVB_AEM_NO_STRING_INDEX;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorEntitySet_entity_id(openavb_aem_descriptor_entity_t *pDescriptor, char *aMacAddr, U8 *nMacAddr, U16 id)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ struct ether_addr macAddrBuffer;
+ if (aMacAddr) {
+ // If an ascii mac address is passed in parse and use it.
+ memset(macAddrBuffer.ether_addr_octet, 0, sizeof(macAddrBuffer));
+
+ if (!ether_aton_r(aMacAddr, &macAddrBuffer)) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_PARSING_MAC_ADDRESS));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+ memcpy(pDescriptor->entity_id, macAddrBuffer.ether_addr_octet, 3);
+ memcpy(pDescriptor->entity_id + 3 + 2, macAddrBuffer.ether_addr_octet + 3, 3);
+ }
+ else if (nMacAddr) {
+ // If a network mac address is passed in use it.
+ memcpy(pDescriptor->entity_id, nMacAddr, 3);
+ memcpy(pDescriptor->entity_id + 3 + 2, nMacAddr + 3, 3);
+ }
+ else {
+ // If no mac address is passed in obtain it from the stack.
+ memcpy(pDescriptor->entity_id, gAvdeccCfg.ifmac, 3);
+ memcpy(pDescriptor->entity_id + 3 + 2, gAvdeccCfg.ifmac + 3, 3);
+ }
+
+ U16 tmpU16 = htons(id);
+ memcpy(pDescriptor->entity_id + 3, &tmpU16, sizeof(tmpU16));
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorEntitySet_entity_model_id(openavb_aem_descriptor_entity_t *pDescriptor, U8 pData[8])
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor || !pData) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ memcpy(pDescriptor->entity_model_id, pData, 8);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorEntitySet_entity_capabilities(openavb_aem_descriptor_entity_t *pDescriptor, U32 capabilities)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ pDescriptor->entity_capabilities = capabilities;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorEntitySet_talker_capabilities(openavb_aem_descriptor_entity_t *pDescriptor, U16 num_sources, U16 capabilities)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ pDescriptor->talker_stream_sources = num_sources;
+ pDescriptor->talker_capabilities = capabilities;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorEntitySet_listener_capabilities(openavb_aem_descriptor_entity_t *pDescriptor, U16 num_sinks, U16 capabilities)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ pDescriptor->listener_stream_sinks = num_sinks;
+ pDescriptor->listener_capabilities = capabilities;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorEntitySet_entity_name(openavb_aem_descriptor_entity_t *pDescriptor, char *aName)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor || !aName) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ openavbAemSetString(pDescriptor->entity_name, aName);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorEntitySet_vendor_name(openavb_aem_descriptor_entity_t *pDescriptor, U16 nOffset, U8 nIndex)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ pDescriptor->vendor_name_string.offset = nOffset;
+ pDescriptor->vendor_name_string.index = nIndex;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorEntitySet_model_name(openavb_aem_descriptor_entity_t *pDescriptor, U16 nOffset, U8 nIndex)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ pDescriptor->model_name_string.offset = nOffset;
+ pDescriptor->model_name_string.index = nIndex;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorEntitySet_firmware_version(openavb_aem_descriptor_entity_t *pDescriptor, char *aFirmwareVersion)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor || !aFirmwareVersion) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ openavbAemSetString(pDescriptor->firmware_version, aFirmwareVersion);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorEntitySet_group_name(openavb_aem_descriptor_entity_t *pDescriptor, char *aGroupName)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor || !aGroupName) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ openavbAemSetString(pDescriptor->group_name, aGroupName);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorEntitySet_serial_number(openavb_aem_descriptor_entity_t *pDescriptor, char *aSerialNumber)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor || !aSerialNumber) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ openavbAemSetString(pDescriptor->serial_number, aSerialNumber);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_entity.h b/lib/avtp_pipeline/aem/openavb_descriptor_entity.h
new file mode 100644
index 00000000..7e8ade4f
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_entity.h
@@ -0,0 +1,46 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Entity Model : Entity Descriptor
+ * MODULE SUMMARY : Interface for the Entity Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_ENTITY_H
+#define OPENAVB_DESCRIPTOR_ENTITY_H 1
+
+#include "openavb_descriptor_entity_pub.h"
+
+#define OPENAVB_DESCRIPTOR_ENTITY_BASE_LENGTH 312
+
+#endif // OPENAVB_DESCRIPTOR_ENTITY_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_entity_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_entity_pub.h
new file mode 100644
index 00000000..00875ae3
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_entity_pub.h
@@ -0,0 +1,108 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Entity Model : Entity Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the Entity Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_ENTITY_PUB_H
+#define OPENAVB_DESCRIPTOR_ENTITY_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+
+// ENTITY Descriptor IEEE Std 1722.1-2013 clause 7.2.1
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type; // Set internally
+ U16 descriptor_index; // Set internally
+ U8 entity_id[8];
+ U8 entity_model_id[8];
+ U32 entity_capabilities;
+ U16 talker_stream_sources;
+ U16 talker_capabilities;
+ U16 listener_stream_sinks;
+ U16 listener_capabilities;
+ U32 controller_capabilities;
+ U32 available_index;
+ U8 association_id[8];
+ U8 entity_name[OPENAVB_AEM_STRLEN_MAX];
+ openavb_aem_string_ref_t vendor_name_string;
+ openavb_aem_string_ref_t model_name_string;
+ U8 firmware_version[OPENAVB_AEM_STRLEN_MAX];
+ U8 group_name[OPENAVB_AEM_STRLEN_MAX];
+ U8 serial_number[OPENAVB_AEM_STRLEN_MAX];
+ U16 configurations_count; // Set internally
+ U16 current_configuration; // Set internally
+} openavb_aem_descriptor_entity_t;
+
+// Create a new Entity Descriptor
+openavb_aem_descriptor_entity_t *openavbAemDescriptorEntityNew(void);
+
+// Set the Entity ID using the common approach of mac address and an ID. Either pass in aMacAddr (ascii) or nMacAddr (network)
+bool openavbAemDescriptorEntitySet_entity_id(openavb_aem_descriptor_entity_t *pDescriptor, char *aMacAddr, U8 *nMacAddr, U16 id);
+
+// Set the Entity Model ID. Pass in a pointer to an array of 8 bytes of arbitrary data.
+bool openavbAemDescriptorEntitySet_entity_model_id(openavb_aem_descriptor_entity_t *pDescriptor, U8 pData[8]);
+
+// Set the Entity Capabilities. Use the OPENAVB_ADP_ENTITY_CAPABILITIES_... flags from adp/openavb_adp_pub.h.
+bool openavbAemDescriptorEntitySet_entity_capabilities(openavb_aem_descriptor_entity_t *pDescriptor, U32 capabilities);
+
+// Set the Talker Capabilities. Use the OPENAVB_ADP_TALKER_CAPABILITIES_... flags from adp/openavb_adp_pub.h.
+bool openavbAemDescriptorEntitySet_talker_capabilities(openavb_aem_descriptor_entity_t *pDescriptor, U16 num_sources, U16 capabilities);
+
+// Set the Listener Capabilities. Use the OPENAVB_ADP_LISTENER_CAPABILITIES_... flags from adp/openavb_adp_pub.h.
+bool openavbAemDescriptorEntitySet_listener_capabilities(openavb_aem_descriptor_entity_t *pDescriptor, U16 num_sinks, U16 capabilities);
+
+// Set the Entity Name.
+bool openavbAemDescriptorEntitySet_entity_name(openavb_aem_descriptor_entity_t *pDescriptor, char *aName);
+
+// Set the Vendor Name.
+bool openavbAemDescriptorEntitySet_vendor_name(openavb_aem_descriptor_entity_t *pDescriptor, U16 nOffset, U8 nIndex);
+
+// Set the Model Name.
+bool openavbAemDescriptorEntitySet_model_name(openavb_aem_descriptor_entity_t *pDescriptor, U16 nOffset, U8 nIndex);
+
+// Set the Firmware Version.
+bool openavbAemDescriptorEntitySet_firmware_version(openavb_aem_descriptor_entity_t *pDescriptor, char *aFirmwareVersion);
+
+// Set the Group Name.
+bool openavbAemDescriptorEntitySet_group_name(openavb_aem_descriptor_entity_t *pDescriptor, char *aGroupName);
+
+// Set the Serial Number.
+bool openavbAemDescriptorEntitySet_serial_number(openavb_aem_descriptor_entity_t *pDescriptor, char *aSerialNumber);
+
+#endif // OPENAVB_DESCRIPTOR_ENTITY_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_external_port_io.c b/lib/avtp_pipeline/aem/openavb_descriptor_external_port_io.c
new file mode 100644
index 00000000..615e800c
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_external_port_io.c
@@ -0,0 +1,209 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC External Port IO Descriptor
+ * MODULE SUMMARY : Implements the AVDECC External Port IO IEEE Std 1722.1-2013 clause 7.2.14
+ ******************************************************************
+ */
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_external_port_io.h"
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemDescriptorExternalPortIOToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_external_port_io_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_EXTERNAL_PORT_IO_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_external_port_io_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BHTONS(pDst, pSrc->clock_domain_index);
+ OCT_D2BHTONS(pDst, pSrc->port_flags);
+ OCT_D2BHTONS(pDst, pSrc->number_of_controls);
+ OCT_D2BHTONS(pDst, pSrc->base_control);
+ OCT_D2BHTONS(pDst, pSrc->signal_type);
+ OCT_D2BHTONS(pDst, pSrc->signal_index);
+ OCT_D2BHTONS(pDst, pSrc->signal_output);
+ OCT_D2BHTONL(pDst, pSrc->block_latency);
+ OCT_D2BHTONS(pDst, pSrc->jack_index);
+
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorExternalPortIOFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_external_port_io_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_EXTERNAL_PORT_IO_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_external_port_io_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DNTOHS(pDst->clock_domain_index, pSrc);
+ OCT_B2DNTOHS(pDst->port_flags, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_controls, pSrc);
+ OCT_B2DNTOHS(pDst->base_control, pSrc);
+ OCT_B2DNTOHS(pDst->signal_type, pSrc);
+ OCT_B2DNTOHS(pDst->signal_index, pSrc);
+ OCT_B2DNTOHS(pDst->signal_output, pSrc);
+ OCT_B2DNTOHL(pDst->block_latency, pSrc);
+ OCT_B2DNTOHS(pDst->jack_index, pSrc);
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorExternalPortIOUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_external_port_io_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_external_port_io_t *openavbAemDescriptorExternalPortInputNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_external_port_io_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_external_port_io_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = FALSE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorExternalPortIOToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorExternalPortIOFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorExternalPortIOUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_STREAM_PORT_INPUT;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT openavb_aem_descriptor_external_port_io_t *openavbAemDescriptorExternalPortOutputNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_external_port_io_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_external_port_io_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = FALSE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorExternalPortIOToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorExternalPortIOFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorExternalPortIOUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_STREAM_PORT_OUTPUT;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_external_port_io.h b/lib/avtp_pipeline/aem/openavb_descriptor_external_port_io.h
new file mode 100644
index 00000000..3336d581
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_external_port_io.h
@@ -0,0 +1,46 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC External Port IO Descriptor
+ * MODULE SUMMARY : Interface for the External Port IO Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_EXTERNAL_PORT_IO_H
+#define OPENAVB_DESCRIPTOR_EXTERNAL_PORT_IO_H 1
+
+#include "openavb_descriptor_external_port_io_pub.h"
+
+#define OPENAVB_DESCRIPTOR_EXTERNAL_PORT_IO_BASE_LENGTH 24
+
+#endif // OPENAVB_DESCRIPTOR_EXTERNAL_PORT_IO_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_external_port_io_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_external_port_io_pub.h
new file mode 100644
index 00000000..7f7522cb
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_external_port_io_pub.h
@@ -0,0 +1,66 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC External Port IO Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the External Port IO Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_EXTERNAL_PORT_IO_PUB_H
+#define OPENAVB_DESCRIPTOR_EXTERNAL_PORT_IO_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+
+// EXTERNAL PORT IO Descriptor IEEE Std 1722.1-2013 clause 7.2.14
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type;
+ U16 descriptor_index;
+ U16 clock_domain_index;
+ U16 port_flags;
+ U16 number_of_controls;
+ U16 base_control;
+ U16 signal_type;
+ U16 signal_index;
+ U16 signal_output;
+ U32 block_latency;
+ U16 jack_index;
+} openavb_aem_descriptor_external_port_io_t;
+
+openavb_aem_descriptor_external_port_io_t *openavbAemDescriptorExternalPortInputNew(void);
+openavb_aem_descriptor_external_port_io_t *openavbAemDescriptorExternalPortOutputNew(void);
+
+#endif // OPENAVB_DESCRIPTOR_EXTERNAL_PORT_IO_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_jack_io.c b/lib/avtp_pipeline/aem/openavb_descriptor_jack_io.c
new file mode 100644
index 00000000..5813b03b
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_jack_io.c
@@ -0,0 +1,235 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Jack IO Descriptor
+ * MODULE SUMMARY : Implements the AVDECC Jack IO IEEE Std 1722.1-2013 clause 7.2.7
+ ******************************************************************
+ */
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_jack_io.h"
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemDescriptorJackIOToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_jack_io_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_JACK_IO_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_jack_io_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->object_name);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.index, 0, 2);
+ OCT_D2BHTONS(pDst, pSrc->jack_flags);
+ OCT_D2BHTONS(pDst, pSrc->jack_type);
+ OCT_D2BHTONS(pDst, pSrc->number_of_controls);
+ OCT_D2BHTONS(pDst, pSrc->base_control);
+
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorJackIOFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_jack_io_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_JACK_IO_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_jack_io_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DMEMCP(pDst->object_name, pSrc);
+ BIT_B2DNTOHS(pDst->localized_description.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->localized_description.index, pSrc, 0x0007, 0, 2);
+ OCT_B2DNTOHS(pDst->jack_flags, pSrc);
+ OCT_B2DNTOHS(pDst->jack_type, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_controls, pSrc);
+ OCT_B2DNTOHS(pDst->base_control, pSrc);
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorJackIOUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_jack_io_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_jack_io_t *openavbAemDescriptorJackInputNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_jack_io_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_jack_io_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = TRUE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorJackIOToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorJackIOFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorJackIOUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_JACK_INPUT;
+
+ // Default to no localized strings.
+ pDescriptor->localized_description.offset = OPENAVB_AEM_NO_STRING_OFFSET;
+ pDescriptor->localized_description.index = OPENAVB_AEM_NO_STRING_INDEX;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT openavb_aem_descriptor_jack_io_t *openavbAemDescriptorJackOutputNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_jack_io_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_jack_io_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = TRUE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorJackIOToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorJackIOFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorJackIOUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_JACK_OUTPUT;
+
+ // Default to no localized strings.
+ pDescriptor->localized_description.offset = OPENAVB_AEM_NO_STRING_OFFSET;
+ pDescriptor->localized_description.index = OPENAVB_AEM_NO_STRING_INDEX;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorJackInputInitialize(openavb_aem_descriptor_jack_io_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig)
+{
+ (void) nConfigIdx;
+ if (!pDescriptor || !pConfig) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ return TRUE;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorJackOutputInitialize(openavb_aem_descriptor_jack_io_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig)
+{
+ (void) nConfigIdx;
+ if (!pDescriptor || !pConfig) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_jack_io.h b/lib/avtp_pipeline/aem/openavb_descriptor_jack_io.h
new file mode 100644
index 00000000..0a747c2a
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_jack_io.h
@@ -0,0 +1,46 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Jack IO Descriptor
+ * MODULE SUMMARY : Interface for the Jack IO Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_JACK_IO_H
+#define OPENAVB_DESCRIPTOR_JACK_IO_H 1
+
+#include "openavb_descriptor_jack_io_pub.h"
+
+#define OPENAVB_DESCRIPTOR_JACK_IO_BASE_LENGTH 78
+
+#endif // OPENAVB_DESCRIPTOR_JACK_IO_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_jack_io_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_jack_io_pub.h
new file mode 100644
index 00000000..a2bf65b4
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_jack_io_pub.h
@@ -0,0 +1,66 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Jack IO Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the Jack IO Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_JACK_IO_PUB_H
+#define OPENAVB_DESCRIPTOR_JACK_IO_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+
+// JACK IO Descriptor IEEE Std 1722.1-2013 clause 7.2.7
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type;
+ U16 descriptor_index;
+ U8 object_name[OPENAVB_AEM_STRLEN_MAX];
+ openavb_aem_string_ref_t localized_description;
+ U16 jack_flags;
+ U16 jack_type;
+ U16 number_of_controls;
+ U16 base_control;
+} openavb_aem_descriptor_jack_io_t;
+
+openavb_aem_descriptor_jack_io_t *openavbAemDescriptorJackInputNew(void);
+openavb_aem_descriptor_jack_io_t *openavbAemDescriptorJackOutputNew(void);
+
+bool openavbAemDescriptorJackInputInitialize(openavb_aem_descriptor_jack_io_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig);
+bool openavbAemDescriptorJackOutputInitialize(openavb_aem_descriptor_jack_io_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig);
+
+#endif // OPENAVB_DESCRIPTOR_JACK_IO_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_locale.c b/lib/avtp_pipeline/aem/openavb_descriptor_locale.c
new file mode 100644
index 00000000..4f486d0d
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_locale.c
@@ -0,0 +1,208 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Locale Descriptor
+ * MODULE SUMMARY : Implements the AVDECC Locale IEEE Std 1722.1-2013 clause 7.2.11
+ ******************************************************************
+ */
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_locale.h"
+
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemDescriptorLocaleToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_locale_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_LOCALE_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_locale_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->locale_identifier);
+ OCT_D2BHTONS(pDst, pSrc->number_of_strings);
+ OCT_D2BHTONS(pDst, pSrc->base_strings);
+
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorLocaleFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_locale_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_LOCALE_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_locale_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DMEMCP(pDst->locale_identifier, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_strings, pSrc);
+ OCT_B2DNTOHS(pDst->base_strings, pSrc);
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorLocaleUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_locale_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_locale_t *openavbAemDescriptorLocaleNew(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_locale_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_locale_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = TRUE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorLocaleToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorLocaleFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorLocaleUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_LOCALE;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorLocaleSet_locale_identifier(openavb_aem_descriptor_locale_t *pDescriptor, const char *aLocaleIdentifier)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor || !aLocaleIdentifier) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ openavbAemSetString(pDescriptor->locale_identifier, aLocaleIdentifier);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorLocaleSet_number_of_strings(openavb_aem_descriptor_locale_t *pDescriptor, U16 uNumberOfStrings)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ pDescriptor->number_of_strings = uNumberOfStrings;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorLocaleSet_base_strings(openavb_aem_descriptor_locale_t *pDescriptor, U16 uBaseStrings)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ pDescriptor->base_strings = uBaseStrings;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_locale.h b/lib/avtp_pipeline/aem/openavb_descriptor_locale.h
new file mode 100644
index 00000000..f5e0ffe3
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_locale.h
@@ -0,0 +1,46 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Locale Descriptor
+ * MODULE SUMMARY : Interface for the Locale Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_LOCALE_H
+#define OPENAVB_DESCRIPTOR_LOCALE_H 1
+
+#include "openavb_descriptor_locale_pub.h"
+
+#define OPENAVB_DESCRIPTOR_LOCALE_BASE_LENGTH 72
+
+#endif // OPENAVB_DESCRIPTOR_LOCALE_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_locale_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_locale_pub.h
new file mode 100644
index 00000000..aba0e01a
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_locale_pub.h
@@ -0,0 +1,69 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Locale Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the Locale Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_LOCALE_PUB_H
+#define OPENAVB_DESCRIPTOR_LOCALE_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+
+// LOCALE Descriptor IEEE Std 1722.1-2013 clause 7.2.11
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type; // Set internally
+ U16 descriptor_index; // Set internally
+ U8 locale_identifier[OPENAVB_AEM_STRLEN_MAX];
+ U16 number_of_strings;
+ U16 base_strings;
+} openavb_aem_descriptor_locale_t;
+
+openavb_aem_descriptor_locale_t *openavbAemDescriptorLocaleNew(void);
+
+// Specify the locale identifier for the descriptor.
+bool openavbAemDescriptorLocaleSet_locale_identifier(openavb_aem_descriptor_locale_t *pDescriptor, const char *aLocaleIdentifier);
+
+// Specify the number of strings descriptors in this locale.
+// The same number should be specified for all locales.
+bool openavbAemDescriptorLocaleSet_number_of_strings(openavb_aem_descriptor_locale_t *pDescriptor, U16 uNumberOfStrings);
+
+// Specify the descriptor index of the first strings descriptor for this locale.
+bool openavbAemDescriptorLocaleSet_base_strings(openavb_aem_descriptor_locale_t *pDescriptor, U16 uBaseStrings);
+
+#endif // OPENAVB_DESCRIPTOR_LOCALE_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_locale_strings_handler.c b/lib/avtp_pipeline/aem/openavb_descriptor_locale_strings_handler.c
new file mode 100644
index 00000000..8591bda2
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_locale_strings_handler.c
@@ -0,0 +1,230 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Locale Strings Handler Descriptor
+ ******************************************************************
+ */
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_aem.h"
+#include "openavb_descriptor_locale_strings_handler.h"
+
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+
+extern DLL_EXPORT openavb_aem_descriptor_locale_strings_handler_t *openavbAemDescriptorLocaleStringsHandlerNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_locale_strings_handler_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT void openavbAemDescriptorLocaleStringsHandlerFree(
+ openavb_aem_descriptor_locale_strings_handler_t *pDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (pDescriptor) {
+ while (pDescriptor->pFirstGroup) {
+ openavb_aem_descriptor_locale_strings_handler_group_t *pDel = pDescriptor->pFirstGroup;
+ pDescriptor->pFirstGroup = pDel->pNext;
+ free(pDel->pLocale); // TODO BDT_DEBUG Will this be freed elsewhere?
+ free(pDel->pStrings); // TODO BDT_DEBUG Will this be freed elsewhere?
+ free(pDel);
+ }
+ free(pDescriptor);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+}
+
+extern DLL_EXPORT openavb_aem_descriptor_locale_strings_handler_group_t * openavbAemDescriptorLocaleStringsHandlerGet_group(
+ openavb_aem_descriptor_locale_strings_handler_t *pDescriptor,
+ const char *aLocaleIdentifier,
+ bool bCanCreate)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor || !aLocaleIdentifier) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ // Do we have a matching item?
+ openavb_aem_descriptor_locale_strings_handler_group_t *pTest = pDescriptor->pFirstGroup;
+ while (pTest) {
+ if (strncmp(aLocaleIdentifier, (const char *) pTest->pLocale->locale_identifier, OPENAVB_AEM_STRLEN_MAX) == 0) {
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pTest;
+ }
+ pTest = pTest->pNext;
+ }
+
+ // Can we allocate a new language structure?
+ if (bCanCreate) {
+ // Allocate a new group.
+ openavb_aem_descriptor_locale_strings_handler_group_t *pNew = malloc(sizeof(openavb_aem_descriptor_locale_strings_handler_group_t));
+ if (!pNew) {
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ pNew->pLocale = openavbAemDescriptorLocaleNew();
+ pNew->pStrings = openavbAemDescriptorStringsNew();
+ if (!pNew->pLocale || !pNew->pStrings) {
+ free(pNew->pLocale);
+ free(pNew->pStrings);
+ free(pNew);
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ openavbAemDescriptorLocaleSet_locale_identifier(pNew->pLocale, aLocaleIdentifier);
+
+ // Add the new group to the start of the linked list.
+ pNew->pNext = pDescriptor->pFirstGroup;
+ pDescriptor->pFirstGroup = pNew;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pNew;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+}
+
+extern DLL_EXPORT const char * openavbAemDescriptorLocaleStringsHandlerGet_local_string(
+ openavb_aem_descriptor_locale_strings_handler_t *pDescriptor,
+ const char *aLocaleIdentifier,
+ U8 uStringIndex)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor || !aLocaleIdentifier || uStringIndex >= OPENAVB_AEM_NUM_DESCRIPTOR_STRINGS) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ // Get the group structure to get this string from.
+ openavb_aem_descriptor_locale_strings_handler_group_t *pGroup = openavbAemDescriptorLocaleStringsHandlerGet_group(pDescriptor, aLocaleIdentifier, FALSE);
+ if (!pGroup) {
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ const char * ret = openavbAemDescriptorStringsGet_string(pGroup->pStrings, uStringIndex);
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return ret;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorLocaleStringsHandlerSet_local_string(
+ openavb_aem_descriptor_locale_strings_handler_t *pDescriptor,
+ const char *aLocaleIdentifier,
+ const char *aString,
+ U8 uStringIndex)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor || !aLocaleIdentifier || !aString || uStringIndex >= OPENAVB_AEM_NUM_DESCRIPTOR_STRINGS) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ // Get the group structure to add this string to. Create it if needed.
+ openavb_aem_descriptor_locale_strings_handler_group_t *pGroup = openavbAemDescriptorLocaleStringsHandlerGet_group(pDescriptor, aLocaleIdentifier, TRUE);
+ if (!pGroup) {
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ bool ret = openavbAemDescriptorStringsSet_string(pGroup->pStrings, aString, uStringIndex);
+ if (ret) {
+ openavbAemDescriptorLocaleSet_number_of_strings(pGroup->pLocale, 1);
+ openavbAemDescriptorLocaleSet_base_strings(pGroup->pLocale, 0);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return ret;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorLocaleStringsHandlerAddToConfiguration(
+ openavb_aem_descriptor_locale_strings_handler_t *pDescriptor, U16 nConfigIdx)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_locale_strings_handler_group_t *pCurrent = pDescriptor->pFirstGroup;
+ while (pCurrent) {
+ U16 nResultIdx;
+
+ // Add the locale to the configuration.
+ if (!openavbAemAddDescriptor(pCurrent->pLocale, nConfigIdx, &nResultIdx)) {
+ AVB_LOG_ERROR("Locale Add Descriptor Failure");
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return false;
+ }
+
+ // Add the strings descriptor, if it hasn't already been added.
+ if (openavbAemGetDescriptorIndex(OPENAVB_AEM_DESCRIPTOR_INVALID, pCurrent->pStrings) == OPENAVB_AEM_DESCRIPTOR_INVALID) {
+ if (!openavbAemAddDescriptor(pCurrent->pStrings, OPENAVB_AEM_DESCRIPTOR_INVALID /* Not configuration-specific */, &nResultIdx)) {
+ AVB_LOG_ERROR("Strings Add Descriptor Failure");
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return false;
+ }
+ }
+
+ pCurrent = pCurrent->pNext;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return true;
+}
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_locale_strings_handler.h b/lib/avtp_pipeline/aem/openavb_descriptor_locale_strings_handler.h
new file mode 100644
index 00000000..adf36ca2
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_locale_strings_handler.h
@@ -0,0 +1,44 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Locale Descriptor
+ * MODULE SUMMARY : Interface for the Locale Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_LOCALE_STRINGS_HANDLER_H
+#define OPENAVB_DESCRIPTOR_LOCALE_STRINGS_HANDLER_H 1
+
+#include "openavb_descriptor_locale_strings_handler_pub.h"
+
+#endif // OPENAVB_DESCRIPTOR_LOCALE_STRINGS_HANDLER_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_locale_strings_handler_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_locale_strings_handler_pub.h
new file mode 100644
index 00000000..04796d0c
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_locale_strings_handler_pub.h
@@ -0,0 +1,91 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Locale Strings Handler Public Interface
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_LOCALE_STRINGS_HANDLER_PUB_H
+#define OPENAVB_DESCRIPTOR_LOCALE_STRINGS_HANDLER_PUB_H 1
+
+#include "openavb_descriptor_locale_pub.h"
+#include "openavb_descriptor_strings_pub.h"
+
+// Grouping that holds a locale, and the strings for that locale.
+struct openavb_aem_descriptor_locale_strings_handler_group {
+ openavb_aem_descriptor_locale_t *pLocale;
+ openavb_aem_descriptor_strings_t *pStrings;
+ struct openavb_aem_descriptor_locale_strings_handler_group *pNext;
+};
+typedef struct openavb_aem_descriptor_locale_strings_handler_group openavb_aem_descriptor_locale_strings_handler_group_t;
+
+// Grouping that holds a locale, and the strings for that locale.
+typedef struct {
+ openavb_aem_descriptor_locale_strings_handler_group_t *pFirstGroup;
+} openavb_aem_descriptor_locale_strings_handler_t;
+
+
+openavb_aem_descriptor_locale_strings_handler_t *openavbAemDescriptorLocaleStringsHandlerNew(void);
+
+void openavbAemDescriptorLocaleStringsHandlerFree(
+ openavb_aem_descriptor_locale_strings_handler_t *pDescriptor);
+
+// Return the group structure for the specified locale.
+// If bCanCreate is TRUE, a structure one will be allocated if needed.
+openavb_aem_descriptor_locale_strings_handler_group_t * openavbAemDescriptorLocaleStringsHandlerGet_group(
+ openavb_aem_descriptor_locale_strings_handler_t *pDescriptor,
+ const char *aLocaleIdentifier,
+ bool bCanCreate);
+
+// Returns the string at the specified index for the given locale,
+// or NULL if the string has not been specified.
+const char * openavbAemDescriptorLocaleStringsHandlerGet_local_string(
+ openavb_aem_descriptor_locale_strings_handler_t *pDescriptor,
+ const char *aLocaleIdentifier,
+ U8 uStringIndex);
+
+// Set a string at the specified index for the given locale.
+// If there was a previous string value, it will be overwritten.
+// The index must be a value less than OPENAVB_AEM_NUM_DESCRIPTOR_STRINGS.
+bool openavbAemDescriptorLocaleStringsHandlerSet_local_string(
+ openavb_aem_descriptor_locale_strings_handler_t *pDescriptor,
+ const char *aLocaleIdentifier,
+ const char *aString,
+ U8 uStringIndex);
+
+// Add the strings to the supplied configuration.
+bool openavbAemDescriptorLocaleStringsHandlerAddToConfiguration(
+ openavb_aem_descriptor_locale_strings_handler_t *pDescriptor,
+ U16 nConfigIdx);
+
+#endif // OPENAVB_DESCRIPTOR_LOCALE_STRINGS_HANDLER_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_stream_io.c b/lib/avtp_pipeline/aem/openavb_descriptor_stream_io.c
new file mode 100644
index 00000000..d585a47d
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_stream_io.c
@@ -0,0 +1,572 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Stream IO Descriptor
+ * MODULE SUMMARY : Implements the AVDECC Stream IO IEEE Std 1722.1-2013 clause 7.2.6
+ ******************************************************************
+ */
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_stream_io.h"
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+
+openavbRC openavbAemDescriptorStreamIOToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_stream_io_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_STREAM_IO_BASE_LENGTH + (pDescriptor->number_of_formats * OPENAVB_DESCRIPTOR_STREAM_IO_FORMAT_LENGTH)) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_stream_io_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BMEMCP(pDst, pSrc->object_name);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.offset, 3, 0);
+ BIT_D2BHTONS(pDst, pSrc->localized_description.index, 0, 2);
+ OCT_D2BHTONS(pDst, pSrc->clock_domain_index);
+ OCT_D2BHTONS(pDst, pSrc->stream_flags);
+ openavbAemStreamFormatToBuf(&pSrc->current_format, pDst);
+ pDst += 8;
+ OCT_D2BHTONS(pDst, pSrc->formats_offset);
+ OCT_D2BHTONS(pDst, pSrc->number_of_formats);
+ OCT_D2BMEMCP(pDst, pSrc->backup_talker_entity_id_0);
+ OCT_D2BHTONS(pDst, pSrc->backup_talker_unique_id_0);
+ OCT_D2BMEMCP(pDst, pSrc->backup_talker_entity_id_1);
+ OCT_D2BHTONS(pDst, pSrc->backup_talker_unique_id_1);
+ OCT_D2BMEMCP(pDst, pSrc->backup_talker_entity_id_2);
+ OCT_D2BHTONS(pDst, pSrc->backup_talker_unique_id_2);
+ OCT_D2BMEMCP(pDst, pSrc->backedup_talker_entity_id);
+ OCT_D2BHTONS(pDst, pSrc->backedup_talker_unique_id);
+ OCT_D2BHTONS(pDst, pSrc->avb_interface_index);
+ OCT_D2BHTONL(pDst, pSrc->buffer_length);
+
+ int i1;
+ for (i1 = 0; i1 < pSrc->number_of_formats; i1++) {
+ openavbAemStreamFormatToBuf(&pSrc->stream_formats[i1], pDst);
+ pDst += 8;
+ }
+
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+
+void x_openavbAemStreamFormatFromBuf(openavb_aem_stream_format_t *pDst, U8 *pBuf)
+{
+ U8 *pSrc = pBuf;
+
+ // Tightly bound to caller not safety checks needed.
+
+ BIT_B2DNTOHB(pDst->v, pSrc, 0x80, 7, 0);
+ if (pDst->v == 0) {
+ BIT_B2DNTOHB(pDst->subtype, pSrc, 0x7f, 0, 1);
+ switch (pDst->subtype) {
+ case OPENAVB_AEM_STREAM_FORMAT_61883_IIDC_SUBTYPE:
+ {
+ BIT_B2DNTOHB(pDst->subtypes.iec_61883_iidc.sf, pSrc, 0x80, 7, 0);
+ if (pDst->subtypes.iec_61883_iidc.sf == OPENAVB_AEM_STREAM_FORMAT_SF_IIDC) {
+ pSrc += 4;
+ OCT_B2DNTOHB(pDst->subtypes.iidc.iidc_format, pSrc);
+ OCT_B2DNTOHB(pDst->subtypes.iidc.iidc_mode, pSrc);
+ OCT_B2DNTOHB(pDst->subtypes.iidc.iidc_rate, pSrc);
+ }
+ else {
+ BIT_B2DNTOHB(pDst->subtypes.iec_61883.sf, pSrc, 0x80, 7, 0);
+ BIT_B2DNTOHB(pDst->subtypes.iec_61883.fmt, pSrc, 0x7e, 1, 1);
+ if (pDst->subtypes.iec_61883.fmt == OPENAVB_AEM_STREAM_FORMAT_FMT_61883_4) {
+ // Nothingn to do
+ }
+ else if (pDst->subtypes.iec_61883.fmt == OPENAVB_AEM_STREAM_FORMAT_FMT_61883_6) {
+ BIT_B2DNTOHB(pDst->subtypes.iec_61883_6.fdf_evt, pSrc, 0xf8, 3, 0);
+ BIT_B2DNTOHB(pDst->subtypes.iec_61883_6.fdf_sfc, pSrc, 0x07, 0, 1);
+ OCT_B2DNTOHB(pDst->subtypes.iec_61883_6.dbs, pSrc);
+ BIT_B2DNTOHB(pDst->subtypes.iec_61883_6.b, pSrc, 0x80, 7, 0);
+ BIT_B2DNTOHB(pDst->subtypes.iec_61883_6.nb, pSrc, 0x40, 6, 1);
+
+ if (pDst->subtypes.iec_61883_6.fdf_evt == OPENAVB_AEM_STREAM_FORMAT_FDF_EVT_61883_6_32BITS) {
+ // Nothing to do
+ }
+ else if (pDst->subtypes.iec_61883_6.fdf_evt == OPENAVB_AEM_STREAM_FORMAT_FDF_EVT_61883_6_FLOAT) {
+ // Nothing to do
+ }
+ else if (pDst->subtypes.iec_61883_6.fdf_evt == OPENAVB_AEM_STREAM_FORMAT_FDF_EVT_61883_6_AM824) {
+ OCT_B2DNTOHB(pDst->subtypes.iec_61883_6_am824.label_iec_60958_cnt, pSrc);
+ OCT_B2DNTOHB(pDst->subtypes.iec_61883_6_am824.label_mbla_cnt, pSrc);
+ BIT_B2DNTOHB(pDst->subtypes.iec_61883_6_am824.label_midi_cnt, pSrc, 0xf0, 4, 0);
+ BIT_B2DNTOHB(pDst->subtypes.iec_61883_6_am824.label_smptecnt, pSrc, 0x0f, 0, 1);
+ }
+ }
+
+ else if (pDst->subtypes.iec_61883.fmt == OPENAVB_AEM_STREAM_FORMAT_FMT_61883_8) {
+ pSrc += 3;
+ OCT_B2DNTOHB(pDst->subtypes.iec_61883_8.video_mode, pSrc);
+ OCT_B2DNTOHB(pDst->subtypes.iec_61883_8.compress_mode, pSrc);
+ OCT_B2DNTOHB(pDst->subtypes.iec_61883_8.color_space, pSrc);
+ }
+ }
+ }
+
+ break;
+ case OPENAVB_AEM_STREAM_FORMAT_MMA_SUBTYPE:
+ // Nothing to do
+ break;
+ case OPENAVB_AEM_STREAM_FORMAT_AVTP_AUDIO_SUBTYPE:
+ BIT_B2DNTOHB(pDst->subtypes.avtp_audio.nominal_sample_rate, pSrc, 0x0f, 0, 1);
+ OCT_B2DNTOHB(pDst->subtypes.avtp_audio.format, pSrc);
+ OCT_B2DNTOHB(pDst->subtypes.avtp_audio.bit_depth, pSrc);
+ BIT_B2DNTOHL(pDst->subtypes.avtp_audio.channels_per_frame, pSrc, 0xffc00000, 22, 0);
+ BIT_B2DNTOHL(pDst->subtypes.avtp_audio.samples_per_frame, pSrc, 0x003ff000, 12, 4);
+ break;
+ case OPENAVB_AEM_STREAM_FORMAT_AVTP_VIDEO_SUBTYPE:
+ OCT_B2DNTOHB(pDst->subtypes.avtp_video.format, pSrc);
+ break;
+ case OPENAVB_AEM_STREAM_FORMAT_AVTP_CONTROL_SUBTYPE:
+ BIT_B2DNTOHB(pDst->subtypes.avtp_control.protocol_type, pSrc, 0xf0, 4, 1);
+ OCT_B2DMEMCP(pDst->subtypes.avtp_control.format_id, pSrc);
+ break;
+ case OPENAVB_AEM_STREAM_FORMAT_VENDOR_SUBTYPE:
+ pSrc++;
+ OCT_B2DMEMCP(pDst->subtypes.vendor.format_id, pSrc);
+ break;
+ case OPENAVB_AEM_STREAM_FORMAT_EXPERIMENTAL_SUBTYPE:
+ // Nothing to do
+ break;
+ }
+ }
+ else {
+ pSrc++;
+ OCT_B2DMEMCP(pDst->subtypes.vendor_specific.format_id, pSrc);
+ }
+}
+
+
+openavbRC openavbAemDescriptorStreamIOFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_stream_io_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_STREAM_IO_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_stream_io_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DMEMCP(pDst->object_name, pSrc);
+ BIT_B2DNTOHS(pDst->localized_description.offset, pSrc, 0xfff8, 3, 0);
+ BIT_B2DNTOHS(pDst->localized_description.index, pSrc, 0x0007, 0, 2);
+ OCT_B2DNTOHS(pDst->clock_domain_index, pSrc);
+ OCT_B2DNTOHS(pDst->stream_flags, pSrc);
+ x_openavbAemStreamFormatFromBuf(&pDst->current_format, pSrc);
+ pSrc += 8;
+ OCT_B2DNTOHS(pDst->formats_offset, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_formats, pSrc);
+ OCT_B2DMEMCP(pDst->backup_talker_entity_id_0, pSrc);
+ OCT_B2DNTOHS(pDst->backup_talker_unique_id_0, pSrc);
+ OCT_B2DMEMCP(pDst->backup_talker_entity_id_1, pSrc);
+ OCT_B2DNTOHS(pDst->backup_talker_unique_id_1, pSrc);
+ OCT_B2DMEMCP(pDst->backup_talker_entity_id_2, pSrc);
+ OCT_B2DNTOHS(pDst->backup_talker_unique_id_2, pSrc);
+ OCT_B2DMEMCP(pDst->backedup_talker_entity_id, pSrc);
+ OCT_B2DNTOHS(pDst->backedup_talker_unique_id, pSrc);
+ OCT_B2DNTOHS(pDst->avb_interface_index, pSrc);
+ OCT_B2DNTOHL(pDst->buffer_length, pSrc);
+
+ if (bufLength < OPENAVB_DESCRIPTOR_STREAM_IO_BASE_LENGTH + (pDescriptor->number_of_formats * OPENAVB_DESCRIPTOR_STREAM_IO_FORMAT_LENGTH)) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ int i1;
+ for (i1 = 0; i1 < pDst->number_of_formats; i1++) {
+ x_openavbAemStreamFormatFromBuf(&pDst->stream_formats[i1], pSrc);
+ pSrc += 8;
+ }
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorStreamIOUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_stream_io_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_stream_io_t *openavbAemDescriptorStreamInputNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_stream_io_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_stream_io_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = TRUE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorStreamIOToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorStreamIOFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorStreamIOUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT;
+ pDescriptor->formats_offset = OPENAVB_DESCRIPTOR_STREAM_IO_BASE_LENGTH;
+
+ // Default to no localized strings.
+ pDescriptor->localized_description.offset = OPENAVB_AEM_NO_STRING_OFFSET;
+ pDescriptor->localized_description.index = OPENAVB_AEM_NO_STRING_INDEX;
+
+ // Will determine the status of this once the Listener has connected to AVDECC.
+ pDescriptor->fast_connect_status = OPENAVB_FAST_CONNECT_STATUS_UNKNOWN;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT openavb_aem_descriptor_stream_io_t *openavbAemDescriptorStreamOutputNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_stream_io_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_stream_io_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = TRUE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorStreamIOToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorStreamIOFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorStreamIOUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT;
+ pDescriptor->formats_offset = OPENAVB_DESCRIPTOR_STREAM_IO_BASE_LENGTH;
+
+ // Default to no localized strings.
+ pDescriptor->localized_description.offset = OPENAVB_AEM_NO_STRING_OFFSET;
+ pDescriptor->localized_description.index = OPENAVB_AEM_NO_STRING_INDEX;
+
+ // Talkers won't attempt to fast connect.
+ pDescriptor->fast_connect_status = OPENAVB_FAST_CONNECT_STATUS_NOT_AVAILABLE;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+static void fillInStreamFormat(openavb_aem_descriptor_stream_io_t *pDescriptor, const openavb_avdecc_configuration_cfg_t *pConfig)
+{ // AVDECC_TODO - Specify the stream format information for MMA Stream Format.
+ if (strcmp(pConfig->stream->map_fn,"openavbMapAVTPAudioInitialize") == 0)
+ {
+ pDescriptor->stream_formats[0].v = 0;
+ pDescriptor->stream_formats[0].subtype = OPENAVB_AEM_STREAM_FORMAT_AVTP_AUDIO_SUBTYPE;
+ pDescriptor->stream_formats[0].subtypes.avtp_audio.nominal_sample_rate = 0x05;
+ pDescriptor->stream_formats[0].subtypes.avtp_audio.format = 2;
+ pDescriptor->stream_formats[0].subtypes.avtp_audio.bit_depth = 32;
+ pDescriptor->stream_formats[0].subtypes.avtp_audio.channels_per_frame = 2;
+ pDescriptor->stream_formats[0].subtypes.avtp_audio.samples_per_frame = 6;
+ }
+ else if (strcmp(pConfig->stream->map_fn,"openavbMapUncmpAudioInitialize") == 0)
+ {
+ pDescriptor->stream_formats[0].v = 0;
+ pDescriptor->stream_formats[0].subtype = OPENAVB_AEM_STREAM_FORMAT_61883_IIDC_SUBTYPE;
+ pDescriptor->stream_formats[0].subtypes.iec_61883_iidc.sf = 1;
+ pDescriptor->stream_formats[0].subtypes.iec_61883_6_am824.fmt = OPENAVB_AEM_STREAM_FORMAT_FMT_61883_6;
+ pDescriptor->stream_formats[0].subtypes.iec_61883_6_am824.fdf_evt = OPENAVB_AEM_STREAM_FORMAT_FDF_EVT_61883_6_AM824;
+ pDescriptor->stream_formats[0].subtypes.iec_61883_6_am824.fdf_sfc = 0x02;
+ pDescriptor->stream_formats[0].subtypes.iec_61883_6_am824.dbs = 0x08;
+ pDescriptor->stream_formats[0].subtypes.iec_61883_6_am824.b = 0x00;
+ pDescriptor->stream_formats[0].subtypes.iec_61883_6_am824.nb = 0x01;
+ pDescriptor->stream_formats[0].subtypes.iec_61883_6_am824.label_iec_60958_cnt = 0;
+ pDescriptor->stream_formats[0].subtypes.iec_61883_6_am824.label_mbla_cnt = 8;
+ pDescriptor->stream_formats[0].subtypes.iec_61883_6_am824.label_midi_cnt = 0;
+ pDescriptor->stream_formats[0].subtypes.iec_61883_6_am824.label_smptecnt = 0;
+ }
+ else if (strcmp(pConfig->stream->map_fn,"openavbMapCtrlInitialize") == 0)
+ {
+ pDescriptor->stream_formats[0].v = 0;
+ pDescriptor->stream_formats[0].subtype = OPENAVB_AEM_STREAM_FORMAT_AVTP_CONTROL_SUBTYPE;
+ pDescriptor->stream_formats[0].subtypes.avtp_control.protocol_type = 3;
+ pDescriptor->stream_formats[0].subtypes.avtp_control.format_id[0] = 0x90;
+ pDescriptor->stream_formats[0].subtypes.avtp_control.format_id[1] = 0xe0;
+ pDescriptor->stream_formats[0].subtypes.avtp_control.format_id[2] = 0xf0;
+ pDescriptor->stream_formats[0].subtypes.avtp_control.format_id[3] = 0x00;
+ pDescriptor->stream_formats[0].subtypes.avtp_control.format_id[4] = 0x00;
+ pDescriptor->stream_formats[0].subtypes.avtp_control.format_id[5] = 0x00;
+ }
+ else if (strcmp(pConfig->stream->map_fn,"openavbMapMpeg2tsInitialize") == 0)
+ {
+ pDescriptor->stream_formats[0].v = 0;
+ pDescriptor->stream_formats[0].subtype = OPENAVB_AEM_STREAM_FORMAT_61883_IIDC_SUBTYPE;
+ pDescriptor->stream_formats[0].subtypes.iec_61883_4.sf = 1;
+ pDescriptor->stream_formats[0].subtypes.iec_61883_4.fmt = OPENAVB_AEM_STREAM_FORMAT_FMT_61883_4;
+ }
+ else if (strcmp(pConfig->stream->map_fn,"openavbMapMjpegInitialize") == 0 || strcmp(pConfig->stream->map_fn,"openavbMapH264Initialize") == 0)
+ {
+ pDescriptor->stream_formats[0].v = 0;
+ pDescriptor->stream_formats[0].subtype = OPENAVB_AEM_STREAM_FORMAT_AVTP_VIDEO_SUBTYPE;
+ if (strcmp(pConfig->stream->map_fn,"openavbMapMjpegInitialize") == 0)
+ {
+ pDescriptor->stream_formats[0].subtypes.avtp_video.format = OPENAVB_AEM_RTP_PAYLOAD_SUBTYPE_RTP_MJPEG;
+ }
+ else
+ {
+ pDescriptor->stream_formats[0].subtypes.avtp_video.format = OPENAVB_AEM_RTP_PAYLOAD_SUBTYPE_RTP_H264;
+ }
+ }
+ pDescriptor->number_of_formats = 1;
+
+ // Make the current format the first format in the list.
+ memcpy(&(pDescriptor->current_format), &(pDescriptor->stream_formats[0]), sizeof(openavb_aem_stream_format_t));
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorStreamInputInitialize(openavb_aem_descriptor_stream_io_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig)
+{
+ (void) nConfigIdx;
+ if (!pDescriptor || !pConfig) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // Specify a name.
+ sprintf((char *)(pDescriptor->object_name), "Stream Input %u", pDescriptor->descriptor_index);
+
+ // Specify the stream flags.
+ // The stream configuration is ignored for Listeners, as Listeners will accept both Class A and Class B.
+ pDescriptor->stream_flags |= ( OPENAVB_AEM_STREAM_FLAG_CLASS_A | OPENAVB_AEM_STREAM_FLAG_CLASS_B );
+
+ // Specify the stream format information.
+ fillInStreamFormat(pDescriptor, pConfig);
+
+ // Save the stream configuration pointer.
+ pDescriptor->stream = pConfig->stream;
+
+ return TRUE;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorStreamOutputInitialize(openavb_aem_descriptor_stream_io_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig)
+{
+ (void) nConfigIdx;
+ if (!pDescriptor || !pConfig) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // Specify a name.
+ sprintf((char *)(pDescriptor->object_name), "Stream Output %u", pDescriptor->descriptor_index);
+
+ // Specify the stream flags.
+ if (pConfig->stream->sr_class == SR_CLASS_A) { pDescriptor->stream_flags |= OPENAVB_AEM_STREAM_FLAG_CLASS_A; }
+ if (pConfig->stream->sr_class == SR_CLASS_B) { pDescriptor->stream_flags |= OPENAVB_AEM_STREAM_FLAG_CLASS_B; }
+
+ // Specify the stream format information.
+ fillInStreamFormat(pDescriptor, pConfig);
+
+ // Save the stream configuration pointer.
+ pDescriptor->stream = pConfig->stream;
+
+ return TRUE;
+}
+
+
+////////////////////////////////
+// Public functions for internal
+// AVDECC use (not exported)
+////////////////////////////////
+
+void openavbAemStreamFormatToBuf(openavb_aem_stream_format_t *pSrc, U8 *pBuf)
+{
+ U8 *pDst = pBuf;
+
+ // Tightly bound to caller not safety checks needed.
+
+ memset(pBuf, 0, 8);
+
+ if (pSrc->v == 0) {
+ BIT_D2BHTONB(pDst, pSrc->v, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtype, 0, 1);
+ switch (pSrc->subtype) {
+ case OPENAVB_AEM_STREAM_FORMAT_61883_IIDC_SUBTYPE:
+ {
+ if (pSrc->subtypes.iec_61883_iidc.sf == OPENAVB_AEM_STREAM_FORMAT_SF_IIDC) {
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iidc.sf, 7, 1);
+ pDst += 3;
+ OCT_D2BHTONB(pDst, pSrc->subtypes.iidc.iidc_format);
+ OCT_D2BHTONB(pDst, pSrc->subtypes.iidc.iidc_mode);
+ OCT_D2BHTONB(pDst, pSrc->subtypes.iidc.iidc_rate);
+ }
+ else {
+ if (pSrc->subtypes.iec_61883.fmt == OPENAVB_AEM_STREAM_FORMAT_FMT_61883_4) {
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_4.sf, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_4.fmt, 1, 1);
+ }
+ else if (pSrc->subtypes.iec_61883.fmt == OPENAVB_AEM_STREAM_FORMAT_FMT_61883_6) {
+ if (pSrc->subtypes.iec_61883_6.fdf_evt == OPENAVB_AEM_STREAM_FORMAT_FDF_EVT_61883_6_32BITS) {
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_32bit.sf, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_32bit.fmt, 1, 1);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_32bit.fdf_evt, 3, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_32bit.fdf_sfc, 0, 1);
+ OCT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_32bit.dbs);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_32bit.b, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_32bit.nb, 6, 1);
+ }
+ else if (pSrc->subtypes.iec_61883_6.fdf_evt == OPENAVB_AEM_STREAM_FORMAT_FDF_EVT_61883_6_FLOAT) {
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_float.sf, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_float.fmt, 1, 1);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_float.fdf_evt, 3, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_float.fdf_sfc, 0, 1);
+ OCT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_float.dbs);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_float.b, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_float.nb, 6, 1);
+ }
+ else if (pSrc->subtypes.iec_61883_6.fdf_evt == OPENAVB_AEM_STREAM_FORMAT_FDF_EVT_61883_6_AM824) {
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_am824.sf, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_am824.fmt, 1, 1);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_am824.fdf_evt, 3, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_am824.fdf_sfc, 0, 1);
+ OCT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_am824.dbs);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_am824.b, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_am824.nb, 6, 1);
+ OCT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_am824.label_iec_60958_cnt);
+ OCT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_am824.label_mbla_cnt);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_am824.label_midi_cnt, 4, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_6_am824.label_smptecnt, 0, 1);
+ }
+ }
+ else if (pSrc->subtypes.iec_61883.fmt == OPENAVB_AEM_STREAM_FORMAT_FMT_61883_8) {
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_8.sf, 7, 0);
+ BIT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_8.fmt, 1, 1);
+ pDst += 3;
+ OCT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_8.video_mode);
+ OCT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_8.compress_mode);
+ OCT_D2BHTONB(pDst, pSrc->subtypes.iec_61883_8.color_space);
+ }
+ }
+ }
+
+ break;
+ case OPENAVB_AEM_STREAM_FORMAT_MMA_SUBTYPE:
+ // Nothing to do
+ break;
+ case OPENAVB_AEM_STREAM_FORMAT_AVTP_AUDIO_SUBTYPE:
+ BIT_D2BHTONB(pDst, pSrc->subtypes.avtp_audio.nominal_sample_rate, 0, 1);
+ OCT_D2BHTONB(pDst, pSrc->subtypes.avtp_audio.format);
+ OCT_D2BHTONB(pDst, pSrc->subtypes.avtp_audio.bit_depth);
+ BIT_D2BHTONL(pDst, pSrc->subtypes.avtp_audio.channels_per_frame, 22, 0);
+ BIT_D2BHTONL(pDst, pSrc->subtypes.avtp_audio.samples_per_frame, 12, 4);
+ break;
+ case OPENAVB_AEM_STREAM_FORMAT_AVTP_VIDEO_SUBTYPE:
+ OCT_D2BHTONB(pDst, pSrc->subtypes.avtp_video.format);
+ break;
+ case OPENAVB_AEM_STREAM_FORMAT_AVTP_CONTROL_SUBTYPE:
+ BIT_D2BHTONB(pDst, pSrc->subtypes.avtp_control.protocol_type, 4, 1);
+ OCT_D2BMEMCP(pDst, pSrc->subtypes.avtp_control.format_id);
+ break;
+ case OPENAVB_AEM_STREAM_FORMAT_VENDOR_SUBTYPE:
+ pDst++;
+ OCT_D2BMEMCP(pDst, pSrc->subtypes.vendor.format_id);
+ break;
+ case OPENAVB_AEM_STREAM_FORMAT_EXPERIMENTAL_SUBTYPE:
+ // Nothing to do
+ break;
+ }
+ }
+ else {
+ BIT_D2BHTONB(pDst, pSrc->v, 7, 1);
+ pDst++;
+ OCT_D2BMEMCP(pDst, pSrc->subtypes.vendor_specific.format_id);
+ }
+}
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_stream_io.h b/lib/avtp_pipeline/aem/openavb_descriptor_stream_io.h
new file mode 100644
index 00000000..b4edc9c4
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_stream_io.h
@@ -0,0 +1,47 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Stream IO Descriptor
+ * MODULE SUMMARY : Interface for the Stream IO Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_STREAM_IO_H
+#define OPENAVB_DESCRIPTOR_STREAM_IO_H 1
+
+#include "openavb_descriptor_stream_io_pub.h"
+
+#define OPENAVB_DESCRIPTOR_STREAM_IO_BASE_LENGTH 132
+#define OPENAVB_DESCRIPTOR_STREAM_IO_FORMAT_LENGTH 8
+
+#endif // OPENAVB_DESCRIPTOR_STREAM_IO_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_stream_io_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_stream_io_pub.h
new file mode 100644
index 00000000..91fc384f
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_stream_io_pub.h
@@ -0,0 +1,111 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Stream IO Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the Stream IO Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_STREAM_IO_PUB_H
+#define OPENAVB_DESCRIPTOR_STREAM_IO_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+#include "openavb_tl_pub.h"
+#include "openavb_avdecc_read_ini_pub.h"
+
+#define OPENAVB_DESCRIPTOR_STREAM_IO_MAX_FORMATS (47)
+
+// Possible statuses of the fast connect support for the Listener
+typedef enum {
+ OPENAVB_FAST_CONNECT_STATUS_UNKNOWN = 0, // Still need to determine if something is available
+ OPENAVB_FAST_CONNECT_STATUS_NOT_AVAILABLE, // No fast connects available for the Listener, or is a Talker
+ OPENAVB_FAST_CONNECT_STATUS_IN_PROGRESS, // Attempting fast connect
+ OPENAVB_FAST_CONNECT_STATUS_TIMED_OUT, // Talker did not respond to fast connect attempts
+ OPENAVB_FAST_CONNECT_STATUS_SUCCEEDED, // Fast connect was successful; don't need to try again
+} openavb_fast_connect_status_t;
+
+// STREAM IO Descriptor IEEE Std 1722.1-2013 clause 7.2.6
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type;
+ U16 descriptor_index;
+ U8 object_name[OPENAVB_AEM_STRLEN_MAX];
+ openavb_aem_string_ref_t localized_description;
+ U16 clock_domain_index;
+ U16 stream_flags;
+ openavb_aem_stream_format_t current_format;
+ U16 formats_offset;
+ U16 number_of_formats;
+ U8 backup_talker_entity_id_0[8];
+ U16 backup_talker_unique_id_0;
+ U8 backup_talker_entity_id_1[8];
+ U16 backup_talker_unique_id_1;
+ U8 backup_talker_entity_id_2[8];
+ U16 backup_talker_unique_id_2;
+ U8 backedup_talker_entity_id[8];
+ U16 backedup_talker_unique_id;
+ U16 avb_interface_index;
+ U32 buffer_length;
+ openavb_aem_stream_format_t stream_formats[OPENAVB_DESCRIPTOR_STREAM_IO_MAX_FORMATS];
+
+ // Current status of the fast connect support for the Listener.
+ openavb_fast_connect_status_t fast_connect_status;
+ U8 fast_connect_talker_entity_id[8];
+ struct timespec fast_connect_start_time;
+
+ // OPENAVB_ACMP_FLAG values from CONNECT_TX_RESPONSE or CONNECT_RX_RESPONSE.
+ U16 acmp_flags;
+
+ // Streaming values for GET_STREAM_INFO from CONNECT_TX_RESPONSE or CONNECT_RX_RESPONSE.
+ // These values are currently only used for the Listener, as the Talker can get them from it's current configuration.
+ U8 acmp_stream_id[8];
+ U8 acmp_dest_addr[6];
+ U16 acmp_stream_vlan_id;
+
+ // Also save a pointer to the supplied stream information.
+ const openavb_tl_data_cfg_t *stream;
+
+} openavb_aem_descriptor_stream_io_t;
+
+openavb_aem_descriptor_stream_io_t *openavbAemDescriptorStreamInputNew(void);
+openavb_aem_descriptor_stream_io_t *openavbAemDescriptorStreamOutputNew(void);
+
+bool openavbAemDescriptorStreamInputInitialize(openavb_aem_descriptor_stream_io_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig);
+bool openavbAemDescriptorStreamOutputInitialize(openavb_aem_descriptor_stream_io_t *pDescriptor, U16 nConfigIdx, const openavb_avdecc_configuration_cfg_t *pConfig);
+
+void openavbAemStreamFormatToBuf(openavb_aem_stream_format_t *pSrc, U8 *pBuf);
+
+#endif // OPENAVB_DESCRIPTOR_STREAM_IO_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_stream_port_io.c b/lib/avtp_pipeline/aem/openavb_descriptor_stream_port_io.c
new file mode 100644
index 00000000..007a11cb
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_stream_port_io.c
@@ -0,0 +1,207 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Stream Port IO Descriptor
+ * MODULE SUMMARY : Implements the AVDECC Stream Port IO IEEE Std 1722.1-2013 clause 7.2.13
+ ******************************************************************
+ */
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_stream_port_io.h"
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemDescriptorStreamPortIOToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_stream_port_io_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_STREAM_PORT_IO_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_stream_port_io_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ OCT_D2BHTONS(pDst, pSrc->clock_domain_index);
+ OCT_D2BHTONS(pDst, pSrc->port_flags);
+ OCT_D2BHTONS(pDst, pSrc->number_of_controls);
+ OCT_D2BHTONS(pDst, pSrc->base_control);
+ OCT_D2BHTONS(pDst, pSrc->number_of_clusters);
+ OCT_D2BHTONS(pDst, pSrc->base_cluster);
+ OCT_D2BHTONS(pDst, pSrc->number_of_maps);
+ OCT_D2BHTONS(pDst, pSrc->base_map);
+
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorStreamPortIOFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_stream_port_io_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_STREAM_PORT_IO_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_stream_port_io_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ OCT_B2DNTOHS(pDst->clock_domain_index, pSrc);
+ OCT_B2DNTOHS(pDst->port_flags, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_controls, pSrc);
+ OCT_B2DNTOHS(pDst->base_control, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_clusters, pSrc);
+ OCT_B2DNTOHS(pDst->base_cluster, pSrc);
+ OCT_B2DNTOHS(pDst->number_of_maps, pSrc);
+ OCT_B2DNTOHS(pDst->base_map, pSrc);
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorStreamPortIOUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_stream_port_io_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_stream_port_io_t *openavbAemDescriptorStreamPortInputNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_stream_port_io_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_stream_port_io_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = FALSE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorStreamPortIOToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorStreamPortIOFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorStreamPortIOUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_STREAM_PORT_INPUT;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT openavb_aem_descriptor_stream_port_io_t *openavbAemDescriptorStreamPortOutputNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_stream_port_io_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_stream_port_io_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = FALSE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorStreamPortIOToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorStreamPortIOFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorStreamPortIOUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_STREAM_PORT_OUTPUT;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_stream_port_io.h b/lib/avtp_pipeline/aem/openavb_descriptor_stream_port_io.h
new file mode 100644
index 00000000..fe331476
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_stream_port_io.h
@@ -0,0 +1,46 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Stream Port IO Descriptor
+ * MODULE SUMMARY : Interface for the Stream Port IO Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_STREAM_PORT_IO_H
+#define OPENAVB_DESCRIPTOR_STREAM_PORT_IO_H 1
+
+#include "openavb_descriptor_stream_port_io_pub.h"
+
+#define OPENAVB_DESCRIPTOR_STREAM_PORT_IO_BASE_LENGTH 20
+
+#endif // OPENAVB_DESCRIPTOR_STREAM_PORT_IO_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_stream_port_io_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_stream_port_io_pub.h
new file mode 100644
index 00000000..000c058d
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_stream_port_io_pub.h
@@ -0,0 +1,65 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Stream Port IO Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the Stream Port IO Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_STREAM_PORT_IO_PUB_H
+#define OPENAVB_DESCRIPTOR_STREAM_PORT_IO_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+
+// STREAM PORT IO Descriptor IEEE Std 1722.1-2013 clause 7.2.13
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type;
+ U16 descriptor_index;
+ U16 clock_domain_index;
+ U16 port_flags;
+ U16 number_of_controls;
+ U16 base_control;
+ U16 number_of_clusters;
+ U16 base_cluster;
+ U16 number_of_maps;
+ U16 base_map;
+} openavb_aem_descriptor_stream_port_io_t;
+
+openavb_aem_descriptor_stream_port_io_t *openavbAemDescriptorStreamPortInputNew(void);
+openavb_aem_descriptor_stream_port_io_t *openavbAemDescriptorStreamPortOutputNew(void);
+
+#endif // OPENAVB_DESCRIPTOR_STREAM_PORT_IO_PUB_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_strings.c b/lib/avtp_pipeline/aem/openavb_descriptor_strings.c
new file mode 100644
index 00000000..dc599622
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_strings.c
@@ -0,0 +1,193 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Strings Descriptor
+ * MODULE SUMMARY : Implements the AVDECC Strings IEEE Std 1722.1-2013 clause 7.2.12
+ ******************************************************************
+ */
+
+#include <stdlib.h>
+
+#define AVB_LOG_COMPONENT "AEM"
+#include "openavb_log.h"
+
+#include "openavb_rawsock.h"
+#include "openavb_aem.h"
+#include "openavb_descriptor_strings.h"
+
+
+////////////////////////////////
+// Private (internal) functions
+////////////////////////////////
+openavbRC openavbAemDescriptorStringsToBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf, U16 *descriptorSize)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_strings_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf || !descriptorSize) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_STRINGS_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ *descriptorSize = 0;
+
+ openavb_aem_descriptor_strings_t *pSrc = pDescriptor;
+ U8 *pDst = pBuf;
+
+ OCT_D2BHTONS(pDst, pSrc->descriptor_type);
+ OCT_D2BHTONS(pDst, pSrc->descriptor_index);
+ memcpy(pDst, pSrc->string, sizeof(pSrc->string));
+ pDst += sizeof(pSrc->string);
+ *descriptorSize = pDst - pBuf;
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorStringsFromBuf(void *pVoidDescriptor, U16 bufLength, U8 *pBuf)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_strings_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor || !pBuf) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ if (bufLength < OPENAVB_DESCRIPTOR_STRINGS_BASE_LENGTH) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVBAVDECC_RC_BUFFER_TOO_SMALL), AVB_TRACE_AEM);
+ }
+
+ U8 *pSrc = pBuf;
+ openavb_aem_descriptor_strings_t *pDst = pDescriptor;
+
+ OCT_B2DNTOHS(pDst->descriptor_type, pSrc);
+ OCT_B2DNTOHS(pDst->descriptor_index, pSrc);
+ memcpy(pDst->string, pSrc, sizeof(pDst->string));
+ pSrc += sizeof(pDst->string);
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+openavbRC openavbAemDescriptorStringsUpdate(void *pVoidDescriptor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_strings_t *pDescriptor = pVoidDescriptor;
+
+ if (!pDescriptor) {
+ AVB_RC_LOG_TRACE_RET(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT), AVB_TRACE_AEM);
+ }
+
+ // AVDECC_TODO - Any updates needed?
+
+ AVB_RC_TRACE_RET(OPENAVB_AVDECC_SUCCESS, AVB_TRACE_AEM);
+}
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT openavb_aem_descriptor_strings_t *openavbAemDescriptorStringsNew()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ openavb_aem_descriptor_strings_t *pDescriptor;
+
+ pDescriptor = malloc(sizeof(*pDescriptor));
+
+ if (!pDescriptor) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+ memset(pDescriptor, 0, sizeof(*pDescriptor));
+
+ pDescriptor->descriptorPvtPtr = malloc(sizeof(*pDescriptor->descriptorPvtPtr));
+ if (!pDescriptor->descriptorPvtPtr) {
+ free(pDescriptor);
+ pDescriptor = NULL;
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_OUT_OF_MEMORY));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ pDescriptor->descriptorPvtPtr->size = sizeof(openavb_aem_descriptor_strings_t);
+ pDescriptor->descriptorPvtPtr->bTopLevel = FALSE;
+ pDescriptor->descriptorPvtPtr->toBuf = openavbAemDescriptorStringsToBuf;
+ pDescriptor->descriptorPvtPtr->fromBuf = openavbAemDescriptorStringsFromBuf;
+ pDescriptor->descriptorPvtPtr->update = openavbAemDescriptorStringsUpdate;
+
+ pDescriptor->descriptor_type = OPENAVB_AEM_DESCRIPTOR_STRINGS;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return pDescriptor;
+}
+
+extern DLL_EXPORT const char * openavbAemDescriptorStringsGet_string(openavb_aem_descriptor_strings_t *pDescriptor, U8 index)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor || index >= OPENAVB_AEM_NUM_DESCRIPTOR_STRINGS) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return NULL;
+ }
+
+ const char *ret = (const char *) (pDescriptor->string[index]);
+ if (*ret == '\0') {
+ /* The string is empty. */
+ ret = NULL;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return ret;
+}
+
+extern DLL_EXPORT bool openavbAemDescriptorStringsSet_string(openavb_aem_descriptor_strings_t *pDescriptor, const char *pString, U8 index)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AEM);
+
+ if (!pDescriptor || !pString || index >= OPENAVB_AEM_NUM_DESCRIPTOR_STRINGS) {
+ AVB_RC_LOG(AVB_RC(OPENAVB_AVDECC_FAILURE | OPENAVB_RC_INVALID_ARGUMENT));
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return FALSE;
+ }
+
+ openavbAemSetString(pDescriptor->string[index], pString);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AEM);
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_strings.h b/lib/avtp_pipeline/aem/openavb_descriptor_strings.h
new file mode 100644
index 00000000..014cb2ac
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_strings.h
@@ -0,0 +1,46 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Strings Descriptor
+ * MODULE SUMMARY : Interface for the Strings Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_STRINGS_H
+#define OPENAVB_DESCRIPTOR_STRINGS_H 1
+
+#include "openavb_descriptor_strings_pub.h"
+
+#define OPENAVB_DESCRIPTOR_STRINGS_BASE_LENGTH 452
+
+#endif // OPENAVB_DESCRIPTOR_STRINGS_H
diff --git a/lib/avtp_pipeline/aem/openavb_descriptor_strings_pub.h b/lib/avtp_pipeline/aem/openavb_descriptor_strings_pub.h
new file mode 100644
index 00000000..57218c1b
--- /dev/null
+++ b/lib/avtp_pipeline/aem/openavb_descriptor_strings_pub.h
@@ -0,0 +1,65 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AEM - AVDECC Strings Descriptor Public Interface
+ * MODULE SUMMARY : Public Interface for the Strings Descriptor
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_DESCRIPTOR_STRINGS_PUB_H
+#define OPENAVB_DESCRIPTOR_STRINGS_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_aem_types_pub.h"
+#include "openavb_aem_pub.h"
+
+#define OPENAVB_AEM_NUM_DESCRIPTOR_STRINGS (7)
+
+// STRINGS Descriptor IEEE Std 1722.1-2013 clause 7.2.12
+typedef struct {
+ openavb_descriptor_pvt_ptr_t descriptorPvtPtr;
+
+ U16 descriptor_type; // Set internally
+ U16 descriptor_index; // Set internally
+ U8 string[OPENAVB_AEM_NUM_DESCRIPTOR_STRINGS][OPENAVB_AEM_STRLEN_MAX];
+} openavb_aem_descriptor_strings_t;
+
+openavb_aem_descriptor_strings_t *openavbAemDescriptorStringsNew(void);
+
+// Returns the descriptor string at the specified index, or NULL if not specified.
+const char * openavbAemDescriptorStringsGet_string(openavb_aem_descriptor_strings_t *pDescriptor, U8 index);
+
+// Set a descriptor string at the specified index.
+bool openavbAemDescriptorStringsSet_string(openavb_aem_descriptor_strings_t *pDescriptor, const char *pString, U8 index);
+
+#endif // OPENAVB_DESCRIPTOR_STRINGS_PUB_H
diff --git a/lib/avtp_pipeline/avdecc/CMakeLists.txt b/lib/avtp_pipeline/avdecc/CMakeLists.txt
new file mode 100644
index 00000000..bccfc799
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc/CMakeLists.txt
@@ -0,0 +1,12 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/avdecc/openavb_avdecc.c
+ ${AVB_OSAL_DIR}/avdecc/openavb_avdecc_osal.c
+ ${AVB_OSAL_DIR}/avdecc/openavb_avdecc_cfg.c
+ ${AVB_OSAL_DIR}/avdecc/openavb_avdecc_read_ini.c
+ ${AVB_OSAL_DIR}/avdecc/openavb_avdecc_pipeline_interaction.c
+ ${AVB_OSAL_DIR}/avdecc/openavb_avdecc_save_state.c
+ ${AVB_OSAL_DIR}/openavb_osal_avdecc.c
+ ${AVB_OSAL_DIR}/openavb_grandmaster_osal.c
+ ${AVB_SRC_DIR}/avdecc_msg/openavb_avdecc_msg_server.c
+ PARENT_SCOPE
+)
diff --git a/lib/avtp_pipeline/avdecc/avdecc.ini b/lib/avtp_pipeline/avdecc/avdecc.ini
new file mode 100644
index 00000000..d4b4bb60
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc/avdecc.ini
@@ -0,0 +1,82 @@
+[network]
+
+# Interface name on which to use AVDECC
+#ifname=eth2
+
+
+[vlan]
+
+# VLAN ID to use for AVDECC traffic.
+# If VLAN support is not desired, comment out this value.
+#vlanID = 2
+
+# VLAN Priority to use for AVDECC traffic.
+# If VLAN support is not desired, comment out this value.
+#vlanPCP = 3
+
+
+[fast_connect]
+
+# If enable (set to 1), the fast_connect option will cause AVDECC-initiated
+# connections to be saved to an avdecc_save.ini file. When the AVDECC client
+# is restarted after an unexpected shutdown, AVDECC Fast Connect will be
+# attempted.
+#
+# The default value is 0, which disabled the AVDECC Fast Connect and Saved
+# State support.
+fast_connect = 1
+
+
+[discovery]
+
+# The valid_time is the amount of time (in seconds) the device will be
+# considered valid by other devices on the network after the last received
+# discovery packet. A smaller valid_time value will cause the device to be
+# recognized as disappearing more quickly if it is unplugged from the network
+# (or stops working), but will result in more background network traffic.
+#
+# Valid values are 2 to 62 seconds, with only even numbers being allowed.
+# The default value is 62 seconds.
+valid_time = 20
+
+
+[descriptor_entity]
+
+# ID value to be combined with the interface MAC Address to generate the
+# entity_id. For example, a device with MAC Address 00:11:22:33:44:55 and
+# avdeccId of 0x9876 would be assigned an entity_id of
+# 00-01-02-98-76-33-44-55.
+# The default ID value is 0xfffe.
+#avdeccId = 0xfffe
+
+# The entity_model_id is a unique vendor-specific 64-bit number used to
+# identify an AVDECC data model.
+entity_model_id = 0x0000000000000000
+
+# The entity_name is a UTF-8 string defining the device's name
+entity_name = "ACME Audio Processor"
+
+# The firmware_version is a UTF-8 string defining the device's firmware
+# version
+firmware_version = "0.0.0.1"
+
+# The group_name is a UTF-8 string defining the name of the device's group
+group_name = "Acme Processors"
+
+# The serial_number is a UTF-8 string defining the device's serial number
+serial_number = "12345"
+
+
+[localization]
+
+# A UTF-8 string defining the localization language to use for localized
+# strings. The format is "language code - region code".
+# Refer to IEEE Std 1722.1-2013 clause 7.2.11 for more details.
+locale_identifier = "en"
+
+# The vendor_name is a localized UTF-8 string defining the vendor's name
+vendor_name = "Acme Audio Inc."
+
+# The model_name is a localized UTF-8 string defining the device's model name
+model_name = "Acme 2400X"
+
diff --git a/lib/avtp_pipeline/avdecc/openavb_avdecc.c b/lib/avtp_pipeline/avdecc/openavb_avdecc.c
new file mode 100644
index 00000000..9c82a648
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc/openavb_avdecc.c
@@ -0,0 +1,509 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AVDECC - Top level 1722.1 implementation
+ * MODULE SUMMARY : Top level 1722.1 implementation
+ ******************************************************************
+ */
+
+#include "openavb_rawsock.h"
+#include "openavb_avtp.h"
+
+#define AVB_LOG_COMPONENT "AVDECC"
+#include "openavb_log.h"
+
+#include "openavb_aem.h"
+#include "openavb_adp.h"
+#include "openavb_acmp.h"
+#include "openavb_aecp.h"
+
+#include "openavb_endpoint.h"
+
+#define ADDR_PTR(A) (U8*)(&((A)->ether_addr_octet))
+
+openavb_avdecc_cfg_t gAvdeccCfg;
+openavb_tl_data_cfg_t * streamList = NULL;
+openavb_aem_descriptor_configuration_t *pConfiguration = NULL;
+
+static openavb_avdecc_configuration_cfg_t *pFirstConfigurationCfg = NULL;
+static U8 talker_stream_sources = 0;
+static U8 listener_stream_sources = 0;
+static bool first_talker = 1;
+static bool first_listener = 1;
+
+bool openavbAvdeccStartAdp()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ openavbRC rc = openavbAdpStart();
+ if (IS_OPENAVB_FAILURE(rc)) {
+ openavbAdpStop();
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return TRUE;
+}
+
+void openavbAvdeccStopAdp()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+ openavbAdpStop();
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+}
+
+bool openavbAvdeccStartCmp()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ openavbRC rc = openavbAcmpStart();
+ if (IS_OPENAVB_FAILURE(rc)) {
+ openavbAcmpStop();
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return TRUE;
+}
+
+void openavbAvdeccStopCmp()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+ openavbAcmpStop();
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+}
+
+bool openavbAvdeccStartEcp()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ openavbRC rc = openavbAecpStart();
+ if (IS_OPENAVB_FAILURE(rc)) {
+ openavbAecpStop();
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return TRUE;
+}
+
+void openavbAvdeccStopEcp()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+ openavbAecpStop();
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+}
+
+void openavbAvdeccFindMacAddr(void)
+{
+ // Open a rawsock may be the easiest cross platform way to get the MAC address.
+ void *txSock = openavbRawsockOpen(gAvdeccCfg.ifname, FALSE, TRUE, ETHERTYPE_AVTP, 100, 1);
+ if (txSock) {
+ openavbRawsockGetAddr(txSock, gAvdeccCfg.ifmac);
+ openavbRawsockClose(txSock);
+ txSock = NULL;
+ }
+}
+
+bool openavbAvdeccAddConfiguration(openavb_tl_data_cfg_t *stream)
+{
+ bool first_time = 0;
+ // Create a new config to hold the configuration information.
+ openavb_avdecc_configuration_cfg_t *pCfg = malloc(sizeof(openavb_avdecc_configuration_cfg_t));
+ if (!pCfg) {
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ memset(pCfg, 0, sizeof(openavb_avdecc_configuration_cfg_t));
+
+ // Add a pointer to the supplied stream information.
+ pCfg->stream = stream;
+
+ // Add the new config to the end of the list of configurations.
+ if (pFirstConfigurationCfg == NULL) {
+ pFirstConfigurationCfg = pCfg;
+ } else {
+ openavb_avdecc_configuration_cfg_t *pLast = pFirstConfigurationCfg;
+ while (pLast->next != NULL) {
+ pLast = pLast->next;
+ }
+ pLast->next = pCfg;
+ }
+
+ // Create a new configuration.
+ U16 nConfigIdx = 0;
+ if (pConfiguration == NULL)
+ {
+ first_time = 1;
+ pConfiguration = openavbAemDescriptorConfigurationNew();
+ if (!openavbAemAddDescriptor(pConfiguration, OPENAVB_AEM_DESCRIPTOR_INVALID, &nConfigIdx)) {
+ AVB_LOG_ERROR("Error adding AVDECC configuration");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ }
+ // Specify a default user-friendly name to use.
+ // AVDECC_TODO - Allow the user to specify a friendly name, or use the name if the .INI file.
+ if (pCfg->friendly_name[0] == '\0') {
+ snprintf((char *) pCfg->friendly_name, OPENAVB_AEM_STRLEN_MAX, "Configuration %u", nConfigIdx);
+ }
+
+ // Save the stream information in the configuration.
+ if (!openavbAemDescriptorConfigurationInitialize(pConfiguration, nConfigIdx, pCfg)) {
+ AVB_LOG_ERROR("Error initializing AVDECC configuration");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ // Add the descriptors needed for both talkers and listeners.
+ U16 nResultIdx;
+ if (first_time)
+ {
+ openavb_aem_descriptor_avb_interface_t *pNewAvbInterface = openavbAemDescriptorAvbInterfaceNew();
+ if (!openavbAemAddDescriptor(pNewAvbInterface, nConfigIdx, &nResultIdx) ||
+ !openavbAemDescriptorAvbInterfaceInitialize(pNewAvbInterface, nConfigIdx, pCfg)) {
+ AVB_LOG_ERROR("Error adding AVDECC AVB Interface to configuration");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ openavb_aem_descriptor_audio_unit_t *pNewAudioUnit = openavbAemDescriptorAudioUnitNew();
+ if (!openavbAemAddDescriptor(pNewAudioUnit, nConfigIdx, &nResultIdx) ||
+ !openavbAemDescriptorAudioUnitInitialize(pNewAudioUnit, nConfigIdx, pCfg)) {
+ AVB_LOG_ERROR("Error adding AVDECC Audio Unit to configuration");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ }
+ else
+ {
+ openavb_aem_descriptor_audio_unit_t *pAudioUnitDescriptor =
+ (openavb_aem_descriptor_audio_unit_t *) openavbAemGetDescriptor(nConfigIdx, OPENAVB_AEM_DESCRIPTOR_AUDIO_UNIT, 0);
+ if (pAudioUnitDescriptor != NULL)
+ {
+ if (!openavbAemDescriptorAudioUnitInitialize(pAudioUnitDescriptor, nConfigIdx, pCfg)) {
+ AVB_LOG_ERROR("Error updating AVDECC Audio Unit to configuration");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ }
+ else
+ {
+ AVB_LOG_ERROR("Error getting AVDECC Audio Unit descriptor");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ }
+
+ // AVDECC_TODO: Add other descriptors as needed. Future options include:
+ // VIDEO_UNIT
+ // SENSOR_UNIT
+ // CONTROL
+
+ if (stream->role == AVB_ROLE_TALKER) {
+ gAvdeccCfg.bTalker = TRUE;
+
+ openavb_aem_descriptor_stream_io_t *pNewStreamOutput = openavbAemDescriptorStreamOutputNew();
+ if (!openavbAemAddDescriptor(pNewStreamOutput, nConfigIdx, &nResultIdx) ||
+ !openavbAemDescriptorStreamOutputInitialize(pNewStreamOutput, nConfigIdx, pCfg)) {
+ AVB_LOG_ERROR("Error adding AVDECC Stream Output to configuration");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (first_talker)
+ {
+ first_talker = 0;
+ openavb_aem_descriptor_clock_source_t *pNewClockSource = openavbAemDescriptorClockSourceNew();
+ if (!openavbAemAddDescriptor(pNewClockSource, nConfigIdx, &nResultIdx) ||
+ !openavbAemDescriptorClockSourceInitialize(pNewClockSource, nConfigIdx, pCfg)) {
+ AVB_LOG_ERROR("Error adding AVDECC Clock Source to configuration");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ openavb_aem_descriptor_clock_domain_t *pNewClockDomain = openavbAemDescriptorClockDomainNew();
+ if (!openavbAemAddDescriptor(pNewClockDomain, nConfigIdx, &nResultIdx) ||
+ !openavbAemDescriptorClockDomainInitialize(pNewClockDomain, nConfigIdx, pCfg)) {
+ AVB_LOG_ERROR("Error adding AVDECC Clock Domain to configuration");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ }
+
+ // AVDECC_TODO: Add other descriptors as needed. Future options include:
+ // JACK_INPUT
+ talker_stream_sources++;
+
+ // Add the class specific to the talker.
+ if (stream->sr_class == SR_CLASS_A) { gAvdeccCfg.bClassASupported = TRUE; }
+ if (stream->sr_class == SR_CLASS_B) { gAvdeccCfg.bClassBSupported = TRUE; }
+
+ AVB_LOG_DEBUG("AVDECC talker configuration added");
+ }
+ if (stream->role == AVB_ROLE_LISTENER) {
+ gAvdeccCfg.bListener = TRUE;
+
+ openavb_aem_descriptor_stream_io_t *pNewStreamInput = openavbAemDescriptorStreamInputNew();
+ if (!openavbAemAddDescriptor(pNewStreamInput, nConfigIdx, &nResultIdx) ||
+ !openavbAemDescriptorStreamInputInitialize(pNewStreamInput, nConfigIdx, pCfg)) {
+ AVB_LOG_ERROR("Error adding AVDECC Stream Input to configuration");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (first_listener)
+ {
+ openavb_aem_descriptor_clock_source_t *pNewClockSource = openavbAemDescriptorClockSourceNew();
+ if (!openavbAemAddDescriptor(pNewClockSource, nConfigIdx, &nResultIdx) ||
+ !openavbAemDescriptorClockSourceInitialize(pNewClockSource, nConfigIdx, pCfg)) {
+ AVB_LOG_ERROR("Error adding AVDECC Clock Source to configuration");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ openavb_aem_descriptor_clock_domain_t *pNewClockDomain = openavbAemDescriptorClockDomainNew();
+ if (!openavbAemAddDescriptor(pNewClockDomain, nConfigIdx, &nResultIdx) ||
+ !openavbAemDescriptorClockDomainInitialize(pNewClockDomain, nConfigIdx, pCfg)) {
+ AVB_LOG_ERROR("Error adding AVDECC Clock Domain to configuration");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ }
+
+ // AVDECC_TODO: Add other descriptors as needed. Future options include:
+ // JACK_OUTPUT
+ listener_stream_sources++;
+
+ // Listeners support both Class A and Class B.
+ gAvdeccCfg.bClassASupported = TRUE;
+ gAvdeccCfg.bClassBSupported = TRUE;
+
+ AVB_LOG_DEBUG("AVDECC listener configuration added");
+ }
+
+ if (first_time)
+ {
+ // Add the localized strings to the configuration.
+ if (!openavbAemDescriptorLocaleStringsHandlerAddToConfiguration(gAvdeccCfg.pAemDescriptorLocaleStringsHandler, nConfigIdx)) {
+ AVB_LOG_ERROR("Error adding AVDECC locale strings to configuration");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+////////////////////////////////
+// Public functions
+////////////////////////////////
+extern DLL_EXPORT bool openavbAvdeccInitialize()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ gAvdeccCfg.pDescriptorEntity = openavbAemDescriptorEntityNew();
+ if (!gAvdeccCfg.pDescriptorEntity) {
+ AVB_LOG_ERROR("Failed to allocate an AVDECC descriptor");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ openavbAvdeccFindMacAddr();
+
+ if (!openavbAemDescriptorEntitySet_entity_id(gAvdeccCfg.pDescriptorEntity, NULL, gAvdeccCfg.ifmac, gAvdeccCfg.avdeccId)) {
+ AVB_LOG_ERROR("Failed to set the AVDECC descriptor");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ // Create the Entity Model
+ openavbRC rc = openavbAemCreate(gAvdeccCfg.pDescriptorEntity);
+ if (IS_OPENAVB_FAILURE(rc)) {
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ // Copy the supplied non-localized strings to the descriptor.
+ openavbAemDescriptorEntitySet_entity_model_id(gAvdeccCfg.pDescriptorEntity, gAvdeccCfg.entity_model_id);
+ openavbAemDescriptorEntitySet_entity_name(gAvdeccCfg.pDescriptorEntity, gAvdeccCfg.entity_name);
+ openavbAemDescriptorEntitySet_firmware_version(gAvdeccCfg.pDescriptorEntity, gAvdeccCfg.firmware_version);
+ openavbAemDescriptorEntitySet_group_name(gAvdeccCfg.pDescriptorEntity, gAvdeccCfg.group_name);
+ openavbAemDescriptorEntitySet_serial_number(gAvdeccCfg.pDescriptorEntity, gAvdeccCfg.serial_number);
+
+ // Initialize the localized strings support.
+ gAvdeccCfg.pAemDescriptorLocaleStringsHandler = openavbAemDescriptorLocaleStringsHandlerNew();
+ if (gAvdeccCfg.pAemDescriptorLocaleStringsHandler) {
+ // Add the strings to the locale strings hander.
+ openavbAemDescriptorLocaleStringsHandlerSet_local_string(
+ gAvdeccCfg.pAemDescriptorLocaleStringsHandler, gAvdeccCfg.locale_identifier, gAvdeccCfg.vendor_name, LOCALE_STRING_VENDOR_NAME_INDEX);
+ openavbAemDescriptorLocaleStringsHandlerSet_local_string(
+ gAvdeccCfg.pAemDescriptorLocaleStringsHandler, gAvdeccCfg.locale_identifier, gAvdeccCfg.model_name, LOCALE_STRING_MODEL_NAME_INDEX);
+
+ // Have the descriptor entity reference the locale strings.
+ openavbAemDescriptorEntitySet_vendor_name(gAvdeccCfg.pDescriptorEntity, 0, LOCALE_STRING_VENDOR_NAME_INDEX);
+ openavbAemDescriptorEntitySet_model_name(gAvdeccCfg.pDescriptorEntity, 0, LOCALE_STRING_MODEL_NAME_INDEX);
+ }
+
+ gAvdeccCfg.bTalker = gAvdeccCfg.bListener = FALSE;
+
+ // Add a configuration for each talker or listener stream.
+ openavb_tl_data_cfg_t *current_stream = streamList;
+ while (current_stream != NULL) {
+ // Create a new configuration with the information from this stream.
+ if (!openavbAvdeccAddConfiguration(current_stream)) {
+ AVB_LOG_ERROR("Error adding AVDECC configuration");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ // Proceed to the next stream.
+ current_stream = current_stream->next;
+ }
+
+ if (!gAvdeccCfg.bTalker && !gAvdeccCfg.bListener) {
+ AVB_LOG_ERROR("No AVDECC Configurations -- Aborting");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ // Add non-top-level descriptors. These are independent of the configurations.
+ // STRINGS are handled by gAvdeccCfg.pAemDescriptorLocaleStringsHandler, so not included here.
+ U16 nResultIdx;
+ if (!openavbAemAddDescriptor(openavbAemDescriptorAudioClusterNew(), OPENAVB_AEM_DESCRIPTOR_INVALID, &nResultIdx)) {
+ AVB_LOG_ERROR("Error adding AVDECC Audio Cluster");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (gAvdeccCfg.bTalker) {
+ if (!openavbAemAddDescriptor(openavbAemDescriptorStreamPortOutputNew(), OPENAVB_AEM_DESCRIPTOR_INVALID, &nResultIdx)) {
+ AVB_LOG_ERROR("Error adding AVDECC Output Stream Port");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ }
+ if (gAvdeccCfg.bListener) {
+ if (!openavbAemAddDescriptor(openavbAemDescriptorStreamPortInputNew(), OPENAVB_AEM_DESCRIPTOR_INVALID, &nResultIdx)) {
+ AVB_LOG_ERROR("Error adding AVDECC Input Stream Port");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ }
+
+ // AVDECC_TODO: Add other descriptors as needed. Future options include:
+ // EXTERNAL_PORT_INPUT
+ // EXTERNAL_PORT_OUTPUT
+ // INTERNAL_PORT_INPUT
+ // INTERNAL_PORT_OUTPUT
+ // VIDEO_CLUSTER
+ // SENSOR_CLUSTER
+ // AUDIO_MAP
+ // VIDEO_MAP
+ // SENSOR_MAP
+
+ // Fill in the descriptor capabilities.
+ // AVDECC_TODO: Set these based on the available capabilities.
+ if (!gAvdeccCfg.bClassASupported && !gAvdeccCfg.bClassBSupported) {
+ // If the user didn't specify a traffic class, assume both are supported.
+ gAvdeccCfg.bClassASupported = gAvdeccCfg.bClassBSupported = TRUE;
+ }
+ openavbAemDescriptorEntitySet_entity_capabilities(gAvdeccCfg.pDescriptorEntity,
+ OPENAVB_ADP_ENTITY_CAPABILITIES_AEM_SUPPORTED |
+ (gAvdeccCfg.bClassASupported ? OPENAVB_ADP_ENTITY_CAPABILITIES_CLASS_A_SUPPORTED : 0) |
+ (gAvdeccCfg.bClassBSupported ? OPENAVB_ADP_ENTITY_CAPABILITIES_CLASS_B_SUPPORTED : 0) |
+ OPENAVB_ADP_ENTITY_CAPABILITIES_GPTP_SUPPORTED);
+
+ if (gAvdeccCfg.bTalker) {
+ // AVDECC_TODO: Set these based on the available capabilities.
+ openavbAemDescriptorEntitySet_talker_capabilities(gAvdeccCfg.pDescriptorEntity, talker_stream_sources,
+ OPENAVB_ADP_TALKER_CAPABILITIES_IMPLEMENTED |
+ OPENAVB_ADP_TALKER_CAPABILITIES_AUDIO_SOURCE |
+ OPENAVB_ADP_TALKER_CAPABILITIES_MEDIA_CLOCK_SOURCE);
+ }
+ if (gAvdeccCfg.bListener) {
+ // AVDECC_TODO: Set these based on the available capabilities.
+ openavbAemDescriptorEntitySet_listener_capabilities(gAvdeccCfg.pDescriptorEntity, listener_stream_sources,
+ OPENAVB_ADP_LISTENER_CAPABILITIES_IMPLEMENTED |
+ OPENAVB_ADP_LISTENER_CAPABILITIES_AUDIO_SINK);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return TRUE;
+}
+
+// Start the AVDECC protocols.
+extern DLL_EXPORT bool openavbAvdeccStart()
+{
+ if (!openavbAvdeccStartCmp()) {
+ AVB_LOG_ERROR("openavbAvdeccStartCmp() failure!");
+ return FALSE;
+ }
+ if (!openavbAvdeccStartEcp()) {
+ AVB_LOG_ERROR("openavbAvdeccStartEcp() failure!");
+ return FALSE;
+ }
+ if (!openavbAvdeccStartAdp()) {
+ AVB_LOG_ERROR("openavbAvdeccStartAdp() failure!");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// Stop the AVDECC protocols.
+extern DLL_EXPORT void openavbAvdeccStop(void)
+{
+ openavbAvdeccStopCmp();
+ openavbAvdeccStopEcp();
+ openavbAvdeccStopAdp();
+}
+
+extern DLL_EXPORT bool openavbAvdeccCleanup(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ openavbRC rc = openavbAemDestroy();
+
+ while (pFirstConfigurationCfg) {
+ openavb_avdecc_configuration_cfg_t *pDel = pFirstConfigurationCfg;
+ pFirstConfigurationCfg = pFirstConfigurationCfg->next;
+ free(pDel);
+ }
+
+ if (IS_OPENAVB_FAILURE(rc)) {
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/avdecc/openavb_avdecc.h b/lib/avtp_pipeline/avdecc/openavb_avdecc.h
new file mode 100644
index 00000000..6c32b7e4
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc/openavb_avdecc.h
@@ -0,0 +1,210 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AVDECC - Top level 1722.1 implementation
+ * MODULE SUMMARY : Top level 1722.1 implementation
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_AVDECC_H
+#define OPENAVB_AVDECC_H 1
+
+#include "openavb_platform.h"
+
+#include "openavb_avdecc_pub.h"
+#include "openavb_avdecc_osal.h"
+#include "openavb_types.h"
+#include "openavb_trace.h"
+
+#ifndef DATA_ALIGNMENT_ADJUSTMENT
+// No Data alignment precaution needed.
+
+// Octet based data 2 buffer macros
+#define OCT_D2BMEMCP(d, s) {size_t data_size = sizeof(s); memcpy(d, s, data_size); d += data_size;} // Uses data_size variable to avoid compiler warnings
+#define OCT_D2BBUFCP(d, s, len) memcpy(d, s, len); d += len;
+#define OCT_D2BHTONB(d, s) *(U8 *)(d) = s; d += sizeof(s);
+#define OCT_D2BHTONS(d, s) *(U16 *)(d) = htons(s); d += sizeof(s);
+#define OCT_D2BHTONL(d, s) *(U32 *)(d) = htonl(s); d += sizeof(s);
+
+// Bit based data 2 buffer macros
+#define BIT_D2BHTONB(d, s, shf, inc) *(U8 *)(d) |= s << shf; d += inc;
+#define BIT_D2BHTONS(d, s, shf, inc) *(U16 *)(d) |= htons((U16)(s << shf)); d += inc;
+#define BIT_D2BHTONL(d, s, shf, inc) *(U32 *)(d) |= htonl((U32)(s << shf)); d += inc;
+
+
+// Octet based buffer 2 data macros
+#define OCT_B2DMEMCP(d, s) {size_t data_size = sizeof(d); memcpy(d, s, data_size); s += data_size;} // Uses data_size variable to avoid compiler warnings
+#define OCT_B2DBUFCP(d, s, len) memcpy(d, s, len); s += len;
+#define OCT_B2DNTOHB(d, s) d = *(U8 *)(s); s += sizeof(d);
+#define OCT_B2DNTOHS(d, s) d = ntohs(*(U16 *)(s)); s += sizeof(d);
+#define OCT_B2DNTOHL(d, s) d = ntohl(*(U32 *)(s)); s += sizeof(d);
+
+// Bit based buffer 2 data macros
+#define BIT_B2DNTOHB(d, s, msk, shf, inc) d = (*(U8 *)(s) & (U8)msk) >> shf; s += inc;
+#define BIT_B2DNTOHS(d, s, msk, shf, inc) d = (ntohs(*(U16 *)(s)) & (U16)msk) >> shf; s += inc;
+#define BIT_B2DNTOHL(d, s, msk, shf, inc) d = (ntohl(*(U32 *)(s)) & (U32)msk) >> shf; s += inc;
+
+#else
+// Data alignment precaution needed.
+
+// Octet based data 2 buffer macros
+#define OCT_D2BMEMCP(d, s) {size_t data_size = sizeof(s); memcpy(d, s, data_size); d += data_size;} // Uses data_size variable to avoid compiler warnings
+
+#define OCT_D2BBUFCP(d, s, len) memcpy(d, s, len); d += len;
+
+//#define OCT_D2BHTONB(d, s) *(U8 *)(d) = s; d += sizeof(s);
+#define OCT_D2BHTONB(d, s) \
+{ \
+memcpy(d, &s, sizeof(U8)); \
+d += sizeof(U8); \
+}
+
+//#define OCT_D2BHTONS(d, s) *(U16 *)(d) = htons(s); d += sizeof(s);
+#define OCT_D2BHTONS(d, s) \
+{ \
+U16 sAlign16 = s; \
+sAlign16 = htons(sAlign16); \
+memcpy(d, &sAlign16, sizeof(U16)); \
+d += sizeof(U16); \
+}
+
+//#define OCT_D2BHTONL(d, s) *(U32 *)(d) = htonl(s); d += sizeof(s);
+#define OCT_D2BHTONL(d, s) \
+{ \
+U32 sAlign32 = s; \
+sAlign32 = htonl(sAlign32); \
+memcpy(d, &sAlign32, sizeof(U32)); \
+d += sizeof(U32); \
+}
+
+// Bit based data 2 buffer macros
+//#define BIT_D2BHTONB(d, s, shf, inc) *(U8 *)(d) |= s << shf; d += inc;
+#define BIT_D2BHTONB(d, s, shf, inc) \
+{ \
+U8 sAlign8 = s << shf; \
+U8 dAlign8; \
+memcpy(&dAlign8, d, sizeof(U8)); \
+dAlign8 |= sAlign8; \
+memcpy(d, &dAlign8, sizeof(U8)); \
+d += inc; \
+}
+
+//#define BIT_D2BHTONS(d, s, shf, inc) *(U16 *)(d) |= htons((U16)(s << shf)); d += inc;
+#define BIT_D2BHTONS(d, s, shf, inc) \
+{ \
+U16 sAlign16 = htons((U16)(s << shf)); \
+U16 dAlign16; \
+memcpy(&dAlign16, d, sizeof(U16)); \
+dAlign16 |= sAlign16; \
+memcpy(d, &dAlign16, sizeof(U16)); \
+d += inc; \
+}
+
+//#define BIT_D2BHTONL(d, s, shf, inc) *(U32 *)(d) |= htonl((U32)(s << shf)); d += inc;
+#define BIT_D2BHTONL(d, s, shf, inc) \
+{ \
+U32 sAlign32 = htonl((U32)(s << shf)); \
+U32 dAlign32; \
+memcpy(&dAlign32, d, sizeof(U32)); \
+dAlign32 |= sAlign32; \
+memcpy(d, &dAlign32, sizeof(U32)); \
+d += inc; \
+}
+
+
+// Octet based buffer 2 data macros
+#define OCT_B2DMEMCP(d, s) {size_t data_size = sizeof(d); memcpy(d, s, data_size); s += data_size;} // Uses data_size variable to avoid compiler warnings
+
+#define OCT_B2DBUFCP(d, s, len) memcpy(d, s, len); s += len;
+
+//#define OCT_B2DNTOHB(d, s) d = *(U8 *)(s); s += sizeof(d);
+#define OCT_B2DNTOHB(d, s) \
+{ \
+memcpy(&d, s, sizeof(U8)); \
+s += sizeof(U8); \
+}
+
+//#define OCT_B2DNTOHS(d, s) d = ntohs(*(U16 *)(s)); s += sizeof(d);
+#define OCT_B2DNTOHS(d, s) \
+{ \
+U16 sAlign16; \
+memcpy(&sAlign16, s, sizeof(U16)); \
+sAlign16 = ntohs(sAlign16); \
+memcpy(&d, &sAlign16, sizeof(U16)); \
+s += sizeof(U16); \
+}
+
+//#define OCT_B2DNTOHL(d, s) d = ntohl(*(U32 *)(s)); s += sizeof(d);
+#define OCT_B2DNTOHL(d, s) \
+{ \
+U32 sAlign32; \
+memcpy(&sAlign32, s, sizeof(U32)); \
+sAlign32 = ntohl(sAlign32); \
+memcpy(&d, &sAlign32, sizeof(U32)); \
+s += sizeof(U32); \
+}
+
+// Bit based buffer 2 data macros
+//#define BIT_B2DNTOHB(d, s, msk, shf, inc) d = (*(U8 *)(s) & (U8)msk) >> shf; s += inc;
+#define BIT_B2DNTOHB(d, s, msk, shf, inc) \
+{ \
+U8 sAlign8; \
+memcpy(&sAlign8, s, sizeof(U8)); \
+sAlign8 = (sAlign8 & (U8)msk) >>shf; \
+memcpy(&d, &sAlign8, sizeof(U8)); \
+s += inc; \
+}
+
+//#define BIT_B2DNTOHS(d, s, msk, shf, inc) d = (ntohs(*(U16 *)(s)) & (U16)msk) >> shf; s += inc;
+#define BIT_B2DNTOHS(d, s, msk, shf, inc) \
+{ \
+U16 sAlign16; \
+memcpy(&sAlign16, s, sizeof(U16)); \
+sAlign16 = (ntohs(sAlign16) & (U16)msk) >> shf; \
+memcpy(&d, &sAlign16, sizeof(U16)); \
+s += inc; \
+}
+
+//#define BIT_B2DNTOHL(d, s, msk, shf, inc) d = (ntohl(*(U32 *)(s)) & (U32)msk) >> shf; s += inc;
+#define BIT_B2DNTOHL(d, s, msk, shf, inc) \
+{ \
+U32 sAlign32; \
+memcpy(&sAlign32, s, sizeof(U32)); \
+sAlign32 = (ntohs(sAlign32) & (U32)msk) >> shf; \
+memcpy(&d, &sAlign32, sizeof(U32)); \
+s += inc; \
+}
+
+#endif
+
+#endif // OPENAVB_AVDECC_H
diff --git a/lib/avtp_pipeline/avdecc/openavb_avdecc_pipeline_interaction_pub.h b/lib/avtp_pipeline/avdecc/openavb_avdecc_pipeline_interaction_pub.h
new file mode 100644
index 00000000..c7edac96
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc/openavb_avdecc_pipeline_interaction_pub.h
@@ -0,0 +1,71 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#ifndef OPENAVB_AVDECC_PIPELINE_INTERACTION_PUB_H
+#define OPENAVB_AVDECC_PIPELINE_INTERACTION_PUB_H 1
+
+#include "openavb_acmp.h"
+#include "openavb_descriptor_stream_io_pub.h"
+#include "openavb_avdecc_msg.h"
+
+
+// Run a single talker or listener.
+bool openavbAVDECCRunListener(openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput, U16 configIdx, openavb_acmp_ListenerStreamInfo_t *pListenerStreamInfo);
+bool openavbAVDECCRunTalker(openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput, U16 configIdx, openavb_acmp_TalkerStreamInfo_t *pTalkerStreamInfo);
+
+// Stop a single talker or listener.
+bool openavbAVDECCStopListener(openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput, U16 configIdx, openavb_acmp_ListenerStreamInfo_t *pListenerStreamInfo);
+bool openavbAVDECCStopTalker(openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput, U16 configIdx, openavb_acmp_TalkerStreamInfo_t *pTalkerStreamInfo);
+
+// Get talker stream details. Structure members in TalkerStreamInfo will be filled.
+bool openavbAVDECCGetTalkerStreamInfo(openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput, U16 configIdx, openavb_acmp_TalkerStreamInfo_t *pTalkerStreamInfo);
+
+// Set talker stream details. The settings will be passed to the Talker to use for future connections
+bool openavbAVDECCSetTalkerStreamInfo(
+ openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput,
+ U8 sr_class,
+ U8 stream_id_valid, const U8 stream_src_mac[6], U16 stream_uid,
+ U8 stream_dest_valid, const U8 stream_dest_mac[6],
+ U8 stream_vlan_id_valid, U16 stream_vlan_id);
+
+// Get the streaming state (stopped, running, paused, etc.) AVDECC told the talker or listener to use.
+openavbAvdeccMsgStateType_t openavbAVDECCGetRequestedState(openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput, U16 configIdx);
+
+// Get the streaming state (stopped, running, paused, etc.) last reported by the talker or listener.
+openavbAvdeccMsgStateType_t openavbAVDECCGetStreamingState(openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput, U16 configIdx);
+
+// Pause or resume the stream.
+void openavbAVDECCPauseStream(openavb_aem_descriptor_stream_io_t *pDescriptor, bool bPause);
+
+// Get the current counter value in pValue. Returns TRUE if the counter is supported, FALSE otherwise.
+bool openavbAVDECCGetCounterValue(void *pDescriptor, U16 descriptorType, U32 counterFlag, U32 *pValue);
+
+#endif // OPENAVB_AVDECC_PIPELINE_INTERACTION_PUB_H
diff --git a/lib/avtp_pipeline/avdecc/openavb_avdecc_pub.h b/lib/avtp_pipeline/avdecc/openavb_avdecc_pub.h
new file mode 100644
index 00000000..803438ed
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc/openavb_avdecc_pub.h
@@ -0,0 +1,145 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ ******************************************************************
+ * MODULE : AVDECC - Top level AVDECC (1722.1) Public Interface
+ * MODULE SUMMARY : Top level AVDECC (1722.1) Public Interface
+ ******************************************************************
+ */
+
+#ifndef OPENAVB_AVDECC_PUB_H
+#define OPENAVB_AVDECC_PUB_H 1
+
+// Entity Model public includes
+#include "openavb_aem_pub.h"
+#include "openavb_descriptor_entity_pub.h"
+#include "openavb_descriptor_configuration_pub.h"
+#include "openavb_descriptor_audio_unit_pub.h"
+#include "openavb_descriptor_stream_io_pub.h"
+#include "openavb_descriptor_jack_io_pub.h"
+#include "openavb_descriptor_avb_interface_pub.h"
+#include "openavb_descriptor_clock_source_pub.h"
+#include "openavb_descriptor_locale_pub.h"
+#include "openavb_descriptor_strings_pub.h"
+#include "openavb_descriptor_control_pub.h"
+#include "openavb_descriptor_stream_port_io_pub.h"
+#include "openavb_descriptor_external_port_io_pub.h"
+#include "openavb_descriptor_audio_cluster_pub.h"
+#include "openavb_descriptor_audio_map_pub.h"
+#include "openavb_descriptor_clock_domain_pub.h"
+#include "openavb_descriptor_locale_strings_handler_pub.h"
+
+// Discovery protocol public includes
+#include "openavb_adp_pub.h"
+
+// Connection management public includes
+#include "openavb_acmp_pub.h"
+
+// Enumeration and control public includes
+#include "openavb_aecp_pub.h"
+
+// openavb_tl_data_cfg_t definition
+#include "openavb_avdecc_read_ini_pub.h"
+
+#ifndef IFNAMSIZ
+#define IFNAMSIZ 16
+#endif
+#ifndef ETH_ALEN
+#define ETH_ALEN 6
+#endif
+
+// Indexes for localized strings.
+// (These are defined for internal use, and can be changed as needed.)
+#define LOCALE_STRING_VENDOR_NAME_INDEX 0
+#define LOCALE_STRING_MODEL_NAME_INDEX 1
+
+typedef struct {
+
+ char ifname[IFNAMSIZ + 10]; // Include space for the socket type prefix (e.g. "simple:eth0")
+ U8 ifmac[ETH_ALEN];
+
+ bool bListener;
+ bool bTalker;
+ bool bClassASupported;
+ bool bClassBSupported;
+
+ U16 vlanID;
+ U8 vlanPCP;
+
+ bool bFastConnectSupported; // FAST_CONNECT and SAVED_STATE supported
+
+ U8 valid_time; // Number of 2-second units
+
+ // Information to add to the descriptor.
+ unsigned avdeccId;
+ U8 entity_model_id[8];
+ char entity_name[OPENAVB_AEM_STRLEN_MAX];
+ char firmware_version[OPENAVB_AEM_STRLEN_MAX];
+ char group_name[OPENAVB_AEM_STRLEN_MAX];
+ char serial_number[OPENAVB_AEM_STRLEN_MAX];
+
+ // Localization strings.
+ char locale_identifier[OPENAVB_AEM_STRLEN_MAX];
+ char vendor_name[OPENAVB_AEM_STRLEN_MAX];
+ char model_name[OPENAVB_AEM_STRLEN_MAX];
+
+ openavb_aem_descriptor_entity_t *pDescriptorEntity;
+ openavb_aem_descriptor_locale_strings_handler_t *pAemDescriptorLocaleStringsHandler;
+} openavb_avdecc_cfg_t;
+
+typedef struct openavb_avdecc_configuration_cfg {
+ struct openavb_avdecc_configuration_cfg *next; // next link list pointer
+
+ // Pointer to the endpoint information.
+ openavb_tl_data_cfg_t *stream;
+
+ // Friendly name
+ char friendly_name[OPENAVB_AEM_STRLEN_MAX];
+
+ // AVDECC_TODO: Add additional information as needed.
+
+} openavb_avdecc_configuration_cfg_t;
+
+
+// General initialization for AVDECC. This must be called before any other AVDECC APIs including AEM APIs
+bool openavbAvdeccInitialize(void);
+
+// Start the AVDECC protocols.
+bool openavbAvdeccStart(void);
+
+// Stop the AVDECC protocols.
+void openavbAvdeccStop(void);
+
+// General Cleanup for AVDECC.
+bool openavbAvdeccCleanup(void);
+
+#endif // OPENAVB_AVDECC_PUB_H
diff --git a/lib/avtp_pipeline/avdecc/openavb_avdecc_read_ini_pub.h b/lib/avtp_pipeline/avdecc/openavb_avdecc_read_ini_pub.h
new file mode 100644
index 00000000..5c71d5b7
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc/openavb_avdecc_read_ini_pub.h
@@ -0,0 +1,197 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+* HEADER SUMMARY : AVDECC Read INI Public Interface
+*/
+
+#ifndef OPENAVB_AVDECC_READ_INI_PUB_H
+#define OPENAVB_AVDECC_READ_INI_PUB_H 1
+
+#include "openavb_types_pub.h"
+#include "openavb_mediaq_pub.h"
+#include "openavb_avtp_time_pub.h"
+#include "openavb_tl_pub.h"
+
+#define MAX_SAMPLING_RATES_COUNT 91
+
+/** \file
+ * AVDECC Read INI Public Interface.
+ */
+
+struct _avdecc_msg_state;
+typedef struct _avdecc_msg_state avdecc_msg_state_t;
+
+/// Maximum size of the friendly name
+#define FRIENDLY_NAME_SIZE 64
+
+/// Structure containing configuration of the host
+struct openavb_tl_data_cfg {
+ struct openavb_tl_data_cfg *next;
+
+ /// Role of the host
+ avb_role_t role;
+ /// Initial Talker/Listener state
+ tl_init_state_t initial_state;
+ /// MAC address of destination - multicast (talker only if SRP is enabled)
+ cfg_mac_t dest_addr;
+ /// MAC address of the source
+ cfg_mac_t stream_addr;
+ /// Stream UID (has to be unique)
+ U16 stream_uid;
+ /// Maximum number of packets sent during one interval (talker only)
+ U32 max_interval_frames;
+ /// Maximum size of the frame
+ U32 max_frame_size;
+ /// Setting maximum transit time, on talker value is added to PTP Walltime,
+ /// on listener value is validated timestamp range
+ U32 max_transit_usec;
+ /// Maximum transmit deficit in usec - should be set to expected buffer size
+ /// on the listener side (talker only)
+ U32 max_transmit_deficit_usec;
+ /// Specify manual an internal latency (talker only)
+ U32 internal_latency;
+ /// Number of microseconds after which late MediaQItem will be purged as too
+ /// old (listener only)
+ U32 max_stale;
+ /// Number of intervals to handle at once (talker only)
+ U32 batch_factor;
+ /// Statistics reporting frequency
+ U32 report_seconds;
+ /// Start paused
+ bool start_paused;
+ /// Class in which host will operate ::SRClassIdx_t (talker only)
+ U8 sr_class;
+ /// Rank of the stream #SR_RANK_REGULAR or #SR_RANK_EMERGENCY (talker only)
+ U8 sr_rank;
+ /// Number of raw TX buffers that should be used (talker only)
+ U32 raw_tx_buffers;
+ /// Number of raw RX buffers (listener only)
+ U32 raw_rx_buffers;
+ /// Is the interface module blocking in the TX CB.
+ bool tx_blocking_in_intf;
+ /// VLAN ID
+ U16 vlan_id;
+ /// When set incoming packets will trigger a signal to the stream task to wakeup.
+ bool rx_signal_mode;
+ /// Enable fixed timestamping in interface
+ U32 fixed_timestamp;
+ /// Wait for next observation interval by spinning rather than sleeping
+ bool spin_wait;
+ /// Bit mask used for CPU pinning
+ U32 thread_affinity;
+ /// Real time priority of thread.
+ U32 thread_rt_priority;
+ /// The current sample rate of this Audio Unit
+ U32 current_sampling_rate;
+ /// The number of sample rates in the sampling_rates field.
+ U16 sampling_rates_count;
+ /// An array of 4-octet sample rates supported by this Audio Unit
+ U32 sampling_rates[MAX_SAMPLING_RATES_COUNT];
+ /// intf_nv_audio_rate
+ U16 audioRate;
+ /// intf_nv_audio_bit_depth
+ U8 audioBitDepth;
+ /// intf_nv_channels
+ U8 audioChannels;
+ /// Friendly name for this configuration
+ char friendly_name[FRIENDLY_NAME_SIZE];
+ /// The name of the initialize function in the mapper
+ char map_fn[100];
+
+ // Pointer to the client Talker/Listener.
+ // Do not free this item; it is for reference only.
+ const avdecc_msg_state_t * client;
+};
+
+typedef struct openavb_tl_data_cfg openavb_tl_data_cfg_t;
+
+
+/** Read an ini file.
+ *
+ * Parses an input configuration file to populate configuration structures, and
+ * name value pairs. Only used in Operating Systems that have a file system
+ *
+ * \param fileName Pointer to configuration file name
+ * \param pCfg Pointer to configuration structure
+ * \return TRUE on success or FALSE on failure
+ *
+ * \warning Not available on all platforms
+ */
+bool openavbReadTlDataIniFile(const char *fileName, openavb_tl_data_cfg_t *pCfg);
+
+
+/** Save the connection to the saved state
+ *
+ * If fast connect support is enabled, this function is used to save the state
+ * of the connection by a Listener when a connection is successfully made to
+ * a Talker for possible fast connect support later.
+ * #openavbAvdeccClearSavedState() should be called when the connection is closed.
+ *
+ * \param pListener Pointer to configuration for the Listener
+ * \param flags The flags used for the connection (CLASS_B, SUPPORTS_ENCRYPTED, ENCRYPTED_PDU)
+ * \param talker_unique_id The unique id for the Talker
+ * \param talker_entity_id The binary entity id for the Talker
+ * \param controller_entity_id The binary entity id for the Controller that initiated the connection
+ *
+ * \return TRUE on success or FALSE on failure
+ */
+bool openavbAvdeccSaveState(const openavb_tl_data_cfg_t *pListener, U16 flags, U16 talker_unique_id, const U8 talker_entity_id[8], const U8 controller_entity_id[8]);
+
+/** Delete a connection with saved state
+ *
+ * If fast connect support is enabled, this function is used to clear previously
+ * saved state information (from a previous call to #openavbAvdeccSaveState).
+ * This function should be called from the Listener when a Talker/Listener connection is closed
+ * (and fast connects should no longer be attempted in the future).
+ *
+ * \param pListener Pointer to configuration for the Listener
+ *
+ * \return TRUE on success or FALSE on failure
+ */
+bool openavbAvdeccClearSavedState(const openavb_tl_data_cfg_t *pListener);
+
+/** Determine if the connection has a saved state
+ *
+ * If fast connect support is enabled, this function is used to get the last
+ * saved state (from a call to #openavbAvdeccSaveState) for a Listener, if any.
+ *
+ * \param pListener Pointer to configuration for the Listener
+ * \param p_flags Optional pointer to the flags used for the connection (CLASS_B, SUPPORTS_ENCRYPTED, ENCRYPTED_PDU)
+ * \param p_talker_unique_id Optional pointer to the unique id for the Talker
+ * \param p_talker_entity_id Optional pointer to the buffer to fill in the binary entity id for the Talker
+ * \param p_controller_entity_id Optional pointer to the buffer to fill in the binary entity id for the Controller that initiated the connection
+ *
+ * \return TRUE if there is a saved state, or FALSE otherwise
+ */
+bool openavbAvdeccGetSaveStateInfo(const openavb_tl_data_cfg_t *pListener, U16 *p_flags, U16 *p_talker_unique_id, U8 (*p_talker_entity_id)[8], U8 (*p_controller_entity_id)[8]);
+
+#endif // OPENAVB_AVDECC_READ_INI_PUB_H
diff --git a/lib/avtp_pipeline/avdecc/shutdown_openavb_avdecc.sh b/lib/avtp_pipeline/avdecc/shutdown_openavb_avdecc.sh
new file mode 100755
index 00000000..352e5433
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc/shutdown_openavb_avdecc.sh
@@ -0,0 +1,18 @@
+#! /bin/sh
+#
+# AVB AVDECC clean-up script
+#
+# Only needs to be run if the AVDECC process crashes.
+#
+# Removes resources created/loaded by AVDECC, so that a new
+# instance can run.
+
+IFACES=$(cat /proc/net/dev | grep -- : | cut -d: -f1)
+
+echo "removing AVDECC resources"
+
+killall -s SIGINT openavb_avdecc > /dev/null 2>&1
+killall -s SIGINT openavb_harness > /dev/null 2>&1
+killall -s SIGINT openavb_host > /dev/null 2>&1
+rm -f /tmp/avdecc_msg > /dev/null 2>&1
+
diff --git a/lib/avtp_pipeline/avdecc_msg/CMakeLists.txt b/lib/avtp_pipeline/avdecc_msg/CMakeLists.txt
new file mode 100644
index 00000000..139597f9
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc_msg/CMakeLists.txt
@@ -0,0 +1,2 @@
+
+
diff --git a/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg.c b/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg.c
new file mode 100644
index 00000000..f599ecf7
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg.c
@@ -0,0 +1,192 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ * MODULE SUMMARY :
+ *
+ * Stream clients (talkers or listeners) must connect to the central
+ * "avdecc_msg" process to create a reservation for their traffic.
+ *
+ * This code implements functions used by both sides of the IPC.
+ */
+
+
+// We are accessed from multiple threads, so need a mutex
+MUTEX_HANDLE(gAvdeccMsgStateMutex);
+
+static avdecc_msg_state_t *gAvdeccMsgStateList[MAX_AVDECC_MSG_CLIENTS] = { 0 };
+static int nNumInitialized = 0;
+
+EXTERN_DLL_EXPORT bool openavbAvdeccMsgInitialize(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ if (nNumInitialized++ == 0) {
+ MUTEX_ATTR_HANDLE(mta);
+ MUTEX_ATTR_INIT(mta);
+ MUTEX_ATTR_SET_TYPE(mta, MUTEX_ATTR_TYPE_DEFAULT);
+ MUTEX_ATTR_SET_NAME(mta, "gAvdeccMsgStateMutex");
+ MUTEX_CREATE_ERR();
+ MUTEX_CREATE(gAvdeccMsgStateMutex, mta);
+ MUTEX_LOG_ERR("Error creating mutex");
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return TRUE;
+}
+
+// General cleanup of the talker and listener library. Should be called after all Talker and Listeners are closed.
+EXTERN_DLL_EXPORT bool openavbAvdeccMsgCleanup()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ if (--nNumInitialized <= 0) {
+ nNumInitialized = 0;
+
+ if (AvdeccMsgStateListGetIndex(0)) {
+ AVB_LOG_WARNING("AvdeccMsgStateList not empty on exit");
+ }
+
+ MUTEX_CREATE_ERR();
+ MUTEX_DESTROY(gAvdeccMsgStateMutex);
+ MUTEX_LOG_ERR("Error destroying mutex");
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return TRUE;
+}
+
+
+bool AvdeccMsgStateListAdd(avdecc_msg_state_t * pState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ if (!pState) {
+ AVB_LOG_ERROR("AvdeccMsgStateListAdd invalid param");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return FALSE;
+ }
+
+ AVDECC_MSG_LOCK();
+ int i1;
+ for (i1 = 0; i1 < MAX_AVDECC_MSG_CLIENTS; i1++) {
+ if (!gAvdeccMsgStateList[i1]) {
+ gAvdeccMsgStateList[i1] = pState;
+ AVDECC_MSG_UNLOCK();
+ AVB_LOGF_DEBUG("AvdeccMsgStateListAdd %d succeeded", pState->avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return TRUE;
+ }
+ }
+ AVDECC_MSG_UNLOCK();
+ AVB_LOGF_WARNING("AvdeccMsgStateListAdd %d out of space", pState->avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return FALSE;
+}
+
+bool AvdeccMsgStateListRemove(avdecc_msg_state_t * pState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ if (!pState) {
+ AVB_LOG_ERROR("AvdeccMsgStateListRemove invalid param");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return FALSE;
+ }
+
+ AVDECC_MSG_LOCK();
+ int i1;
+ for (i1 = 0; i1 < MAX_AVDECC_MSG_CLIENTS; i1++) {
+ if (gAvdeccMsgStateList[i1] == pState) {
+ gAvdeccMsgStateList[i1] = NULL;
+ AVDECC_MSG_UNLOCK();
+ AVB_LOGF_DEBUG("AvdeccMsgStateListRemove %d succeeded", pState->avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return TRUE;
+ }
+ }
+ AVDECC_MSG_UNLOCK();
+ AVB_LOGF_WARNING("AvdeccMsgStateListRemove %d not found", pState->avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return FALSE;
+}
+
+avdecc_msg_state_t * AvdeccMsgStateListGet(int avdeccMsgHandle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ if (!avdeccMsgHandle) {
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ AVB_LOG_ERROR("AvdeccMsgStateListGet invalid param");
+ return NULL;
+ }
+
+ AVDECC_MSG_LOCK();
+ int i1;
+ for (i1 = 0; i1 < MAX_AVDECC_MSG_CLIENTS; i1++) {
+ if (gAvdeccMsgStateList[i1]) {
+ avdecc_msg_state_t *pState = (avdecc_msg_state_t *)gAvdeccMsgStateList[i1];
+ if (pState->avdeccMsgHandle == avdeccMsgHandle) {
+ AVDECC_MSG_UNLOCK();
+ AVB_LOGF_DEBUG("AvdeccMsgStateListGet found index %d, handle %d", i1, pState->avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return pState;
+ }
+ }
+ }
+ AVDECC_MSG_UNLOCK();
+ AVB_LOGF_DEBUG("AvdeccMsgStateListGet %d not found", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return NULL;
+}
+
+avdecc_msg_state_t * AvdeccMsgStateListGetIndex(int nIndex)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ AVDECC_MSG_LOCK();
+ int i1, found = 0;
+ for (i1 = 0; i1 < MAX_AVDECC_MSG_CLIENTS; i1++) {
+ if (gAvdeccMsgStateList[i1]) {
+ if (found++ == nIndex) {
+ avdecc_msg_state_t *pState = (avdecc_msg_state_t *)gAvdeccMsgStateList[i1];
+ AVDECC_MSG_UNLOCK();
+ AVB_LOGF_DEBUG("AvdeccMsgStateListGetIndex found index %d, handle %d for supplied index %d", i1, pState->avdeccMsgHandle, nIndex);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return pState;
+ }
+ }
+ }
+ AVDECC_MSG_UNLOCK();
+ AVB_LOGF_DEBUG("AvdeccMsgStateListGetIndex no match for index %d", nIndex);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return NULL;
+}
diff --git a/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg.h b/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg.h
new file mode 100644
index 00000000..5efd90d2
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg.h
@@ -0,0 +1,216 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+* HEADER SUMMARY : Declarations used by the AVDECC message code.
+*/
+
+#ifndef OPENAVB_AVDECC_MSG_H
+#define OPENAVB_AVDECC_MSG_H
+
+#include "openavb_types.h"
+
+#define AVB_AVDECC_MSG_HANDLE_INVALID (-1)
+#define AVDECC_MSG_RECONNECT_SECONDS 10
+#define AVB_AVDECC_MSG_UNIX_PATH "/tmp/avdecc_msg"
+#define MAX_AVDECC_MSG_CLIENTS 16
+
+
+////////////////
+// AVDECC Msg state mutex
+////////////////
+extern MUTEX_HANDLE(gAvdeccMsgStateMutex);
+#define AVDECC_MSG_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(gAvdeccMsgStateMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define AVDECC_MSG_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(gAvdeccMsgStateMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+
+typedef enum OPENAVB_AVDECC_MSG_VER_STATE
+{
+ OPENAVB_AVDECC_MSG_VER_UNKNOWN = 0,
+ OPENAVB_AVDECC_MSG_VER_INVALID,
+ OPENAVB_AVDECC_MSG_VER_VALID,
+} openavbAvdeccMsgVerState_t;
+
+struct _avdecc_msg_state;
+typedef struct _avdecc_msg_state avdecc_msg_state_t;
+
+
+bool openavbAvdeccMsgInitialize(void);
+bool openavbAvdeccMsgCleanup();
+
+// Functions to save the list of AVDECC Msg clients
+bool AvdeccMsgStateListAdd(avdecc_msg_state_t * pState);
+bool AvdeccMsgStateListRemove(avdecc_msg_state_t * pState);
+avdecc_msg_state_t * AvdeccMsgStateListGet(int avdeccMsgHandle);
+avdecc_msg_state_t * AvdeccMsgStateListGetIndex(int nIndex);
+
+bool openavbAvdeccMsgClntService(int socketHandle, int timeout);
+void openavbAvdeccMsgSrvrService(void);
+
+
+typedef enum {
+ OPENAVB_AVDECC_MSG_UNKNOWN = 0,
+ OPENAVB_AVDECC_MSG_STOPPED,
+ OPENAVB_AVDECC_MSG_STOPPED_UNEXPECTEDLY,
+ OPENAVB_AVDECC_MSG_RUNNING,
+ OPENAVB_AVDECC_MSG_PAUSED,
+} openavbAvdeccMsgStateType_t;
+
+typedef enum {
+ // Client-to-Server messages
+ OPENAVB_AVDECC_MSG_VERSION_REQUEST,
+ OPENAVB_AVDECC_MSG_CLIENT_INIT_IDENTIFY,
+ OPENAVB_AVDECC_MSG_C2S_TALKER_STREAM_ID,
+ OPENAVB_AVDECC_MSG_CLIENT_CHANGE_NOTIFICATION,
+
+ // Server-to-Client messages
+ OPENAVB_AVDECC_MSG_VERSION_CALLBACK,
+ OPENAVB_AVDECC_MSG_LISTENER_STREAM_ID,
+ OPENAVB_AVDECC_MSG_S2C_TALKER_STREAM_ID,
+ OPENAVB_AVDECC_MSG_CLIENT_CHANGE_REQUEST,
+} openavbAvdeccMsgType_t;
+
+//////////////////////////////
+// Client-to-Server message parameters
+//////////////////////////////
+typedef struct {
+} openavbAvdeccMsgParams_VersionRequest_t;
+
+typedef struct {
+ char friendly_name[FRIENDLY_NAME_SIZE];
+ U8 talker;
+} openavbAvdeccMsgParams_ClientInitIdentify_t;
+
+typedef struct {
+ U8 sr_class; // SR_CLASS_A or SR_CLASS_B
+ U8 stream_src_mac[6]; // MAC Address for the Talker
+ U16 stream_uid; // Stream ID value
+ U8 stream_dest_mac[6]; // Multicast address for the stream
+ U16 stream_vlan_id; // VLAN ID of the stream
+} openavbAvdeccMsgParams_C2S_TalkerStreamID_t;
+
+typedef struct {
+ U8 current_state; // Convert to openavbAvdeccMsgStateType_t
+} openavbAvdeccMsgParams_ClientChangeNotification_t;
+
+//////////////////////////////
+// Server-to-Client messages parameters
+//////////////////////////////
+typedef struct {
+ U32 AVBVersion;
+} openavbAvdeccMsgParams_VersionCallback_t;
+
+typedef struct {
+ U8 sr_class; // SR_CLASS_A or SR_CLASS_B
+ U8 stream_src_mac[6]; // MAC Address for the Talker
+ U16 stream_uid; // Stream ID value
+ U8 stream_dest_mac[6]; // Multicast address for the stream
+ U16 stream_vlan_id; // VLAN ID of the stream
+} openavbAvdeccMsgParams_ListenerStreamID_t;
+
+typedef struct {
+ U8 sr_class; // SR_CLASS_A or SR_CLASS_B
+ U8 stream_id_valid; // The stream_src_mac and stream_uid values were supplied
+ U8 stream_src_mac[6]; // MAC Address for the Talker
+ U16 stream_uid; // Stream ID value
+ U8 stream_dest_valid; // The stream_dest_mac value was supplied
+ U8 stream_dest_mac[6]; // Multicast address for the stream
+ U8 stream_vlan_id_valid; // The stream_vlan_id value was supplied
+ U16 stream_vlan_id; // VLAN ID of the stream
+} openavbAvdeccMsgParams_S2C_TalkerStreamID_t;
+
+typedef struct {
+ U8 desired_state; // Convert to openavbAvdeccMsgStateType_t
+} openavbAvdeccMsgParams_ClientChangeRequest_t;
+
+#define OPENAVB_AVDECC_MSG_LEN sizeof(openavbAvdeccMessage_t)
+
+bool openavbAvdeccMsgServerOpen(void);
+void openavbAvdeccMsgServerClose(void);
+
+#include "openavb_avdecc_msg_osal.h"
+
+
+/************************** AVDECC Msg Client-Server *************************/
+// There is a single AVDECC server for the entire talker/listener device
+// There is an AVDECC client for each stream.
+
+// AVDECC client open a connection to AVDECC server.
+// (Note that the server never opens a connection to the client.)
+int openavbAvdeccMsgClntOpenSrvrConnection(void);
+// AVDECC client close its connection to the server.
+void openavbAvdeccMsgClntCloseSrvrConnection(int h);
+// AVDECC server close its connection to the client.
+void openavbAvdeccMsgSrvrCloseClientConnection(int h);
+
+// Immediately after establishing connection with the AVDECC Msg server,
+// the AVDECC Msg client checks that the server's version is the same as its own.
+// The client sends a request to the client for its version.
+// The server handles the request and sends its version to the requesting client.
+// The client compares the received version to its own.
+bool openavbAvdeccMsgClntRequestVersionFromServer(int h);
+bool openavbAvdeccMsgSrvrHndlVerRqstFromClient(int h);
+void openavbAvdeccMsgSrvrSendServerVersionToClient(int h, U32 AVBVersion);
+void openavbAvdeccMsgClntCheckVerMatchesSrvr(int h, U32 AVBVersion);
+
+// Client notify the server of identity (so AVDECC Msg knows client identity)
+bool openavbAvdeccMsgClntInitIdentify(int avdeccMsgHandle, const char * friendly_name, U8 talker);
+bool openavbAvdeccMsgSrvrHndlInitIdentifyFromClient(int avdeccMsgHandle, char * friendly_name, U8 talker);
+
+// Client notify the server of the stream values the Talker will be using.
+bool openavbAvdeccMsgClntTalkerStreamID(int avdeccMsgHandle, U8 sr_class, const U8 stream_src_mac[6], U16 stream_uid, const U8 stream_dest_mac[6], U16 stream_vlan_id);
+bool openavbAvdeccMsgSrvrHndlTalkerStreamIDFromClient(int avdeccMsgHandle, U8 sr_class, const U8 stream_src_mac[6], U16 stream_uid, const U8 stream_dest_mac[6], U16 stream_vlan_id);
+
+// Server notify the client of the stream values for the Listener to use.
+bool openavbAvdeccMsgSrvrListenerStreamID(int avdeccMsgHandle, U8 sr_class, const U8 stream_src_mac[6], U16 stream_uid, const U8 stream_dest_mac[6], U16 stream_vlan_id);
+bool openavbAvdeccMsgClntHndlListenerStreamIDFromServer(int avdeccMsgHandle, U8 sr_class, const U8 stream_src_mac[6], U16 stream_uid, const U8 stream_dest_mac[6], U16 stream_vlan_id);
+
+// Server notify the client of the stream values for the Talker to use (supplied by the AVDECC controller).
+bool openavbAvdeccMsgSrvrTalkerStreamID(
+ int avdeccMsgHandle,
+ U8 sr_class,
+ U8 stream_id_valid, const U8 stream_src_mac[6], U16 stream_uid,
+ U8 stream_dest_valid, const U8 stream_dest_mac[6],
+ U8 stream_vlan_id_valid, U16 stream_vlan_id);
+bool openavbAvdeccMsgClntHndlTalkerStreamIDFromServer(
+ int avdeccMsgHandle,
+ U8 sr_class,
+ U8 stream_id_valid, const U8 stream_src_mac[6], U16 stream_uid,
+ U8 stream_dest_valid, const U8 stream_dest_mac[6],
+ U8 stream_vlan_id_valid, U16 stream_vlan_id);
+
+// Server state change requests, and client notifications of state changes.
+bool openavbAvdeccMsgSrvrChangeRequest(int avdeccMsgHandle, openavbAvdeccMsgStateType_t desiredState);
+bool openavbAvdeccMsgClntHndlChangeRequestFromServer(int avdeccMsgHandle, openavbAvdeccMsgStateType_t desiredState);
+bool openavbAvdeccMsgClntChangeNotification(int avdeccMsgHandle, openavbAvdeccMsgStateType_t currentState);
+bool openavbAvdeccMsgSrvrHndlChangeNotificationFromClient(int avdeccMsgHandle, openavbAvdeccMsgStateType_t currentState);
+
+#endif // OPENAVB_AVDECC_MSG_H
diff --git a/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_client.c b/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_client.c
new file mode 100644
index 00000000..01c827f3
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_client.c
@@ -0,0 +1,723 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+* MODULE SUMMARY :
+*
+* Stream clients (talkers or listeners) must connect to the central
+* "avdecc_msg" process to support AVDECC control.
+* This code provides the means for them to do so.
+*
+* It provides proxy functions for the process to call. The arguments
+* for those calls are packed into messages, which are unpacked in the
+* avdecc_msg process and then used to call the real functions.
+*
+* Current IPC uses unix sockets. Can change this by creating a new
+* implementations in openavb_avdecc_msg_client.c and openavb_avdecc_msg_server.c
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "openavb_platform.h"
+
+#define AVB_LOG_COMPONENT "AVDECC Msg"
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+#include "openavb_trace.h"
+#include "openavb_avdecc_msg_client.h"
+#include "openavb_tl.h"
+#include "openavb_talker.h"
+#include "openavb_listener.h"
+
+// forward declarations
+static bool openavbAvdeccMsgClntReceiveFromServer(int avdeccMsgHandle, openavbAvdeccMessage_t *msg);
+
+// OSAL specific functions
+#include "openavb_avdecc_msg_client_osal.c"
+
+// AvdeccMsgStateListGet() support.
+#include "openavb_avdecc_msg.c"
+
+static bool openavbAvdeccMsgClntReceiveFromServer(int avdeccMsgHandle, openavbAvdeccMessage_t *msg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ if (!msg || avdeccMsgHandle == AVB_AVDECC_MSG_HANDLE_INVALID) {
+ AVB_LOG_ERROR("Client receive; invalid argument passed");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return FALSE;
+ }
+
+ switch(msg->type) {
+ case OPENAVB_AVDECC_MSG_VERSION_CALLBACK:
+ AVB_LOG_DEBUG("Message received: OPENAVB_AVDECC_MSG_VERSION_CALLBACK");
+ openavbAvdeccMsgClntCheckVerMatchesSrvr(avdeccMsgHandle, ntohl(msg->params.versionCallback.AVBVersion));
+ break;
+ case OPENAVB_AVDECC_MSG_LISTENER_STREAM_ID:
+ AVB_LOG_DEBUG("Message received: OPENAVB_AVDECC_MSG_LISTENER_STREAM_ID");
+ openavbAvdeccMsgClntHndlListenerStreamIDFromServer(avdeccMsgHandle,
+ msg->params.listenerStreamID.sr_class, msg->params.listenerStreamID.stream_src_mac, ntohs(msg->params.listenerStreamID.stream_uid),
+ msg->params.listenerStreamID.stream_dest_mac, ntohs(msg->params.listenerStreamID.stream_vlan_id));
+ break;
+ case OPENAVB_AVDECC_MSG_S2C_TALKER_STREAM_ID:
+ AVB_LOG_DEBUG("Message received: OPENAVB_AVDECC_MSG_S2C_TALKER_STREAM_ID");
+ openavbAvdeccMsgClntHndlTalkerStreamIDFromServer(avdeccMsgHandle,
+ msg->params.s2cTalkerStreamID.sr_class,
+ msg->params.s2cTalkerStreamID.stream_id_valid,
+ msg->params.s2cTalkerStreamID.stream_src_mac,
+ ntohs(msg->params.s2cTalkerStreamID.stream_uid),
+ msg->params.s2cTalkerStreamID.stream_dest_valid,
+ msg->params.s2cTalkerStreamID.stream_dest_mac,
+ msg->params.s2cTalkerStreamID.stream_vlan_id_valid,
+ ntohs(msg->params.s2cTalkerStreamID.stream_vlan_id));
+ break;
+ case OPENAVB_AVDECC_MSG_CLIENT_CHANGE_REQUEST:
+ AVB_LOG_DEBUG("Message received: OPENAVB_AVDECC_MSG_CLIENT_CHANGE_REQUEST");
+ openavbAvdeccMsgClntHndlChangeRequestFromServer(avdeccMsgHandle, (openavbAvdeccMsgStateType_t) msg->params.clientChangeRequest.desired_state);
+ break;
+ default:
+ AVB_LOG_ERROR("Client receive: unexpected message");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return FALSE;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return TRUE;
+}
+
+bool openavbAvdeccMsgClntRequestVersionFromServer(int avdeccMsgHandle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ openavbAvdeccMessage_t msgBuf;
+
+ memset(&msgBuf, 0, OPENAVB_AVDECC_MSG_LEN);
+ msgBuf.type = OPENAVB_AVDECC_MSG_VERSION_REQUEST;
+ bool ret = openavbAvdeccMsgClntSendToServer(avdeccMsgHandle, &msgBuf);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return ret;
+}
+
+void openavbAvdeccMsgClntCheckVerMatchesSrvr(int avdeccMsgHandle, U32 AVBVersion)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (!pState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return;
+ }
+
+ if (AVBVersion == AVB_CORE_VER_FULL) {
+ pState->verState = OPENAVB_AVDECC_MSG_VER_VALID;
+ AVB_LOG_DEBUG("AVDECC Versions Match");
+ }
+ else {
+ pState->verState = OPENAVB_AVDECC_MSG_VER_INVALID;
+ AVB_LOG_WARNING("AVDECC Versions Do Not Match");
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+}
+
+bool openavbAvdeccMsgClntInitIdentify(int avdeccMsgHandle, const char * friendly_name, U8 talker)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ openavbAvdeccMessage_t msgBuf;
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (!pState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ memset(&msgBuf, 0, OPENAVB_AVDECC_MSG_LEN);
+ msgBuf.type = OPENAVB_AVDECC_MSG_CLIENT_INIT_IDENTIFY;
+ openavbAvdeccMsgParams_ClientInitIdentify_t * pParams =
+ &(msgBuf.params.clientInitIdentify);
+ strncpy(pParams->friendly_name, friendly_name, sizeof(pParams->friendly_name));
+ pParams->talker = talker;
+ bool ret = openavbAvdeccMsgClntSendToServer(avdeccMsgHandle, &msgBuf);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return ret;
+}
+
+bool openavbAvdeccMsgClntTalkerStreamID(int avdeccMsgHandle, U8 sr_class, const U8 stream_src_mac[6], U16 stream_uid, const U8 stream_dest_mac[6], U16 stream_vlan_id)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ openavbAvdeccMessage_t msgBuf;
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (!pState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ // Send a default stream_vlan_id value if none specified.
+ if (stream_vlan_id == 0) {
+ stream_vlan_id = 2; // SR Class default VLAN Id values per IEEE 802.1Q-2011 Table 9-2
+ }
+
+ // Send the stream information to the server.
+ memset(&msgBuf, 0, OPENAVB_AVDECC_MSG_LEN);
+ msgBuf.type = OPENAVB_AVDECC_MSG_C2S_TALKER_STREAM_ID;
+ openavbAvdeccMsgParams_C2S_TalkerStreamID_t * pParams =
+ &(msgBuf.params.c2sTalkerStreamID);
+ pParams->sr_class = sr_class;
+ memcpy(pParams->stream_src_mac, stream_src_mac, 6);
+ pParams->stream_uid = htons(stream_uid);
+ memcpy(pParams->stream_dest_mac, stream_dest_mac, 6);
+ pParams->stream_vlan_id = htons(stream_vlan_id);
+ bool ret = openavbAvdeccMsgClntSendToServer(avdeccMsgHandle, &msgBuf);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return ret;
+}
+
+bool openavbAvdeccMsgClntHndlListenerStreamIDFromServer(int avdeccMsgHandle, U8 sr_class, const U8 stream_src_mac[6], U16 stream_uid, const U8 stream_dest_mac[6], U16 stream_vlan_id)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (!pState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ if (!pState->pTLState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d state not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ // Determine if the supplied information differs from the current settings.
+ openavb_tl_cfg_t * pCfg = &(pState->pTLState->cfg);
+ if (pCfg->sr_class != sr_class ||
+ memcmp(pCfg->stream_addr.buffer.ether_addr_octet, stream_src_mac, 6) != 0 ||
+ pCfg->stream_uid != stream_uid ||
+ memcmp(pCfg->dest_addr.buffer.ether_addr_octet, stream_dest_mac, 6) != 0 ||
+ pCfg->vlan_id != stream_vlan_id) {
+ // If the Listener is running, stop the Listener before updating the information.
+ if (pState->pTLState->bRunning) {
+ AVB_LOG_DEBUG("Forcing Listener to Stop to change streaming settings");
+ openavbAvdeccMsgClntHndlChangeRequestFromServer(avdeccMsgHandle, OPENAVB_AVDECC_MSG_STOPPED);
+ }
+
+ // Update the stream information supplied by the server.
+ pCfg->sr_class = sr_class;
+ memcpy(pCfg->stream_addr.buffer.ether_addr_octet, stream_src_mac, 6);
+ pCfg->stream_addr.mac = &(pCfg->stream_addr.buffer); // Indicate that the MAC Address is valid.
+ pCfg->stream_uid = stream_uid;
+ memcpy(pCfg->dest_addr.buffer.ether_addr_octet, stream_dest_mac, 6);
+ pCfg->dest_addr.mac = &(pCfg->dest_addr.buffer); // Indicate that the MAC Address is valid.
+ pCfg->vlan_id = stream_vlan_id;
+ }
+
+ AVB_LOGF_DEBUG("AVDECC-supplied (Listener) sr_class: %u", pCfg->sr_class);
+ AVB_LOGF_DEBUG("AVDECC-supplied (Listener) stream_id: " ETH_FORMAT "/%u",
+ ETH_OCTETS(pCfg->stream_addr.buffer.ether_addr_octet), pCfg->stream_uid);
+ AVB_LOGF_DEBUG("AVDECC-supplied (Listener) dest_addr: " ETH_FORMAT,
+ ETH_OCTETS(pCfg->dest_addr.buffer.ether_addr_octet));
+ AVB_LOGF_DEBUG("AVDECC-supplied (Listener) vlan_id: %u", pCfg->vlan_id);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return true;
+}
+
+bool openavbAvdeccMsgClntHndlTalkerStreamIDFromServer(int avdeccMsgHandle,
+ U8 sr_class, U8 stream_id_valid, const U8 stream_src_mac[6], U16 stream_uid, U8 stream_dest_valid, const U8 stream_dest_mac[6], U8 stream_vlan_id_valid, U16 stream_vlan_id)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (!pState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ if (!pState->pTLState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d state not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ // Update the stream information supplied by the server.
+ openavb_tl_cfg_t * pCfg = &(pState->pTLState->cfg);
+ pCfg->sr_class = sr_class;
+ AVB_LOGF_DEBUG("AVDECC-supplied (Talker) sr_class: %u", pCfg->sr_class);
+ if (stream_id_valid) {
+ if (memcmp(stream_src_mac, "\x00\x00\x00\x00\x00\x00", 6) == 0 && stream_uid == 0) {
+ // Restore from the backup value.
+ if (pCfg->backup_stream_id_valid) {
+ memcpy(pCfg->stream_addr.buffer.ether_addr_octet, pCfg->backup_stream_addr, 6);
+ pCfg->stream_addr.mac = &(pCfg->stream_addr.buffer); // Indicate that the MAC Address is valid.
+ pCfg->stream_uid = pCfg->backup_stream_uid;
+ pCfg->backup_stream_id_valid = FALSE;
+ AVB_LOGF_DEBUG("AVDECC-supplied (Talker) reverted to default stream_id: " ETH_FORMAT "/%u",
+ ETH_OCTETS(pCfg->stream_addr.buffer.ether_addr_octet), pCfg->stream_uid);
+ }
+ }
+ else {
+ // Backup the current value.
+ if (!pCfg->backup_stream_id_valid) {
+ memcpy(pCfg->backup_stream_addr, pCfg->stream_addr.buffer.ether_addr_octet, 6);
+ pCfg->backup_stream_uid = pCfg->stream_uid;
+ pCfg->backup_stream_id_valid = TRUE;
+ }
+
+ // Save the new value.
+ memcpy(pCfg->stream_addr.buffer.ether_addr_octet, stream_src_mac, 6);
+ pCfg->stream_addr.mac = &(pCfg->stream_addr.buffer); // Indicate that the MAC Address is valid.
+ pCfg->stream_uid = stream_uid;
+ AVB_LOGF_DEBUG("AVDECC-supplied (Talker) stream_id: " ETH_FORMAT "/%u",
+ ETH_OCTETS(pCfg->stream_addr.buffer.ether_addr_octet), pCfg->stream_uid);
+ }
+ }
+ if (stream_dest_valid) {
+ if (memcmp(stream_dest_mac, "\x00\x00\x00\x00\x00\x00", 6) == 0) {
+ // Restore from the backup value.
+ if (pCfg->backup_dest_addr_valid) {
+ memcpy(pCfg->dest_addr.buffer.ether_addr_octet, pCfg->backup_dest_addr, 6);
+ pCfg->dest_addr.mac = &(pCfg->dest_addr.buffer); // Indicate that the MAC Address is valid.
+ pCfg->backup_dest_addr_valid = FALSE;
+ AVB_LOGF_DEBUG("AVDECC-supplied (Talker) reverted to default dest_addr: " ETH_FORMAT,
+ ETH_OCTETS(pCfg->dest_addr.buffer.ether_addr_octet));
+ }
+ }
+ else {
+ // Backup the current value.
+ if (!pCfg->backup_dest_addr_valid) {
+ memcpy(pCfg->backup_dest_addr, pCfg->dest_addr.buffer.ether_addr_octet, 6);
+ pCfg->backup_dest_addr_valid = TRUE;
+ }
+
+ // Save the new value.
+ memcpy(pCfg->dest_addr.buffer.ether_addr_octet, stream_dest_mac, 6);
+ pCfg->dest_addr.mac = &(pCfg->dest_addr.buffer); // Indicate that the MAC Address is valid.
+ AVB_LOGF_DEBUG("AVDECC-supplied (Talker) dest_addr: " ETH_FORMAT,
+ ETH_OCTETS(pCfg->dest_addr.buffer.ether_addr_octet));
+ }
+ }
+ if (stream_vlan_id_valid) {
+ if (stream_vlan_id == 0) {
+ // Restore from the backup value.
+ if (pCfg->backup_vlan_id_valid) {
+ pCfg->vlan_id = pCfg->backup_vlan_id;
+ pCfg->backup_vlan_id_valid = FALSE;
+ AVB_LOGF_DEBUG("AVDECC-supplied (Talker) reverted to default vlan_id: %u", pCfg->vlan_id);
+ }
+ }
+ else {
+ // Backup the current value.
+ if (!pCfg->backup_vlan_id_valid) {
+ pCfg->backup_vlan_id_valid = pCfg->vlan_id;
+ pCfg->backup_vlan_id_valid = TRUE;
+ }
+
+ // Save the new value.
+ pCfg->vlan_id = stream_vlan_id;
+ AVB_LOGF_DEBUG("AVDECC-supplied (Talker) vlan_id: %u", pCfg->vlan_id);
+ }
+ }
+
+ // Notify AVDECC of the Talker values to be used after the update.
+ openavbAvdeccMsgClntTalkerStreamID(avdeccMsgHandle, pCfg->sr_class, pCfg->stream_addr.buffer.ether_addr_octet, pCfg->stream_uid, pCfg->dest_addr.buffer.ether_addr_octet, pCfg->vlan_id);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return true;
+}
+
+bool openavbAvdeccMsgClntHndlChangeRequestFromServer(int avdeccMsgHandle, openavbAvdeccMsgStateType_t desiredState)
+{
+ bool ret = false;
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (!pState || !pState->pTLState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ switch (desiredState) {
+ case OPENAVB_AVDECC_MSG_STOPPED:
+ // Stop requested.
+ AVB_LOGF_DEBUG("Stop state requested for client %d", avdeccMsgHandle);
+ if (pState->pTLState->bRunning) {
+ if (openavbTLStop((tl_handle_t) pState->pTLState)) {
+ // NOTE: openavbTLStop() call will cause client change notification if successful.
+ AVB_LOGF_INFO("Client %d state changed to Stopped", avdeccMsgHandle);
+ ret = true;
+ } else {
+ // Notify server of issues.
+ AVB_LOGF_ERROR("Unable to change client %d state to Stopped", avdeccMsgHandle);
+ openavbAvdeccMsgClntChangeNotification(avdeccMsgHandle, OPENAVB_AVDECC_MSG_UNKNOWN);
+ }
+ } else {
+ // Notify server we are already in this state.
+ AVB_LOGF_INFO("Client %d state is already at Stopped", avdeccMsgHandle);
+ openavbAvdeccMsgClntChangeNotification(avdeccMsgHandle, OPENAVB_AVDECC_MSG_STOPPED);
+ ret = true;
+ }
+ break;
+
+ case OPENAVB_AVDECC_MSG_RUNNING:
+ // Run requested.
+ AVB_LOGF_DEBUG("Run state requested for client %d", avdeccMsgHandle);
+ if (!(pState->pTLState->bRunning)) {
+ if (openavbTLRun((tl_handle_t) pState->pTLState)) {
+ // NOTE: openavbTLRun() call will cause client change notification if successful.
+ AVB_LOGF_INFO("Client %d state changed to Running", avdeccMsgHandle);
+ ret = true;
+ } else {
+ // Notify server of issues.
+ AVB_LOGF_ERROR("Unable to change client %d state to Running", avdeccMsgHandle);
+ openavbAvdeccMsgClntChangeNotification(avdeccMsgHandle, OPENAVB_AVDECC_MSG_UNKNOWN);
+ }
+ }
+ else if (pState->pTLState->bRunning && pState->pTLState->bPaused) {
+ if (pState->pTLState->cfg.role == AVB_ROLE_TALKER) {
+ openavbTLPauseTalker(pState->pTLState, FALSE);
+ // NOTE: openavbTLPauseTalker() call will cause Talker change notification.
+ AVB_LOGF_INFO("Talker %d state changed from Paused to Running", avdeccMsgHandle);
+ ret = true;
+ } else {
+ openavbTLPauseListener(pState->pTLState, FALSE);
+ // NOTE: openavbTLPauseListener() call will cause Listener change notification.
+ AVB_LOGF_INFO("Listener %d state changed from Paused to Running", avdeccMsgHandle);
+ ret = true;
+ }
+ }
+ else {
+ // Notify server we are already in this state.
+ AVB_LOGF_INFO("Client %d state is already at Running", avdeccMsgHandle);
+ openavbAvdeccMsgClntChangeNotification(avdeccMsgHandle, OPENAVB_AVDECC_MSG_RUNNING);
+ ret = true;
+ }
+ break;
+
+ case OPENAVB_AVDECC_MSG_PAUSED:
+ // Running with Pause requested.
+ AVB_LOGF_DEBUG("Paused state requested for client %d", avdeccMsgHandle);
+ if (!(pState->pTLState->bRunning)) {
+ // Notify server of issues.
+ AVB_LOGF_ERROR("Client %d attempted to pause the stream while not Running.", avdeccMsgHandle);
+ openavbAvdeccMsgClntChangeNotification(avdeccMsgHandle, OPENAVB_AVDECC_MSG_UNKNOWN);
+ }
+ else if (pState->pTLState->bRunning && !(pState->pTLState->bPaused)) {
+ if (pState->pTLState->cfg.role == AVB_ROLE_TALKER) {
+ openavbTLPauseTalker(pState->pTLState, TRUE);
+ // NOTE: openavbTLPauseTalker() call will cause Talker change notification.
+ AVB_LOGF_INFO("Talker %d state changed from Running to Paused", avdeccMsgHandle);
+ ret = true;
+ } else {
+ openavbTLPauseListener(pState->pTLState, TRUE);
+ // NOTE: openavbTLPauseListener() call will cause Listener change notification.
+ AVB_LOGF_INFO("Listener %d state changed from Running to Paused", avdeccMsgHandle);
+ ret = true;
+ }
+ }
+ else {
+ // Notify server we are already in this state.
+ AVB_LOGF_INFO("Client %d state is already at Paused", avdeccMsgHandle);
+ openavbAvdeccMsgClntChangeNotification(avdeccMsgHandle, OPENAVB_AVDECC_MSG_PAUSED);
+ ret = true;
+ }
+ break;
+
+ default:
+ AVB_LOGF_ERROR("openavbAvdeccMsgClntHndlChangeRequestFromServer invalid state %d", desiredState);
+ break;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return ret;
+}
+
+bool openavbAvdeccMsgClntChangeNotification(int avdeccMsgHandle, openavbAvdeccMsgStateType_t currentState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ openavbAvdeccMessage_t msgBuf;
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (!pState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ memset(&msgBuf, 0, OPENAVB_AVDECC_MSG_LEN);
+ msgBuf.type = OPENAVB_AVDECC_MSG_CLIENT_CHANGE_NOTIFICATION;
+ openavbAvdeccMsgParams_ClientChangeNotification_t * pParams =
+ &(msgBuf.params.clientChangeNotification);
+ pParams->current_state = (U8) currentState;
+ bool ret = openavbAvdeccMsgClntSendToServer(avdeccMsgHandle, &msgBuf);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return ret;
+}
+
+
+// Called from openavbAvdeccMsgThreadFn() which is started from openavbTLRun()
+void openavbAvdeccMsgRunTalker(avdecc_msg_state_t *pState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ if (!pState) {
+ AVB_LOG_ERROR("Invalid AVDECC Msg State");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return;
+ }
+
+ openavb_tl_cfg_t * cfg = &(pState->pTLState->cfg);
+ if (cfg->role != AVB_ROLE_TALKER) {
+ AVB_LOG_ERROR("openavbAvdeccMsgRunTalker() passed a non-Talker state");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return;
+ }
+
+ if (!pState->bConnected) {
+ AVB_LOG_WARNING("Failed to connect to AVDECC Msg");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return;
+ }
+
+ // Let the AVDECC Msg server know our identity.
+ if (!openavbAvdeccMsgClntInitIdentify(pState->avdeccMsgHandle, cfg->friendly_name, true)) {
+ AVB_LOG_ERROR("openavbAvdeccMsgClntInitIdentify() failed");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return;
+ }
+
+ // Let the AVDECC Msg server know our stream ID.
+ if (!openavbAvdeccMsgClntTalkerStreamID(pState->avdeccMsgHandle,
+ cfg->sr_class, cfg->stream_addr.buffer.ether_addr_octet, cfg->stream_uid,
+ cfg->dest_addr.buffer.ether_addr_octet, cfg->vlan_id)) {
+ AVB_LOG_ERROR("openavbAvdeccMsgClntTalkerStreamID() failed");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return;
+ }
+
+ // Let the AVDECC Msg server know our current state.
+ if (!openavbAvdeccMsgClntChangeNotification(pState->avdeccMsgHandle,
+ (pState->pTLState->bRunning ?
+ (pState->pTLState->bPaused ? OPENAVB_AVDECC_MSG_PAUSED : OPENAVB_AVDECC_MSG_RUNNING ) :
+ OPENAVB_AVDECC_MSG_STOPPED))) {
+ AVB_LOG_ERROR("Initial openavbAvdeccMsgClntChangeNotification() failed");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return;
+ }
+
+ // Do until we are stopped or lose connection to AVDECC Msg server.
+ while (pState->pTLState->bAvdeccMsgRunning && pState->bConnected) {
+
+ // Look for messages from AVDECC Msg.
+ if (!openavbAvdeccMsgClntService(pState->avdeccMsgHandle, 1000)) {
+ AVB_LOG_WARNING("Lost connection to AVDECC Msg");
+ pState->bConnected = FALSE;
+ pState->avdeccMsgHandle = AVB_AVDECC_MSG_HANDLE_INVALID;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+}
+
+// Called from openavbAvdeccMsgThreadFn() which is started from openavbTLRun()
+void openavbAvdeccMsgRunListener(avdecc_msg_state_t *pState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ if (!pState && !pState->pTLState) {
+ AVB_LOG_ERROR("Invalid AVDECC Msg State");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return;
+ }
+
+ openavb_tl_cfg_t * cfg = &(pState->pTLState->cfg);
+ if (cfg->role != AVB_ROLE_LISTENER) {
+ AVB_LOG_ERROR("openavbAvdeccMsgRunListener() passed a non-Listener state");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return;
+ }
+
+ if (!pState->bConnected) {
+ AVB_LOG_WARNING("Failed to connect to AVDECC Msg");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return;
+ }
+
+ // Let the AVDECC Msg server know our identity.
+ if (!openavbAvdeccMsgClntInitIdentify(pState->avdeccMsgHandle, cfg->friendly_name, false)) {
+ AVB_LOG_ERROR("openavbAvdeccMsgClntInitIdentify() failed");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return;
+ }
+
+ // Let the AVDECC Msg server know our current state.
+ if (!openavbAvdeccMsgClntChangeNotification(pState->avdeccMsgHandle,
+ (pState->pTLState->bRunning ?
+ (pState->pTLState->bPaused ? OPENAVB_AVDECC_MSG_PAUSED : OPENAVB_AVDECC_MSG_RUNNING ) :
+ OPENAVB_AVDECC_MSG_STOPPED))) {
+ AVB_LOG_ERROR("Initial openavbAvdeccMsgClntChangeNotification() failed");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return;
+ }
+
+ // Do until we are stopped or lose connection to AVDECC Msg.
+ while (pState->pTLState->bAvdeccMsgRunning && pState->bConnected) {
+
+ // Look for messages from AVDECC Msg.
+ if (!openavbAvdeccMsgClntService(pState->avdeccMsgHandle, 1000)) {
+ AVB_LOG_WARNING("Lost connection to AVDECC Msg");
+ pState->bConnected = FALSE;
+ pState->avdeccMsgHandle = AVB_AVDECC_MSG_HANDLE_INVALID;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+}
+
+// AVDECC Msg thread function
+void* openavbAvdeccMsgThreadFn(void *pv)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ avdecc_msg_state_t avdeccMsgState;
+
+ // Perform the base initialization.
+ openavbAvdeccMsgInitialize();
+
+ // Initialize our local state structure.
+ memset(&avdeccMsgState, 0, sizeof(avdeccMsgState));
+ avdeccMsgState.pTLState = (tl_state_t *)pv;
+
+ avdeccMsgState.avdeccMsgHandle =
+ avdeccMsgState.pTLState->avdeccMsgHandle = AVB_AVDECC_MSG_HANDLE_INVALID;
+ while (avdeccMsgState.pTLState->bAvdeccMsgRunning) {
+ AVB_TRACE_LINE(AVB_TRACE_AVDECC_MSG_DETAIL);
+
+ if (avdeccMsgState.avdeccMsgHandle == AVB_AVDECC_MSG_HANDLE_INVALID) {
+ avdeccMsgState.avdeccMsgHandle = openavbAvdeccMsgClntOpenSrvrConnection();
+ if (avdeccMsgState.avdeccMsgHandle == AVB_AVDECC_MSG_HANDLE_INVALID) {
+ // error connecting to AVDECC Msg, already logged
+ SLEEP(1);
+ continue;
+ }
+ avdeccMsgState.pTLState->avdeccMsgHandle = avdeccMsgState.avdeccMsgHandle;
+ }
+ AvdeccMsgStateListAdd(&avdeccMsgState);
+
+ // Validate the AVB version for client and server are the same before continuing
+ avdeccMsgState.verState = OPENAVB_AVDECC_MSG_VER_UNKNOWN;
+ avdeccMsgState.bConnected = openavbAvdeccMsgClntRequestVersionFromServer(avdeccMsgState.avdeccMsgHandle);
+ if (avdeccMsgState.pTLState->bAvdeccMsgRunning && avdeccMsgState.bConnected && avdeccMsgState.verState == OPENAVB_AVDECC_MSG_VER_UNKNOWN) {
+ // Check for AVDECC Msg version message. Timeout in 500 msec.
+ if (!openavbAvdeccMsgClntService(avdeccMsgState.avdeccMsgHandle, 500)) {
+ AVB_LOG_WARNING("Lost connection to AVDECC Msg, will retry");
+ avdeccMsgState.bConnected = FALSE;
+ avdeccMsgState.avdeccMsgHandle =
+ avdeccMsgState.pTLState->avdeccMsgHandle = AVB_AVDECC_MSG_HANDLE_INVALID;
+ }
+ }
+ if (avdeccMsgState.verState == OPENAVB_AVDECC_MSG_VER_UNKNOWN) {
+ AVB_LOG_ERROR("AVB core version not reported by AVDECC Msg server. Will reconnect to AVDECC Msg and check again.");
+ } else if (avdeccMsgState.verState == OPENAVB_AVDECC_MSG_VER_INVALID) {
+ AVB_LOG_ERROR("AVB core version is different than AVDECC Msg AVB core version. Will reconnect to AVDECC Msg and check again.");
+ } else {
+ AVB_LOG_DEBUG("AVB core version matches AVDECC Msg AVB core version.");
+ }
+
+ if (avdeccMsgState.bConnected && avdeccMsgState.verState == OPENAVB_AVDECC_MSG_VER_VALID) {
+ if (avdeccMsgState.pTLState->cfg.role == AVB_ROLE_TALKER) {
+ openavbAvdeccMsgRunTalker(&avdeccMsgState);
+ }
+ else {
+ openavbAvdeccMsgRunListener(&avdeccMsgState);
+ }
+ }
+
+ // Close the AVDECC Msg connection.
+ AvdeccMsgStateListRemove(&avdeccMsgState);
+ openavbAvdeccMsgClntCloseSrvrConnection(avdeccMsgState.avdeccMsgHandle);
+ avdeccMsgState.bConnected = FALSE;
+ avdeccMsgState.avdeccMsgHandle =
+ avdeccMsgState.pTLState->avdeccMsgHandle = AVB_AVDECC_MSG_HANDLE_INVALID;
+
+ if (avdeccMsgState.pTLState->bAvdeccMsgRunning && avdeccMsgState.verState == OPENAVB_AVDECC_MSG_VER_VALID) {
+ SLEEP(1);
+ }
+ }
+
+ avdeccMsgState.pTLState = NULL;
+
+ // Perform the base cleanup.
+ openavbAvdeccMsgCleanup();
+
+ THREAD_JOINABLE(avdeccMsgState.pTLState->avdeccMsgThread);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return NULL;
+}
+
+
+// Client-side helper function.
+bool openavbAvdeccMsgClntNotifyCurrentState(tl_state_t *pTLState)
+{
+ if (!pTLState) { return FALSE; }
+ if (!(pTLState->bAvdeccMsgRunning)) { return FALSE; }
+
+ // Find the AVDECC Msg for the supplied tl_state_t pointer.
+ int i;
+ for (i = 0; i < MAX_AVDECC_MSG_CLIENTS; ++i) {
+ avdecc_msg_state_t * pAvdeccMsgState = AvdeccMsgStateListGetIndex(i);
+ if (!pAvdeccMsgState) {
+ // Out of items.
+ break;
+ }
+ if (pAvdeccMsgState->pTLState == pTLState) {
+ // Notify the server regarding the current state.
+ if (pTLState->bRunning) {
+ openavbAvdeccMsgClntChangeNotification(pAvdeccMsgState->avdeccMsgHandle, (pTLState->bPaused ? OPENAVB_AVDECC_MSG_PAUSED : OPENAVB_AVDECC_MSG_RUNNING));
+ } else {
+ openavbAvdeccMsgClntChangeNotification(pAvdeccMsgState->avdeccMsgHandle, OPENAVB_AVDECC_MSG_STOPPED);
+ }
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
diff --git a/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_client.h b/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_client.h
new file mode 100644
index 00000000..9fea390e
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_client.h
@@ -0,0 +1,60 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#ifndef OPENAVB_AVDECC_MSG_CLIENT_H
+#define OPENAVB_AVDECC_MSG_CLIENT_H
+
+#include "openavb_types.h"
+#include "openavb_tl.h"
+#include "openavb_avdecc_msg.h"
+
+
+struct _avdecc_msg_state {
+
+ // Connected to AVDECC Msg flag. (assumed atomic)
+ bool bConnected;
+
+ // The status of the version check to make sure AVDECC Msg and TL are running the same version.
+ openavbAvdeccMsgVerState_t verState;
+
+ // Pointer to the talker/listener state linked to the AVDECC Msg instance.
+ tl_state_t *pTLState;
+
+ // Handle to the AVDECC Msg handle for the connection to the server.
+ int avdeccMsgHandle;
+
+};
+
+
+// Client-side helper function.
+bool openavbAvdeccMsgClntNotifyCurrentState(tl_state_t *pTLState);
+
+#endif // OPENAVB_AVDECC_MSG_CLIENT_H
diff --git a/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_server.c b/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_server.c
new file mode 100644
index 00000000..326b64b7
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_server.c
@@ -0,0 +1,470 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+ * MODULE SUMMARY :
+ *
+ * Stream clients (talkers or listeners) must connect to the central
+ * "avdecc_msg" process to create a reservation for their traffic.
+ *
+ * This code implements the server side of the IPC.
+ *
+ * It provides proxy functions for the avdecc_msg to call. The arguments
+ * for those calls are packed into messages, which are unpacked in the
+ * process and then used to call the real functions.
+ *
+ * Current IPC uses unix sockets. Can change this by creating a new
+ * implementations in openavb_avdecc_msg_client.c and openavb_avdecc_msg_server.c
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+//#define AVB_LOG_LEVEL AVB_LOG_LEVEL_DEBUG
+#define AVB_LOG_COMPONENT "AVDECC Msg"
+#include "openavb_pub.h"
+#include "openavb_log.h"
+#include "openavb_avdecc_pub.h"
+#include "openavb_adp.h"
+#include "openavb_acmp_sm_talker.h"
+#include "openavb_acmp_sm_listener.h"
+
+#include "openavb_avdecc_msg_server.h"
+#include "openavb_trace.h"
+
+// forward declarations
+static bool openavbAvdeccMsgSrvrReceiveFromClient(int avdeccMsgHandle, openavbAvdeccMessage_t *msg);
+
+// OSAL specific functions
+#include "openavb_avdecc_msg_server_osal.c"
+
+// AvdeccMsgStateListGet() support.
+#include "openavb_avdecc_msg.c"
+
+// the following are from openavb_avdecc.c
+extern openavb_avdecc_cfg_t gAvdeccCfg;
+extern openavb_tl_data_cfg_t * streamList;
+
+
+static bool openavbAvdeccMsgSrvrReceiveFromClient(int avdeccMsgHandle, openavbAvdeccMessage_t *msg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ if (!msg) {
+ AVB_LOG_ERROR("Receiving message; invalid argument passed");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return FALSE;
+ }
+
+ bool ret = FALSE;
+ switch (msg->type) {
+ case OPENAVB_AVDECC_MSG_VERSION_REQUEST:
+ AVB_LOG_DEBUG("Message received: OPENAVB_AVDECC_MSG_VERSION_REQUEST");
+ ret = openavbAvdeccMsgSrvrHndlVerRqstFromClient(avdeccMsgHandle);
+ break;
+ case OPENAVB_AVDECC_MSG_CLIENT_INIT_IDENTIFY:
+ AVB_LOG_DEBUG("Message received: OPENAVB_AVDECC_MSG_CLIENT_INIT_IDENTIFY");
+ ret = openavbAvdeccMsgSrvrHndlInitIdentifyFromClient(avdeccMsgHandle,
+ msg->params.clientInitIdentify.friendly_name,
+ msg->params.clientInitIdentify.talker);
+ break;
+ case OPENAVB_AVDECC_MSG_C2S_TALKER_STREAM_ID:
+ AVB_LOG_DEBUG("Message received: OPENAVB_AVDECC_MSG_C2S_TALKER_STREAM_ID");
+ ret = openavbAvdeccMsgSrvrHndlTalkerStreamIDFromClient(avdeccMsgHandle,
+ msg->params.c2sTalkerStreamID.sr_class,
+ msg->params.c2sTalkerStreamID.stream_src_mac,
+ ntohs(msg->params.c2sTalkerStreamID.stream_uid),
+ msg->params.c2sTalkerStreamID.stream_dest_mac,
+ ntohs(msg->params.c2sTalkerStreamID.stream_vlan_id));
+ break;
+ case OPENAVB_AVDECC_MSG_CLIENT_CHANGE_NOTIFICATION:
+ AVB_LOG_DEBUG("Message received: OPENAVB_AVDECC_MSG_CLIENT_CHANGE_NOTIFICATION");
+ ret = openavbAvdeccMsgSrvrHndlChangeNotificationFromClient(avdeccMsgHandle, (openavbAvdeccMsgStateType_t) msg->params.clientChangeNotification.current_state);
+ break;
+ default:
+ AVB_LOG_ERROR("Unexpected message received at server");
+ break;
+ }
+
+ AVB_LOGF_VERBOSE("Message handled, ret=%d", ret);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return ret;
+}
+
+void openavbAvdeccMsgSrvrSendServerVersionToClient(int avdeccMsgHandle, U32 AVBVersion)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ openavbAvdeccMessage_t msgBuf;
+ memset(&msgBuf, 0, OPENAVB_AVDECC_MSG_LEN);
+ msgBuf.type = OPENAVB_AVDECC_MSG_VERSION_CALLBACK;
+ msgBuf.params.versionCallback.AVBVersion = htonl(AVBVersion);
+ openavbAvdeccMsgSrvrSendToClient(avdeccMsgHandle, &msgBuf);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+}
+
+/* Client version request
+ */
+bool openavbAvdeccMsgSrvrHndlVerRqstFromClient(int avdeccMsgHandle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ openavbAvdeccMsgSrvrSendServerVersionToClient(avdeccMsgHandle, AVB_CORE_VER_FULL);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return TRUE;
+}
+
+bool openavbAvdeccMsgSrvrHndlInitIdentifyFromClient(int avdeccMsgHandle, char * friendly_name, U8 talker)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ openavb_tl_data_cfg_t * currentStream;
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (pState) {
+ // The handle was already specified. Something has gone terribly wrong!
+ AVB_LOGF_ERROR("avdeccMsgHandle %d already used", avdeccMsgHandle);
+ AvdeccMsgStateListRemove(pState);
+ free(pState);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ // Make sure the supplied string is nil-terminated.
+ friendly_name[FRIENDLY_NAME_SIZE - 1] = '\0';
+
+ // Create a structure to hold the client information.
+ pState = (avdecc_msg_state_t *) calloc(1, sizeof(avdecc_msg_state_t));
+ if (!pState) {
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+ pState->avdeccMsgHandle = avdeccMsgHandle;
+ pState->bTalker = (talker != 0);
+ pState->lastRequestedState = pState->lastReportedState = OPENAVB_AVDECC_MSG_UNKNOWN;
+
+ // Find the state information matching this item.
+ for (currentStream = streamList; currentStream != NULL; currentStream = currentStream->next) {
+ if (strncmp(currentStream->friendly_name, friendly_name, FRIENDLY_NAME_SIZE) == 0)
+ {
+ break;
+ }
+ }
+ if (!currentStream) {
+ AVB_LOGF_WARNING("Ignoring unexpected client %d, friendly_name: %s",
+ avdeccMsgHandle, friendly_name);
+ free(pState);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ // Keep track of this new state item.
+ if (!AvdeccMsgStateListAdd(pState)) {
+ AVB_LOGF_ERROR("Error saving client identity information %d", avdeccMsgHandle);
+ free(pState);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ // Associate this Listener instance with the stream information.
+ pState->stream = currentStream;
+ currentStream->client = pState;
+
+ AVB_LOGF_INFO("Client %d Detected, friendly_name: %s",
+ avdeccMsgHandle, friendly_name);
+
+ // Enable ADP support, now that we have at least one Talker/Listener.
+ openavbAdpHaveTL(true);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return true;
+}
+
+bool openavbAvdeccMsgSrvrHndlTalkerStreamIDFromClient(int avdeccMsgHandle, U8 sr_class, const U8 stream_src_mac[6], U16 stream_uid, const U8 stream_dest_mac[6], U16 stream_vlan_id)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (!pState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ openavb_tl_data_cfg_t *pCfg = pState->stream;
+ if (!pCfg) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d stream not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ // Update the stream information supplied by the client.
+ pCfg->sr_class = sr_class;
+ memcpy(pCfg->stream_addr.buffer.ether_addr_octet, stream_src_mac, 6);
+ pCfg->stream_addr.mac = &(pCfg->stream_addr.buffer); // Indicate that the MAC Address is valid.
+ pCfg->stream_uid = stream_uid;
+ memcpy(pCfg->dest_addr.buffer.ether_addr_octet, stream_dest_mac, 6);
+ pCfg->dest_addr.mac = &(pCfg->dest_addr.buffer); // Indicate that the MAC Address is valid.
+ pCfg->vlan_id = stream_vlan_id;
+ AVB_LOGF_DEBUG("Talker-supplied sr_class: %u", pCfg->sr_class);
+ AVB_LOGF_DEBUG("Talker-supplied stream_id: " ETH_FORMAT "/%u",
+ ETH_OCTETS(pCfg->stream_addr.buffer.ether_addr_octet), pCfg->stream_uid);
+ AVB_LOGF_DEBUG("Talker-supplied dest_addr: " ETH_FORMAT,
+ ETH_OCTETS(pCfg->dest_addr.buffer.ether_addr_octet));
+ AVB_LOGF_DEBUG("Talker-supplied vlan_id: %u", pCfg->vlan_id);
+
+ // Notify the state machine that we received this information.
+ openavbAcmpSMTalker_updateStreamInfo(pCfg);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return true;
+}
+
+bool openavbAvdeccMsgSrvrListenerStreamID(int avdeccMsgHandle, U8 sr_class, const U8 stream_src_mac[6], U16 stream_uid, const U8 stream_dest_mac[6], U16 stream_vlan_id)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ openavbAvdeccMessage_t msgBuf;
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (!pState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ memset(&msgBuf, 0, OPENAVB_AVDECC_MSG_LEN);
+ msgBuf.type = OPENAVB_AVDECC_MSG_LISTENER_STREAM_ID;
+ openavbAvdeccMsgParams_ListenerStreamID_t * pParams =
+ &(msgBuf.params.listenerStreamID);
+ pParams->sr_class = sr_class;
+ memcpy(pParams->stream_src_mac, stream_src_mac, 6);
+ pParams->stream_uid = htons(stream_uid);
+ memcpy(pParams->stream_dest_mac, stream_dest_mac, 6);
+ pParams->stream_vlan_id = htons(stream_vlan_id);
+ bool ret = openavbAvdeccMsgSrvrSendToClient(avdeccMsgHandle, &msgBuf);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return ret;
+}
+
+bool openavbAvdeccMsgSrvrTalkerStreamID(int avdeccMsgHandle,
+ U8 sr_class, U8 stream_id_valid, const U8 stream_src_mac[6], U16 stream_uid, U8 stream_dest_valid, const U8 stream_dest_mac[6], U8 stream_vlan_id_valid, U16 stream_vlan_id)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ openavbAvdeccMessage_t msgBuf;
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (!pState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ // Send the stream information to the client.
+ memset(&msgBuf, 0, OPENAVB_AVDECC_MSG_LEN);
+ msgBuf.type = OPENAVB_AVDECC_MSG_S2C_TALKER_STREAM_ID;
+ openavbAvdeccMsgParams_S2C_TalkerStreamID_t * pParams =
+ &(msgBuf.params.s2cTalkerStreamID);
+ pParams->sr_class = sr_class;
+ pParams->stream_id_valid = stream_id_valid;
+ memcpy(pParams->stream_src_mac, stream_src_mac, 6);
+ pParams->stream_uid = htons(stream_uid);
+ pParams->stream_dest_valid = stream_dest_valid;
+ memcpy(pParams->stream_dest_mac, stream_dest_mac, 6);
+ pParams->stream_vlan_id_valid = stream_vlan_id_valid;
+ pParams->stream_vlan_id = htons(stream_vlan_id);
+ bool ret = openavbAvdeccMsgSrvrSendToClient(avdeccMsgHandle, &msgBuf);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return ret;
+}
+
+bool openavbAvdeccMsgSrvrChangeRequest(int avdeccMsgHandle, openavbAvdeccMsgStateType_t desiredState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ openavbAvdeccMessage_t msgBuf;
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (!pState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ memset(&msgBuf, 0, OPENAVB_AVDECC_MSG_LEN);
+ msgBuf.type = OPENAVB_AVDECC_MSG_CLIENT_CHANGE_REQUEST;
+ openavbAvdeccMsgParams_ClientChangeRequest_t * pParams =
+ &(msgBuf.params.clientChangeRequest);
+ pParams->desired_state = (U8) desiredState;
+ bool ret = openavbAvdeccMsgSrvrSendToClient(avdeccMsgHandle, &msgBuf);
+ if (ret) {
+ // Save the requested state for future reference.
+ pState->lastRequestedState = desiredState;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return ret;
+}
+
+static const char * GetStateString(openavbAvdeccMsgStateType_t state)
+{
+ switch (state) {
+ case OPENAVB_AVDECC_MSG_UNKNOWN:
+ return "Unknown";
+ case OPENAVB_AVDECC_MSG_STOPPED:
+ return "Stopped";
+ case OPENAVB_AVDECC_MSG_RUNNING:
+ return "Running";
+ case OPENAVB_AVDECC_MSG_PAUSED:
+ return "Paused";
+ case OPENAVB_AVDECC_MSG_STOPPED_UNEXPECTEDLY:
+ return "Stopped_Unexpectedly";
+ default:
+ return "ERROR";
+ }
+}
+
+bool openavbAvdeccMsgSrvrHndlChangeNotificationFromClient(int avdeccMsgHandle, openavbAvdeccMsgStateType_t currentState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (!pState) {
+ AVB_LOGF_ERROR("avdeccMsgHandle %d not valid", avdeccMsgHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return false;
+ }
+
+ // Save the updated state.
+ if (currentState != pState->lastReportedState) {
+ openavbAvdeccMsgStateType_t previousState = pState->lastReportedState;
+ pState->lastReportedState = currentState;
+ AVB_LOGF_INFO("Notified of client %d state change from %s to %s (Last requested: %s)",
+ avdeccMsgHandle, GetStateString(previousState), GetStateString(currentState), GetStateString(pState->lastRequestedState));
+
+ // If AVDECC did not yet set the client state, set the client state to the desired state.
+ if (pState->lastRequestedState == OPENAVB_AVDECC_MSG_UNKNOWN) {
+ if (pState->stream->initial_state == TL_INIT_STATE_RUNNING && pState->lastReportedState != OPENAVB_AVDECC_MSG_RUNNING) {
+ // Have the client be running if the user explicitly requested it to be running.
+ openavbAvdeccMsgSrvrChangeRequest(avdeccMsgHandle, OPENAVB_AVDECC_MSG_RUNNING);
+ }
+ else if (pState->stream->initial_state != TL_INIT_STATE_RUNNING && pState->lastReportedState == OPENAVB_AVDECC_MSG_RUNNING) {
+ // Have the client not be running if the user didn't explicitly request it to be running.
+ openavbAvdeccMsgSrvrChangeRequest(avdeccMsgHandle, OPENAVB_AVDECC_MSG_STOPPED);
+ }
+ else if (gAvdeccCfg.bFastConnectSupported &&
+ !(pState->bTalker) &&
+ pState->lastReportedState == OPENAVB_AVDECC_MSG_STOPPED) {
+ // Listener started as not running, and is not configured to start in the running state.
+ // See if we should do a fast connect using the saved state.
+ openavb_tl_data_cfg_t *pCfg = pState->stream;
+ if (pCfg) {
+ U16 flags, talker_unique_id;
+ U8 talker_entity_id[8], controller_entity_id[8];
+ bool bAvailable = openavbAvdeccGetSaveStateInfo(pCfg, &flags, &talker_unique_id, &talker_entity_id, &controller_entity_id);
+ if (bAvailable) {
+ openavbAcmpSMListenerSet_doFastConnect(pCfg, flags, talker_unique_id, talker_entity_id, controller_entity_id);
+ }
+ }
+ }
+ }
+ else if (currentState == OPENAVB_AVDECC_MSG_STOPPED_UNEXPECTEDLY) {
+ if (previousState != OPENAVB_AVDECC_MSG_STOPPED_UNEXPECTEDLY &&
+ pState->lastRequestedState == OPENAVB_AVDECC_MSG_RUNNING &&
+ gAvdeccCfg.bFastConnectSupported) {
+ // The Talker disappeared. Use fast connect to assist with reconnecting if it reappears.
+ openavb_tl_data_cfg_t *pCfg = pState->stream;
+ if (pCfg) {
+ U16 flags, talker_unique_id;
+ U8 talker_entity_id[8], controller_entity_id[8];
+ bool bAvailable = openavbAvdeccGetSaveStateInfo(pCfg, &flags, &talker_unique_id, &talker_entity_id, &controller_entity_id);
+ if (bAvailable) {
+ // Set the timed-out status for the Listener's descriptor.
+ // The next time the Talker advertises itself, openavbAcmpSMListenerSet_talkerTestFastConnect() should try to reconnect.
+ openavb_aem_descriptor_stream_io_t *pDescriptor;
+ U16 listenerUniqueId;
+ for (listenerUniqueId = 0; listenerUniqueId < 0xFFFF; ++listenerUniqueId) {
+ pDescriptor = openavbAemGetDescriptor(openavbAemGetConfigIdx(), OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT, listenerUniqueId);
+ if (pDescriptor && pDescriptor->stream &&
+ strcmp(pDescriptor->stream->friendly_name, pCfg->friendly_name) == 0) {
+ // We found a match.
+ AVB_LOGF_INFO("Listener %s waiting to fast connect to flags=0x%04x, talker_unique_id=0x%04x, talker_entity_id=" ENTITYID_FORMAT ", controller_entity_id=" ENTITYID_FORMAT,
+ pCfg->friendly_name,
+ flags,
+ talker_unique_id,
+ ENTITYID_ARGS(talker_entity_id),
+ ENTITYID_ARGS(controller_entity_id));
+ pDescriptor->fast_connect_status = OPENAVB_FAST_CONNECT_STATUS_TIMED_OUT;
+ memcpy(pDescriptor->fast_connect_talker_entity_id, talker_entity_id, sizeof(pDescriptor->fast_connect_talker_entity_id));
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &pDescriptor->fast_connect_start_time);
+ pDescriptor->fast_connect_start_time.tv_sec += 5; // Give the Talker some time to shutdown or stabilize
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Now that we have handled this, treat this state as a normal stop.
+ pState->lastReportedState = OPENAVB_AVDECC_MSG_STOPPED;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return true;
+}
+
+
+/* Called if a client closes their end of the IPC
+ */
+void openavbAvdeccMsgSrvrCloseClientConnection(int avdeccMsgHandle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ // Free the state for this handle.
+ avdecc_msg_state_t *pState = AvdeccMsgStateListGet(avdeccMsgHandle);
+ if (pState) {
+ AvdeccMsgStateListRemove(pState);
+ if (streamList && pState->stream) {
+ // Clear the stream pointer to this object.
+ pState->stream = NULL;
+ }
+ free(pState);
+
+ // If there are no more Talkers or Listeners, stop ADP.
+ if (AvdeccMsgStateListGetIndex(0) == NULL) {
+ openavbAdpHaveTL(false);
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+}
diff --git a/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_server.h b/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_server.h
new file mode 100644
index 00000000..a7b1f037
--- /dev/null
+++ b/lib/avtp_pipeline/avdecc_msg/openavb_avdecc_msg_server.h
@@ -0,0 +1,57 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#ifndef OPENAVB_AVDECC_MSG_SERVER_H
+#define OPENAVB_AVDECC_MSG_SERVER_H
+
+#include "openavb_types.h"
+#include "openavb_avdecc_msg.h"
+
+typedef struct openavb_tl_data_cfg openavb_tl_data_cfg_t;
+
+struct _avdecc_msg_state {
+
+ // Handle to the AVDECC Msg handle for the connection to the server.
+ int avdeccMsgHandle;
+
+ // TRUE if a Talker, FALSE if a Listener.
+ bool bTalker;
+
+ // Local stream that matches the client's Talker/Listener.
+ // Do not free this pointer; it is for reference only.
+ openavb_tl_data_cfg_t * stream;
+
+ // Talker/Listener state information.
+ openavbAvdeccMsgStateType_t lastRequestedState;
+ openavbAvdeccMsgStateType_t lastReportedState;
+};
+
+#endif // OPENAVB_AVDECC_MSG_SERVER_H
diff --git a/lib/avtp_pipeline/avtp/openavb_avtp.c b/lib/avtp_pipeline/avtp/openavb_avtp.c
index 6cf3ea8b..82932d23 100644
--- a/lib/avtp_pipeline/avtp/openavb_avtp.c
+++ b/lib/avtp_pipeline/avtp/openavb_avtp.c
@@ -1,16 +1,17 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
+
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -21,10 +22,10 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -72,11 +73,8 @@ static openavbRC openAvtpSock(avtp_stream_t *pStream)
}
if (pStream->rawsock != NULL) {
- // Get the socket, so we can poll on it
- pStream->sock = openavbRawsockGetSocket(pStream->rawsock);
-
openavbSetRxSignalMode(pStream->rawsock, pStream->bRxSignalMode);
-
+
if (!pStream->tx) {
// Set the multicast address that we want to receive
openavbRawsockRxMulticast(pStream->rawsock, TRUE, pStream->dest_addr.ether_addr_octet);
@@ -147,6 +145,9 @@ openavbRC openavbAvtpTxInit(
pStream->pMapCB->map_tx_init_cb(pStream->pMediaQ);
pStream->pIntfCB->intf_tx_init_cb(pStream->pMediaQ);
+ if (pStream->pIntfCB->intf_set_stream_uid_cb) {
+ pStream->pIntfCB->intf_set_stream_uid_cb(pStream->pMediaQ, streamID->uniqueID);
+ }
// Set the frame length
pStream->frameLen = pStream->pMapCB->map_max_data_size_cb(pStream->pMediaQ) + ETH_HDR_LEN_VLAN;
@@ -255,7 +256,7 @@ static void inline rxDeliveryStats(avtp_rx_info_t *rxInfo,
static openavbRC fillAvtpHdr(avtp_stream_t *pStream, U8 *pFill)
{
AVB_TRACE_ENTRY(AVB_TRACE_AVTP_DETAIL);
-
+
switch (pStream->pMapCB->map_avtp_version_cb()) {
default:
AVB_RC_LOG_RET(AVB_RC(OPENAVB_AVTP_FAILURE | OPENAVBAVTP_RC_INVALID_AVTP_VERSION));
@@ -324,15 +325,37 @@ openavbRC openavbAvtpTx(void *pv, bool bSend, bool txBlockingInIntf)
AVB_RC_LOG_TRACE_RET(rc, AVB_TRACE_AVTP_DETAIL);
}
+ U64 timeNsec = 0;
+
if (!txBlockingInIntf) {
- // Call interface module to read data
- pStream->pIntfCB->intf_tx_cb(pStream->pMediaQ);
- // Call mapping module to move data into AVTP frame
- txCBResult = pStream->pMapCB->map_tx_cb(pStream->pMediaQ, pAvtpFrame, &avtpFrameLen);
+ // Call interface module to read data
+ pStream->pIntfCB->intf_tx_cb(pStream->pMediaQ);
+
+#if IGB_LAUNCHTIME_ENABLED
+ // lets get unmodified timestamp from mediaq item about to be sent by mapping
+ media_q_item_t* item = openavbMediaQTailLock(pStream->pMediaQ, true);
+ if (item) {
+ timeNsec = item->pAvtpTime->timeNsec;
+ openavbMediaQTailUnlock(pStream->pMediaQ);
+ }
+#endif
+
+ // Call mapping module to move data into AVTP frame
+ txCBResult = pStream->pMapCB->map_tx_cb(pStream->pMediaQ, pAvtpFrame, &avtpFrameLen);
- pStream->bytes += avtpFrameLen;
+ pStream->bytes += avtpFrameLen;
}
else {
+
+#if IGB_LAUNCHTIME_ENABLED
+ // lets get unmodified timestamp from mediaq item about to be sent by mapping
+ media_q_item_t* item = openavbMediaQTailLock(pStream->pMediaQ, true);
+ if (item) {
+ timeNsec = item->pAvtpTime->timeNsec;
+ openavbMediaQTailUnlock(pStream->pMediaQ);
+ }
+#endif
+
// Blocking in interface mode. Pull from media queue for tx first
if ((txCBResult = pStream->pMapCB->map_tx_cb(pStream->pMediaQ, pAvtpFrame, &avtpFrameLen)) == TX_CB_RET_PACKET_NOT_READY) {
// Call interface module to read data
@@ -343,8 +366,9 @@ openavbRC openavbAvtpTx(void *pv, bool bSend, bool txBlockingInIntf)
}
}
- // If we got data from the mapping module, notifiy the raw sockets.
- if (txCBResult != TX_CB_RET_PACKET_NOT_READY) {
+ // If we got data from the mapping module and stream is not paused,
+ // notify the raw sockets.
+ if (txCBResult != TX_CB_RET_PACKET_NOT_READY && !pStream->bPause) {
if (pStream->tsEval) {
processTimestampEval(pStream, pAvtpFrame);
@@ -353,7 +377,7 @@ openavbRC openavbAvtpTx(void *pv, bool bSend, bool txBlockingInIntf)
// Increment the sequence number now that we are sure this is a good packet.
pStream->avtp_sequence_num++;
// Mark the frame "ready to send".
- openavbRawsockTxFrameReady(pStream->rawsock, pStream->pBuf, avtpFrameLen + pStream->ethHdrLen);
+ openavbRawsockTxFrameReady(pStream->rawsock, pStream->pBuf, avtpFrameLen + pStream->ethHdrLen, timeNsec);
// Send if requested
if (bSend)
openavbRawsockSend(pStream->rawsock);
@@ -410,6 +434,9 @@ openavbRC openavbAvtpRxInit(
pStream->pMapCB->map_rx_init_cb(pStream->pMediaQ);
pStream->pIntfCB->intf_rx_init_cb(pStream->pMediaQ);
+ if (pStream->pIntfCB->intf_set_stream_uid_cb) {
+ pStream->pIntfCB->intf_set_stream_uid_cb(pStream->pMediaQ, streamID->uniqueID);
+ }
// Set the frame length
pStream->frameLen = pStream->pMapCB->map_max_data_size_cb(pStream->pMediaQ) + ETH_HDR_LEN_VLAN;
@@ -443,7 +470,7 @@ openavbRC openavbAvtpRxInit(
static void x_avtpRxFrame(avtp_stream_t *pStream, U8 *pFrame, U32 frameLen)
{
AVB_TRACE_ENTRY(AVB_TRACE_AVTP_DETAIL);
- AVB_LOGF_DEBUG("pFrame=%p, len=%u", pFrame, frameLen);
+ IF_LOG_INTERVAL(4096) AVB_LOGF_DEBUG("pFrame=%p, len=%u", pFrame, frameLen);
U8 subtype, flags, flags2, rxSeq, nLost, avtpVersion;
U8 *pRead = pFrame;
@@ -468,7 +495,7 @@ static void x_avtpRxFrame(avtp_stream_t *pStream, U8 *pFrame, U32 frameLen)
else if (pStream->avtp_sequence_num != rxSeq) {
nLost = (rxSeq - pStream->avtp_sequence_num)
+ (rxSeq < pStream->avtp_sequence_num ? 256 : 0);
- AVB_LOGF_DEBUG("AVTP sequence mismatch: expected: %u,\tgot: %u,\tlost %d",
+ AVB_LOGF_INFO("AVTP sequence mismatch: expected: %3u,\tgot: %3u,\tlost %3d",
pStream->avtp_sequence_num, rxSeq, nLost);
pStream->nLost += nLost;
}
@@ -477,8 +504,7 @@ static void x_avtpRxFrame(avtp_stream_t *pStream, U8 *pFrame, U32 frameLen)
pStream->bytes += frameLen;
flags2 = *pRead++;
-
- AVB_LOGF_DEBUG("subtype=%u, sv=%u, ver=%u, mr=%u, tv=%u tu=%u",
+ IF_LOG_INTERVAL(4096) AVB_LOGF_DEBUG("subtype=%u, sv=%u, ver=%u, mr=%u, tv=%u tu=%u",
subtype, flags & 0x80, avtpVersion,
flags & 0x08, flags & 0x01, flags2 & 0x01);
@@ -489,7 +515,7 @@ static void x_avtpRxFrame(avtp_stream_t *pStream, U8 *pFrame, U32 frameLen)
}
pStream->pMapCB->map_rx_cb(pStream->pMediaQ, pFrame, frameLen);
-
+
// NOTE : This is a redundant call. It is handled in avtpTryRx()
// pStream->pIntfCB->intf_rx_cb(pStream->pMediaQ);
@@ -551,7 +577,7 @@ static void avtpTryRx(avtp_stream_t *pStream)
timeout = AVTP_MAX_BLOCK_USEC;
if (timeout < RAWSOCK_MIN_TIMEOUT_USEC)
timeout = RAWSOCK_MIN_TIMEOUT_USEC;
-
+
pBuf = (U8 *)openavbRawsockGetRxFrame(pStream->rawsock, timeout, &offsetToFrame, &frameLen);
if (!pBuf)
pStream->pIntfCB->intf_rx_cb(pStream->pMediaQ);
@@ -672,10 +698,12 @@ void openavbAvtpPause(void *handle, bool bPause)
pStream->bPause = bPause;
+ // AVDECC_TODO: Do something with the bPause value!
+
AVB_TRACE_EXIT(AVB_TRACE_AVTP);
}
-void openavbAvtpShutdown(void *pv)
+void openavbAvtpShutdownTalker(void *pv)
{
AVB_TRACE_ENTRY(AVB_TRACE_AVTP);
AVB_LOG_DEBUG("Shutdown");
@@ -700,3 +728,29 @@ void openavbAvtpShutdown(void *pv)
AVB_TRACE_EXIT(AVB_TRACE_AVTP);
return;
}
+
+void openavbAvtpShutdownListener(void *pv)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVTP);
+ AVB_LOG_DEBUG("Shutdown");
+
+ avtp_stream_t *pStream = (avtp_stream_t *)pv;
+ if (pStream) {
+ // close the rawsock
+ if (pStream->rawsock) {
+ openavbRawsockClose(pStream->rawsock);
+ pStream->rawsock = NULL;
+ }
+
+ pStream->pIntfCB->intf_end_cb(pStream->pMediaQ);
+ pStream->pMapCB->map_end_cb(pStream->pMediaQ);
+
+ if (pStream->ifname)
+ free(pStream->ifname);
+
+ // free the malloc'd stream info
+ free(pStream);
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_AVTP);
+ return;
+}
diff --git a/lib/avtp_pipeline/avtp/openavb_avtp.h b/lib/avtp_pipeline/avtp/openavb_avtp.h
index b7d56b89..13d9a364 100644
--- a/lib/avtp_pipeline/avtp/openavb_avtp.h
+++ b/lib/avtp_pipeline/avtp/openavb_avtp.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -100,8 +101,6 @@ typedef struct
U16 nbuffers;
// The rawsock library handle. Used to send or receive frames.
void *rawsock;
- // The actual socket used by the rawsock library. Used for poll().
- int sock;
// The streamID - in network form
U8 streamIDnet[8];
// The destination address for stream
@@ -179,7 +178,8 @@ void openavbAvtpConfigTimsstampEval(void *handle, U32 tsInterval, U32 reportInte
void openavbAvtpPause(void *handle, bool bPause);
-void openavbAvtpShutdown(void *handle);
+void openavbAvtpShutdownTalker(void *handle);
+void openavbAvtpShutdownListener(void *handle);
int openavbAvtpTxBufferLevel(void *handle);
diff --git a/lib/avtp_pipeline/avtp/openavb_avtp_time.c b/lib/avtp_pipeline/avtp/openavb_avtp_time.c
index 49581289..93c3aaac 100644
--- a/lib/avtp_pipeline/avtp/openavb_avtp_time.c
+++ b/lib/avtp_pipeline/avtp/openavb_avtp_time.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/avtp/openavb_avtp_time_pub.h b/lib/avtp_pipeline/avtp/openavb_avtp_time_pub.h
index e2ab0c2e..0c429425 100644
--- a/lib/avtp_pipeline/avtp/openavb_avtp_time_pub.h
+++ b/lib/avtp_pipeline/avtp/openavb_avtp_time_pub.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -123,6 +124,16 @@ void openavbAvtpTimeSetToTimestamp(avtp_time_t *pAvtpTime, U32 timestamp);
*/
void openavbAvtpTimeSetToTimespec(avtp_time_t *pAvtpTime, timespec_t* timestamp);
+/** Set to nanosecond timestamp.
+ *
+ * Set the time in the avtp_time_t structure to the value of U64
+ * timeNS.
+ *
+ * \param pAvtpTime A pointer to the avtp_time_t structure.
+ * \param timeNS A U64 timestamp in nanoseconds.
+ */
+void openavbAvtpTimeSetToTimestampNS(avtp_time_t *pAvtpTime, U64 timeNS);
+
/** Push a timestamp, for use in Media Clock Recovery (MCR).
* \note Not available in all platforms.
*
diff --git a/lib/avtp_pipeline/avtp_avdecc.mk b/lib/avtp_pipeline/avtp_avdecc.mk
new file mode 100644
index 00000000..9a140c03
--- /dev/null
+++ b/lib/avtp_pipeline/avtp_avdecc.mk
@@ -0,0 +1,23 @@
+AVB_FEATURE_AVDECC ?= 1
+PLATFORM_TOOLCHAIN ?= x86_i210_linux
+
+.PHONY: all clean
+
+all: build_avdecc/Makefile
+ $(MAKE) -s -C build_avdecc install
+
+doc: build_avdecc/Makefile
+ $(MAKE) -s -C build_avdecc doc
+ @echo "\n\nTo display documentation use:\n\n" \
+ "\txdg-open $(abspath build_avdecc/documents/api_docs/index.html)\n"
+
+clean:
+ $(RM) -r build_avdecc
+
+build_avdecc/Makefile:
+ mkdir -p build_avdecc && \
+ cd build_avdecc && \
+ cmake -DCMAKE_TOOLCHAIN_FILE=../platform/Linux/$(PLATFORM_TOOLCHAIN).cmake \
+ -DAVB_FEATURE_AVDECC=$(AVB_FEATURE_AVDECC) \
+ ..
+
diff --git a/lib/avtp_pipeline/avtp_pipeline.mk b/lib/avtp_pipeline/avtp_pipeline.mk
index b0f4ede0..a3ed80e8 100644
--- a/lib/avtp_pipeline/avtp_pipeline.mk
+++ b/lib/avtp_pipeline/avtp_pipeline.mk
@@ -1,4 +1,7 @@
AVB_FEATURE_ENDPOINT ?= 1
+IGB_LAUNCHTIME_ENABLED ?= 0
+AVB_FEATURE_GSTREAMER ?= 1
+PLATFORM_TOOLCHAIN ?= x86_i210_linux
.PHONY: all clean
@@ -16,6 +19,8 @@ clean:
build/Makefile:
mkdir -p build && \
cd build && \
- cmake -DCMAKE_TOOLCHAIN_FILE=../platform/Linux/x86_i210_linux.cmake \
+ cmake -DCMAKE_TOOLCHAIN_FILE=../platform/Linux/$(PLATFORM_TOOLCHAIN).cmake \
-DAVB_FEATURE_ENDPOINT=$(AVB_FEATURE_ENDPOINT) \
- ..
+ -DIGB_LAUNCHTIME_ENABLED=$(IGB_LAUNCHTIME_ENABLED) \
+ -DAVB_FEATURE_GSTREAMER=$(AVB_FEATURE_GSTREAMER) \
+ ..
diff --git a/lib/avtp_pipeline/documents/sdk_avtp_interface_module_dev.md b/lib/avtp_pipeline/documents/sdk_avtp_interface_module_dev.md
index 4e6fb69f..aedd7e37 100644
--- a/lib/avtp_pipeline/documents/sdk_avtp_interface_module_dev.md
+++ b/lib/avtp_pipeline/documents/sdk_avtp_interface_module_dev.md
@@ -7,6 +7,7 @@ Interface modules are the components that sit between the core AVB stack and the
platform device drivers that supply access to media hardware.
<br>
+
The Plug-in Architecture {#sdk_avtp_intf_module_plugin}
========================
The OPENAVB AVB stack has a plug-in architecture for the AVTP implementation in the
@@ -63,6 +64,7 @@ callback list for the interface module to call into the media queue to access
and work with the media queue.
<br>
+
Task / Thread Model {#sdk_avtp_intf_module_task}
=================
In the general case the task / threading (hereafter referred to as task) model
@@ -85,6 +87,7 @@ it can only be accessed within the scope of a callback into the interface
module.
<br>
+
Building an Interface Module {#sdk_avtp_intf_module_building}
============================
There should be minimal dependencies for creation of an interface module. The
@@ -96,6 +99,7 @@ handled via callbacks that are available to the interface module in the media
queue structure it receives as a parameter on its own callbacks.
<br>
+
Interface Module in a Talker {#sdk_avtp_intf_module_talker}
============================
An interface module when used in a talker pulls data from a media source and
@@ -103,12 +107,14 @@ pushes it onto the media queue in the format expected by the mapping module
configured for that stream.
<br>
+
Interface Module in a Listener {#sdk_avtp_intf_module_listener}
==============================
When called from a listener it pulls data from the media queue and pushes it to
the media sink for presentation.
<br>
+
Working With the Media Queue {#working_with_mediaq}
============================
The media queue is the conduit between interface modules and mapping modules.
@@ -151,6 +157,7 @@ For a detailed work flow please visit
[Media Queue Usage](@ref sdk_notes_media_queue_usage)
<br>
+
Timestamps {#sdk_avtp_intf_module_timestamps}
==========
For interface modules often the only requirement for timestamps is to assign a
diff --git a/lib/avtp_pipeline/documents/sdk_avtp_stream_cfg.md b/lib/avtp_pipeline/documents/sdk_avtp_stream_cfg.md
index f96d0a0e..f254898b 100644
--- a/lib/avtp_pipeline/documents/sdk_avtp_stream_cfg.md
+++ b/lib/avtp_pipeline/documents/sdk_avtp_stream_cfg.md
@@ -54,7 +54,7 @@ void h264_SampleListenerCfg(openavb_tl_cfg_t *cfg)
// On the talker this value is added to the PTP walltime to create the AVTP Timestamp.
// On the listener this value is used to validate an expected valid timestamp range.
// Note: For the listener the map_nv_item_count value must be set large enough to
- // allow buffering at least as many AVTP packets that can be transmitted during this
+ // allow buffering at least as many AVTP packets that can be transmitted during this
// max transit time.
cfg->max_transit_usec = 2000;
@@ -119,8 +119,8 @@ void h264_SampleListenerCfg(openavb_tl_cfg_t *cfg)
// cfg->libCfgNames[cfgIdx] = "map_nv_tx_rate";
// cfg->libCfgValues[cfgIdx++] = "8000";
- // map_nv_max_payload_size: This is the max RTP payload size. See RFC 6184 for details,
- // 1412 is the default size
+ // map_nv_max_payload_size: This is the max RTP payload size. See RFC 6184 for details,
+ // 1412 is the default size
cfg->libCfgNames[cfgIdx] = "map_nv_max_payload_size";
cfg->libCfgValues[cfgIdx++] = "1412";
@@ -153,109 +153,34 @@ void h264_SampleListenerCfg(openavb_tl_cfg_t *cfg)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<br>
+
Common Stream Configuration {#sdk_avtp_stream_cfg_common}
===========================
These are common stream configuration values.
Name | Description
--------------------|------------
-role |Sets the process as a talker or listener. Valid values are\
- *talker* or *listener*.
-stream_addr |Used on the listener and should be set to the mac address \
- of the talker.
-stream_uid |The unique stream ID. The talker and listener must both \
- have this set the same.
-dest_addr |Destination multicast address for the stream.<br> \
- If using \
- <ul><li><b>with MAAP</b> - dynamic destination addresses \
- are generated automatically by the talker and passed to \
- the listener, and don't need to be configured.</li> \
- <li><b>without MAAP</b>, locally administered (static) \
- addresses must be configured. Those addresses are in the \
- range of: 91:E0:F0:00:FE:00 - 91:E0:F0:00:FE:FF. Typically\
- use :00 for the first stream, :01 for the second, etc. \
- </li></ul> \
- If <b>SRP</b> \
- <ul><li><b>is being</b> used the static destination \
- address only needs to be set in the talker;</li> \
- <li><b>is not being</b> used the destination address need \
- to be set (to the same value) in both the talker and \
- listener.</li></ul> \
- The destination is a multicast address, not a real MAC \
- address, so it does not match the talker or listener's \
- interface MAC. There are several pools of those addresses \
- for use by AVTP defined in 1722.
-max_interval_frames |The maximum number of packets that will be sent during an \
- observation interval. This is only used on the talker.
+role |Sets the process as a talker or listener. Valid values are *talker* or *listener*.
+stream_addr |Used on the listener and should be set to the mac address of the talker. If not specified on the talker, the talker's detected mac address will be used.<br>If AVDECC is being used, this does not need to be specified for the listener, as AVDECC will tell the listener which value to use.
+stream_uid |The unique stream ID. The talker and listener must both have this set the same.<br>If AVDECC is being used, this does not need to be specified for the listener, as AVDECC will tell the listener which value to use.
+dest_addr |Destination multicast address for the stream.<br>If using<ul><li><b>with MAAP</b> - dynamic destination addresses are generated automatically by the talker and passed to the listener, and don't need to be configured.<br>However, it is recommended that a locally administered (static) address still be configured, as the dest_addr will be used if the MAAP daemon is not available.</li><li><b>without MAAP</b>, locally administered (static) addresses must be configured. Those addresses are in the range of: 91:E0:F0:00:FE:00 - 91:E0:F0:00:FE:FF. Typically use :00 for the first stream, :01 for the second, etc. </li></ul> If <b>SRP</b> <ul><li><b>is being</b> used the static destination address only needs to be set in the talker;</li> <li><b>is not being</b> used the destination address need to be set (to the same value) in both the talker and listener.</li></ul> The destination is a multicast address, not a real MAC address, so it does not match the talker or listener's interface MAC. There are several pools of those addresses for use by AVTP defined in 1722.
+max_interval_frames |The maximum number of packets that will be sent during an observation interval. This is only used on the talker.
max_frame_size |Maximum size of the frame
-sr_class |A talker only setting. Values are either A or B. If not \
- set an internal default is used.
-sr_rank |A talker only setting. If not set an internal default is \
- used.
-max_transit_usec |Allows manually specifying a maximum transit time. \
- <ul><li><b>On the talker</b> this value is added to the \
- PTP walltime to create the AVTP Timestamp.</li> \
- <li><b>On the listener</b> this value is used to validate \
- an expected valid timestamp range.</li></ul> \
- <b>Note:</b> For the listener the map_nv_item_count value \
- must be set large enough to allow buffering at least as \
- many AVTP packets that can be transmitted during this max \
- transit time.
-max_transmit_deficit_usec |Allows setting the maximum packet transmit rate \
- deficit that will be recovered when a talker falls behind.\
- <p>When a talker can not keep up with the specified \
- transmit rate it builds up a deficit and will attempt to \
- make up for this deficit by sending more packets. There is\
- normally some variability in the transmit rate because of \
- other demands on the system so this is expected. However, \
- without this bounding value the deficit could grew too \
- large in cases such where more streams are started than \
- the system can support and when the number of streams is \
- reduced the remaining streams will attempt to recover this\
- deficit by sending packets at a higher rate. This can \
- cause a problem at the listener side and significantly \
- delay the recovery time before media playback will return \
- to normal.</p> \
- <p>Typically this value can be set to the expected buffer \
- size (in usec) that listeners are expected to be \
- buffering.<br> \
- For low latency solutions this is normally a small value. \
- For non-live media playback such as video playback the \
- listener side buffers can often be large enough to held \
- many seconds of data.</p> \
- <b>Note:</b> This is only used on a talker side.
-internal_latency |Allows mannually specifying an internal latency time. This\
- is used only on the talker.
-max_stale |The number of microseconds beyond the presentation time \
- that media queue items will be purged because they are too\
- old (past the presentation time).<br> \
- This is only used on listener end stations. \
- <p><b>Note:</b> needing to purge old media queue items is \
- often a sign of some other problem.<br> \
- For example: a delay at stream startup before incoming \
- packets are ready to be processed by the media sink.<br> \
- If this deficit in processing or purging the old (stale) \
- packets is not handled, syncing multiple listeners will be\
- problematic.</p>
-raw_tx_buffers |The number of raw socket transmit buffers. Typically 4 - 8\
- are good values. This is only used by the talker. If not \
- set internal defaults are used.
-raw_rx_buffers |The number of raw socket receive buffers. Typically 50 - \
- 100 are good values. This is only used by the listener. \
- If not set internal defaults are used.
-report_seconds |How often to output stats. Defaults to 10 seconds. 0 turns\
- off the stats.
-tx_blocking_in_intf |The interface module will block until data is available. \
- This is a talker only configuration value and not all interface modules support it.
-pMapInitFn |Pointer to the mapping module initialization function. \
- Since this is a pointer to a function addresss is it not \
- directly set in platforms that use a .ini file.
-IntfInitFn |Pointer to the interface module initialization function. \
- Since this is a pointer to a function addresss is it not \
- directly set in platforms that use a .ini file.
-
+sr_class |A talker only setting. Values are either A or B. If not set an internal default is used.
+sr_rank |A talker only setting. If not set an internal default is used.
+max_transit_usec |Allows manually specifying a maximum transit time. <ul><li><b>On the talker</b> this value is added to the PTP walltime to create the AVTP Timestamp.</li><li><b>On the listener</b> this value is used to validate an expected valid timestamp range.</li></ul><b>Note:</b> For the listener the map_nv_item_count value must be set large enough to allow buffering at least as many AVTP packets that can be transmitted during this max transit time.
+max_transmit_deficit_usec |Allows setting the maximum packet transmit rate deficit that will be recovered when a talker falls behind. <p>When a talker can not keep up with the specified transmit rate it builds up a deficit and will attempt to make up for this deficit by sending more packets. There is normally some variability in the transmit rate because of other demands on the system so this is expected. However, without this bounding value the deficit could grew too large in cases such where more streams are started than the system can support and when the number of streams is reduced the remaining streams will attempt to recover this deficit by sending packets at a higher rate. This can cause a problem at the listener side and significantly delay the recovery time before media playback will return to normal.</p><p>Typically this value can be set to the expected buffer size (in usec) that listeners are expected to be buffering.<br>For low latency solutions this is normally a small value. For non-live media playback such as video playback the listener side buffers can often be large enough to held many seconds of data.</p><b>Note:</b> This is only used on a talker side.
+internal_latency |Allows manually specifying an internal latency time. This is used only on the talker.
+max_stale |The number of microseconds beyond the presentation time that media queue items will be purged because they are too old (past the presentation time).<br>This is only used on listener end stations.<p><b>Note:</b> needing to purge old media queue items is often a sign of some other problem.<br>For example: a delay at stream startup before incoming packets are ready to be processed by the media sink.<br>If this deficit in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.</p>
+raw_tx_buffers |The number of raw socket transmit buffers. Typically 4 - 8 are good values. This is only used by the talker. If not set internal defaults are used.
+raw_rx_buffers |The number of raw socket receive buffers. Typically 50 - 100 are good values. This is only used by the listener. If not set internal defaults are used.
+report_seconds |How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+tx_blocking_in_intf |The interface module will block until data is available. This is a talker only configuration value and not all interface modules support it.
+pMapInitFn |Pointer to the mapping module initialization function. Since this is a pointer to a function address is it not directly set in platforms that use a .ini file.
+IntfInitFn |Pointer to the interface module initialization function. Since this is a pointer to a function address is it not directly set in platforms that use a .ini file.
<br>
+
# Platform Specific Stream Configuration Values
Some platform ports have unique configuration values.
@@ -263,26 +188,13 @@ Some platform ports have unique configuration values.
Name | Description
--------------------------|---------------------------
-map_lib |The name of the library file (commonly a .so file) that \
- implements the Initialize function.<br> \
- Comment out the map_lib name and link in the .c file to \
- the openavb_tl executable to embed the mapper directly into \
- the executable unit. There is no need to change anything \
- else. The Initialize function will still be dynamically \
- linked in.
+map_lib |The name of the library file (commonly a .so file) that implements the Initialize function.<br>Comment out the map_lib name and link in the .c file to the openavb_tl executable to embed the mapper directly into the executable unit. There is no need to change anything else. The Initialize function will still be dynamically linked in.
map_fn |The name of the initialize function in the mapper
-intf_lib | The name of the library file (commonly a .so file) \
- that implements the Initialize function.<br> \
- Comment out the intf_lib name and link in the .c \
- file to the openavb_tl executable to embed the \
- interface directly into the executable unit.<br> \
- There is no need to change anything else. \
- The Initialize function will still be dynamically \
- linked in
+intf_lib | The name of the library file (commonly a .so file) that implements the Initialize function.<br>Comment out the intf_lib name and link in the .c file to the openavb_tl executable to embed the interface directly into the executable unit.<br>There is no need to change anything else. The Initialize function will still be dynamically linked in
intf_fn | The name of the initialize function in the interface
-
<br>
+
Example Interface / Mapping Combinations {#sdk_avtp_stream_cfg_combinations}
========================================
Below are a few interface / mapping module combinations. Notice that a single
@@ -291,28 +203,13 @@ mappings may work with multiple interface modules.
interface module | mapping module | description
----------------------------|-----------------------|------------
-[echo](@ref echo_host_intf) |[pipe](@ref pipe_map) |Demonstration interface \
- used mostly for \
- verification and testing \
- purposes.
-[alsa](@ref alsa_intf) |[uncmp_audio](@ref uncmp_audio_map)|Audio \
- interface created for \
- demonstration on Linux. \
- Can be used to play \
- captured (line in, mic) \
- audio stream via EAVB
-[alsa](@ref alsa_intf) |[aaf_audio](@ref aaf_audio_map)|Audio \
- interface created for \
- demonstration on Linux. \
- Can be used to play \
- captured (line in, mic) \
- audio stream via EAVB
-[wav_file](@ref wav_file_intf)|[uncmp_audio](@ref uncmp_audio_map)| \
- Configuration for playing \
- wave file via EAVB
-
+[echo](@ref echo_host_intf) |[pipe](@ref pipe_map) |Demonstration interface used mostly for verification and testing purposes.
+[alsa](@ref alsa_intf) |[uncmp_audio](@ref uncmp_audio_map)|Audio interface created for demonstration on Linux. Can be used to play captured (line in, mic) audio stream via EAVB
+[alsa](@ref alsa_intf) |[aaf_audio](@ref aaf_audio_map)|Audio interface created for demonstration on Linux. Can be used to play captured (line in, mic) audio stream via EAVB
+[wav_file](@ref wav_file_intf)|[uncmp_audio](@ref uncmp_audio_map)|Configuration for playing wave file via EAVB
<br>
+
Interface and Mapping Module Configuration {#sdk_avtp_stream_cfg_intf_map}
==========================================
diff --git a/lib/avtp_pipeline/documents/sdk_eavb_integration.md b/lib/avtp_pipeline/documents/sdk_eavb_integration.md
index c1200834..e92f07b6 100644
--- a/lib/avtp_pipeline/documents/sdk_eavb_integration.md
+++ b/lib/avtp_pipeline/documents/sdk_eavb_integration.md
@@ -10,6 +10,7 @@ will be active. The details of stream configuration is described in another
section.
<br>
+
AVTP Control {#sdk_integration_avtp_control}
============
Only a handful of functions are needed to control the AVTP component. This is
@@ -23,6 +24,7 @@ general flow is:
close.
<br>
+
Host Application Integration {#sdk_integration_host_app}
============================
Controlling the non-AVTP components of the AVB stack are platform dependent.
diff --git a/lib/avtp_pipeline/documents/sdk_notes_media_queue_usage.md b/lib/avtp_pipeline/documents/sdk_notes_media_queue_usage.md
index aaa4cda8..4c6daaf2 100644
--- a/lib/avtp_pipeline/documents/sdk_notes_media_queue_usage.md
+++ b/lib/avtp_pipeline/documents/sdk_notes_media_queue_usage.md
@@ -9,6 +9,7 @@ and are hidden from interface module implemented. There are also some
simplifications to make description as straightforward as possible.
<br>
+
# Workflow
The following work flow steps will be described.
@@ -22,6 +23,7 @@ and listener streams
the Media Queue
<br>
+
Starting {#media_queue_usage_start}
========
@@ -53,6 +55,7 @@ Now the listener/talker stream is running. See next steps below for details of
Media Queue interaction for the talker and listener.
<br>
+
Talker specific flow {#media_queue_usage_talker}
====================
@@ -71,6 +74,7 @@ function additionally unlocks the head so the @ref openavbMediaQHeadUnlock call
not needed
<br>
+
Listener specific flow {#media_queue_usage_listener}
======================
@@ -90,6 +94,7 @@ additionally unlocks tail, so it is not necessary to call @ref
openavbMediaQTailUnlock.
<br>
+
Stopping {#media_queue_usage_stop}
========
@@ -101,6 +106,7 @@ During the stopping process following action are taken
the memory taken by all internal structures of Media Queue
<br>
+
Guidelines {#media_queue_usage_rules}
==========
diff --git a/lib/avtp_pipeline/documents/sdk_overview.md b/lib/avtp_pipeline/documents/sdk_overview.md
index 75d6f926..2f0f9e76 100644
--- a/lib/avtp_pipeline/documents/sdk_overview.md
+++ b/lib/avtp_pipeline/documents/sdk_overview.md
@@ -4,7 +4,7 @@ EAVB SDK Overview {#sdk_overview}
Introduction {#sdk_overview_introduction}
============
-Symphony Teleca Corporation (OPENAVB) has developed a software Protocol Stack to
+Harman International Industries, Inc. has developed a software Protocol Stack to
support Ethernet Audio Video Bridging (EAVB or AVB) on a variety of platforms.
The software includes explicit Operating System and Hardware Abstraction Layers
(OSAL and HAL) to facilitate rapid and efficient porting of the generic stack to
@@ -30,6 +30,7 @@ guides are separated into four sections:
This overview section will cover general architecture.
<br>
+
Glossary {#sdk_overview_glossary}
========
**AAF:** AVTP Audio Format
@@ -97,8 +98,6 @@ interface modules and mapping modules communicate.
**SRP:** Stream Reservation Protocol
-**OPENAVB:** Symphony Teleca Corporation
-
**Stream:** A series of AVTP data packets
**Talker:** Takes an audio or video source and transmits it as an AVTP stream on
@@ -106,6 +105,7 @@ the AVB network. It consists of a dedicated task and uses functionality in the
AVTP module, one mapping module and one interface module.
<br>
+
Architecture {#sdk_overview_architecture}
============
@@ -117,6 +117,7 @@ What follows in this section are details that more directly effect the use and
understanding of the SDK.
<br>
+
Below is the component diagram of the Core AVB stack. Notice that the interface
modules are not shown as part of the formal core stack but instead the
interfaces that they use in the core stack are shown. This is also true for the
@@ -126,6 +127,7 @@ interfaces the host application will use (TL APIs).
@image latex Core_AVB.png "Core AVB" width=15cm
<br>
+
General Purpose OSes will generally have the core AVB stack split across
multiple processes. Whereas in an RTOS everything sits within a single execution
image. Here is a process diagram of the components split across processes in the
@@ -135,18 +137,20 @@ Linux reference implementation.
@image latex fig1.png "AVB Components" width=15cm
As shown above the AVTP component of AVB is present in the application task.
-The libopenavbAVBStack library gets initialized and loaded via the APIs exposed and
+The AVB stack library gets initialized and loaded via the APIs exposed and
documented here. This static library implements that AVTP functionality as well
as controlling talker and listener initialization and life cycle. The PTP task
initialization is handled during stack initialization.
<br>
+
The common AVTP stream data flow is shown here.
@image html AVTP_Data_Flow.png "AVTP Data Flow"
@image latex AVTP_Data_Flow.png "AVPT Data Flow" width=15cm
<br>
+
The diagram below shows an audio stream flowing through the AVB system on the
Linux platform. Typically the talker and listener will be in different tasks and
may use different interfaces.
@@ -155,6 +159,7 @@ may use different interfaces.
@image latex fig2.png "AVB Audio Stream Flow" width=15cm
<br>
+
Understanding the stream life-cycle is important for use of this SDK. Below are
sequence diagrams that show the component interaction for key stream use cases.
@@ -162,14 +167,17 @@ sequence diagrams that show the component interaction for key stream use cases.
@image latex Stream_Initialize.png "Stream Initialization" width=15cm
<br>
+
@image html Talker_Stream_Data_Flow.png "Talker Stream Data Flow"
@image latex Talker_Stream_Data_Flow.png "Talker Stream Data Flow" width=15cm
<br>
+
@image html Listener_Stream_Data_Flow.png "Listener Stream Data Flow"
@image latex Listener_Stream_Data_Flow.png "Listener Stream Data Flow" width=15cm
<br>
+
Integration, Extension and Configuration {#sdk_overview_integration}
========================================
Three distinct uses of the SDK are as follows.
@@ -195,6 +203,7 @@ area of configuration is related to stream. See the section [AVTP Stream
Configuration](@ref sdk_avtp_stream_cfg) for more details.
<br>
+
Platform Specific Considerations {#sdk_overview_platform}
================================
The OPENAVB AVB stack is designed for portability covering both general purpose OSes
diff --git a/lib/avtp_pipeline/endpoint/CMakeLists.txt b/lib/avtp_pipeline/endpoint/CMakeLists.txt
index 5960d371..348b904d 100644
--- a/lib/avtp_pipeline/endpoint/CMakeLists.txt
+++ b/lib/avtp_pipeline/endpoint/CMakeLists.txt
@@ -1,6 +1,10 @@
SET (SRC_FILES ${SRC_FILES}
${AVB_SRC_DIR}/endpoint/openavb_endpoint.c
${AVB_OSAL_DIR}/endpoint/openavb_endpoint_osal.c
+ ${AVB_OSAL_DIR}/endpoint/openavb_endpoint_osal_maap.c
+ ${AVB_OSAL_DIR}/endpoint/openavb_endpoint_osal_ptp.c
+ ${AVB_OSAL_DIR}/endpoint/openavb_endpoint_osal_shaper.c
+ ${AVB_OSAL_DIR}/endpoint/openavb_endpoint_osal_srp.c
${AVB_SRC_DIR}/endpoint/openavb_endpoint_server.c
${AVB_OSAL_DIR}/endpoint/openavb_endpoint_cfg.c
PARENT_SCOPE
diff --git a/lib/avtp_pipeline/endpoint/endpoint.ini b/lib/avtp_pipeline/endpoint/endpoint.ini
index 5138c661..aa69f13d 100644
--- a/lib/avtp_pipeline/endpoint/endpoint.ini
+++ b/lib/avtp_pipeline/endpoint/endpoint.ini
@@ -35,6 +35,35 @@ start_options = -u 60
# mode is AVB_SHAPER_SW.
#mode = 4
+[maap]
+
+# The endpoint can use the MAAP daemon to allocate a multicast address for
+# each stream, using the dest_addr value from the Talker configuration file
+# only as a backup in case the MAAP daemon is not available.
+# Set port to the localhost port used by the MAAP daemon if MAAP support is
+# desired.
+# If port is 0 (the default value), then the MAAP daemon is not used and the
+# endpoint always uses the dest_addr value.
+# Note that if the MAAP daemon is not available, and a dest_addr value is not
+# specified, then an address from beginning of the MAAP locally administered
+# Pool will be used. Due to the high likelihood of address conflicts,
+# relying on this backup method is not recommended.
+port=15364
+
+[shaper]
+
+# The endpoint can use the Shaper daemon to smooth the transmission of packets.
+# This is useful for situations where the batch_factor value in the Talker INI
+# file is set to a value greater than 1, and multiple frames are being
+# generated during the same callback. The batch_factor and Shaper daemon are
+# useful for situations where the CPU load needs to be reduced or callback
+# timing for the frame generation functions is unreliable.
+# Set port to the localhost port used by the Shaper daemon if Shaper support is
+# desired.
+# If port is 0 (the default value), then the Shaper daemon is not used and the
+# endpoint frames are transmitted at the time they are generated.
+#port=15365
+
[srp]
# To disable dynamic SRP operation in the case of manually preconfigured streams
diff --git a/lib/avtp_pipeline/endpoint/openavb_endpoint.c b/lib/avtp_pipeline/endpoint/openavb_endpoint.c
index 5a4dfe17..30d8114a 100644
--- a/lib/avtp_pipeline/endpoint/openavb_endpoint.c
+++ b/lib/avtp_pipeline/endpoint/openavb_endpoint.c
@@ -1,16 +1,17 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
+
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -21,10 +22,10 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -33,7 +34,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
* It includes the SRP and QMgr libraries which handle SRP reservations
* and TX queuing.
*
-* The actual AVTP talker/listener work is done in a separate processs.
+* The actual AVTP talker/listener work is done in a separate process.
* The aim of using separate processes is to (1) reduce the
* complexity in the central process; and (2) to allow multiple types
* of children for different AVTP encapsulations and data sources.
@@ -59,6 +60,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_avtp.h"
#include "openavb_qmgr.h"
#include "openavb_maap.h"
+#include "openavb_shaper.h"
#define AVB_LOG_COMPONENT "Endpoint"
#include "openavb_pub.h"
@@ -72,7 +74,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
clientStream_t* x_streamList;
// true until we are signalled to stop
bool endpointRunning = TRUE;
-// data from our configuation file
+// data from our configuration file
openavb_endpoint_cfg_t x_cfg;
/*************************************************************
@@ -135,7 +137,7 @@ clientStream_t* addStream(int h, AVBStreamID_t *streamID)
newClientStream->streamID.uniqueID = streamID->uniqueID;
newClientStream->clientHandle = h;
newClientStream->fwmark = INVALID_FWMARK;
-
+
if(x_streamList == NULL) {
x_streamList = newClientStream;
}else {
@@ -213,7 +215,7 @@ static clientStream_t* findStreamMaap(void* hndMaap)
{
AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
clientStream_t* ps = NULL;
-
+
clientStream_t **lpp;
for(lpp = &x_streamList; *lpp != NULL; lpp = &(*lpp)->next) {
if ((*lpp)->hndMaap == hndMaap)
@@ -229,7 +231,7 @@ static clientStream_t* findStreamMaap(void* hndMaap)
/*************************************************************
*
* Internal function to cleanup streams
- *
+ *
*/
bool x_talkerDeregister(clientStream_t *ps)
{
@@ -253,7 +255,13 @@ bool x_talkerDeregister(clientStream_t *ps)
openavbMaapRelease(ps->hndMaap);
ps->hndMaap = NULL;
}
-
+
+ // Finish Shaping
+ if (ps->hndShaper) {
+ openavbShaperRelease(ps->hndShaper);
+ ps->hndShaper = NULL;
+ }
+
// remove record
delStream(ps);
@@ -304,7 +312,7 @@ openavbRC strmAttachCb(void* pv,
|| lsnrDecl == openavbSrp_LDSt_Ready_Failed)
{
// Somebody is listening - get ready to stream
-
+
if (ps->fwmark != INVALID_FWMARK) {
AVB_LOG_DEBUG("attach callback: already setup queues");
rc = OPENAVB_SUCCESS;
@@ -346,6 +354,7 @@ openavbRC strmAttachCb(void* pv,
x_cfg.ifname,
ps->destAddr,
lsnrDecl,
+ ps->srClass,
ps->classRate,
ps->vlanID,
ps->priority,
@@ -397,7 +406,7 @@ openavbRC strmRegCb(void *pv,
*
* A better way to handle this would require SRP and the
* talkers/listeners to look at destination addresses (in addition
- * to StreamID and talker/listner declaration) and explicitly handle
+ * to StreamID and talker/listener declaration) and explicitly handle
* destination address changes.
*/
static void maapRestartCallback(void* handle, struct ether_addr *addr)
@@ -449,7 +458,7 @@ int avbEndpointLoop(void)
do {
if (!x_cfg.bypassAsCapableCheck && (startPTP() < 0)) {
- // make sure ptp, a seperate process, starts and is using the same interface as endpoint
+ // make sure ptp, a separate process, starts and is using the same interface as endpoint
AVB_LOG_ERROR("PTP failed to start - Exiting");
break;
} else if(x_cfg.bypassAsCapableCheck) {
@@ -457,7 +466,7 @@ int avbEndpointLoop(void)
AVB_LOG_WARNING("Configuration 'gptp_asCapable_not_required = 1' is set.");
AVB_LOG_WARNING("This configuration bypasses the requirement for gPTP");
AVB_LOG_WARNING("and openavb_gptp is not started automatically.");
- AVB_LOG_WARNING("An appropriate ptp MUST be started seperately.");
+ AVB_LOG_WARNING("An appropriate ptp MUST be started separately.");
AVB_LOG_WARNING("Any network which does not use ptp to synchronize time");
AVB_LOG_WARNING("on each and every network device is NOT an AVB network.");
AVB_LOG_WARNING("Such a network WILL NOT FUNCTION PROPERLY.");
@@ -471,12 +480,19 @@ int avbEndpointLoop(void)
break;
}
- if (!openavbMaapInitialize(x_cfg.ifname, maapRestartCallback)) {
+ if (!openavbMaapInitialize(x_cfg.ifname, x_cfg.maapPort, &(x_cfg.maap_preferred), maapRestartCallback)) {
AVB_LOG_ERROR("Failed to initialize MAAP");
openavbQmgrFinalize();
break;
}
+ if (!openavbShaperInitialize(x_cfg.ifname, x_cfg.shaperPort)) {
+ AVB_LOG_ERROR("Failed to initialize Shaper");
+ openavbMaapFinalize();
+ openavbQmgrFinalize();
+ break;
+ }
+
if(!x_cfg.noSrp) {
// Initialize SRP
rc = openavbSrpInitialize(strmAttachCb, strmRegCb, x_cfg.ifname, x_cfg.link_kbit, x_cfg.bypassAsCapableCheck);
@@ -493,6 +509,7 @@ int avbEndpointLoop(void)
if (!IS_OPENAVB_SUCCESS(rc)) {
AVB_LOG_ERROR("Failed to initialize SRP");
+ openavbShaperFinalize();
openavbMaapFinalize();
openavbQmgrFinalize();
break;
@@ -500,23 +517,24 @@ int avbEndpointLoop(void)
if (openavbEndpointServerOpen()) {
+ retVal = 0;
+
while (endpointRunning) {
openavbEptSrvrService();
}
openavbEndpointServerClose();
}
-
+
if(!x_cfg.noSrp) {
// Shutdown SRP
openavbSrpShutdown();
}
+ openavbShaperFinalize();
openavbMaapFinalize();
openavbQmgrFinalize();
- retVal = 0;
-
} while (0);
if (!x_cfg.bypassAsCapableCheck && (stopPTP() < 0)) {
diff --git a/lib/avtp_pipeline/endpoint/openavb_endpoint.h b/lib/avtp_pipeline/endpoint/openavb_endpoint.h
index a807eba8..a3f82078 100644
--- a/lib/avtp_pipeline/endpoint/openavb_endpoint.h
+++ b/lib/avtp_pipeline/endpoint/openavb_endpoint.h
@@ -1,16 +1,17 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
+
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -21,10 +22,10 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -74,10 +75,12 @@ typedef enum {
//////////////////////////////
typedef struct {
U8 destAddr[ETH_ALEN];
+ U8 noMaapAllocate;
AVBTSpec_t tSpec;
U8 srClass;
U8 srRank;
U32 latency;
+ U32 txRate;
} openavbEndpointParams_TalkerRegister_t;
typedef struct {
@@ -94,9 +97,10 @@ typedef struct {
// Server messages parameters
//////////////////////////////
typedef struct {
- char ifname[IFNAMSIZ];
- U8 destAddr[ETH_ALEN];
+ char ifname[IFNAMSIZ + 10]; // Include space for the socket type prefix (e.g. "simple:eth0")
+ U8 destAddr[ETH_ALEN];
openavbSrpLsnrDeclSubtype_t lsnrDecl;
+ U8 srClass;
U32 classRate;
U16 vlanID;
U8 priority;
@@ -105,13 +109,13 @@ typedef struct {
typedef struct {
openavbSrpAttribType_t tlkrDecl;
- char ifname[IFNAMSIZ];
+ char ifname[IFNAMSIZ + 10]; // Include space for the socket type prefix (e.g. "simple:eth0")
U8 destAddr[ETH_ALEN];
AVBTSpec_t tSpec;
U8 srClass;
U32 latency;
openavbSrpFailInfo_t failInfo;
-} openavbEndpointParams_ListenerCallback_t;
+} openavbEndpointParams_ListenerCallback_t;
typedef struct {
U32 AVBVersion;
@@ -133,7 +137,8 @@ typedef struct clientStream_t {
SRClassIdx_t srClass; // AVB class
U8 srRank; // AVB rank
U32 latency; // internal latency
-
+ U32 txRate; // frames per second
+
// Information provided by SRP
U8 priority; // AVB priority to use for stream
U16 vlanID; // VLAN ID to use for stream
@@ -143,6 +148,9 @@ typedef struct clientStream_t {
void *hndMaap; // handle for MAAP address allocation
U8 destAddr[ETH_ALEN]; // destination MAC address (from config or MAAP)
+ // Information provided by Shaper
+ void *hndShaper; // handle for Shaping configuration
+
// Information provided by QMgr
int fwmark; // mark to identify packets of this stream
} clientStream_t;
@@ -203,17 +211,21 @@ void openavbEptClntCheckVerMatchesSrvr(int h, U32 AVBVersion);
bool openavbEptClntRegisterStream(int h,
AVBStreamID_t *streamID,
U8 destAddr[],
+ U8 noMaapAllocation,
AVBTSpec_t *tSpec,
U8 srClass,
U8 srRank,
- U32 latency);
+ U32 latency,
+ U32 txRate);
bool openavbEptSrvrRegisterStream(int h,
AVBStreamID_t *streamID,
U8 destAddr[],
+ U8 noMaapAllocation,
AVBTSpec_t *tSpec,
U8 srClass,
U8 srRank,
- U32 latency);
+ U32 latency,
+ U32 txRate);
// Each lister attaches to the stream it wants to receive;
// specifically the listener indicates interest / declaration to SRP.
@@ -233,6 +245,7 @@ void openavbEptSrvrNotifyTlkrOfSrpCb(int h,
char *ifname,
U8 destAddr[],
openavbSrpLsnrDeclSubtype_t lsnrDecl,
+ U8 srClass,
U32 classRate,
U16 vlanID,
U8 priority,
@@ -242,6 +255,7 @@ void openavbEptClntNotifyTlkrOfSrpCb(int h,
char *ifname,
U8 destAddr[],
openavbSrpLsnrDeclSubtype_t lsnrDecl,
+ U8 srClass,
U32 classRate,
U16 vlanID,
U8 priority,
@@ -270,8 +284,8 @@ void openavbEptClntNotifyLstnrOfSrpCb(int h,
// A talker can withdraw its stream registration at any time;
-// a listener can withdraw its stream attachement at any time;
-// in ether case, endpoint communication is from client to server
+// a listener can withdraw its stream attachment at any time;
+// in either case, endpoint communication is from client to server
bool openavbEptClntStopStream(int h, AVBStreamID_t *streamID);
bool openavbEptSrvrStopStream(int h, AVBStreamID_t *streamID);
diff --git a/lib/avtp_pipeline/endpoint/openavb_endpoint_client.c b/lib/avtp_pipeline/endpoint/openavb_endpoint_client.c
index 50cb3439..27d08cee 100644
--- a/lib/avtp_pipeline/endpoint/openavb_endpoint_client.c
+++ b/lib/avtp_pipeline/endpoint/openavb_endpoint_client.c
@@ -1,16 +1,17 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
+
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -21,10 +22,10 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -36,7 +37,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
* This code provides the means for them to do so.
*
* This source file is compiled into the streamer executable.
-*
+*
* It provides proxy functions for the streamer to call. The arguments
* for those calls are packed into messages, which are unpacked in the
* endpoint process and then used to call the real functions.
@@ -80,13 +81,14 @@ static bool openavbEptClntReceiveFromServer(int h, openavbEndpointMessage_t *msg
msg->params.talkerCallback.ifname,
msg->params.talkerCallback.destAddr,
msg->params.talkerCallback.lsnrDecl,
+ msg->params.talkerCallback.srClass,
msg->params.talkerCallback.classRate,
msg->params.talkerCallback.vlanID,
msg->params.talkerCallback.priority,
msg->params.talkerCallback.fwmark);
break;
case OPENAVB_ENDPOINT_LISTENER_CALLBACK:
- openavbEptClntNotifyLstnrOfSrpCb(h,
+ openavbEptClntNotifyLstnrOfSrpCb(h,
&msg->streamID,
msg->params.listenerCallback.ifname,
msg->params.listenerCallback.destAddr,
@@ -111,10 +113,12 @@ static bool openavbEptClntReceiveFromServer(int h, openavbEndpointMessage_t *msg
bool openavbEptClntRegisterStream(int h,
AVBStreamID_t *streamID,
U8 destAddr[],
+ U8 noMaapAllocate,
AVBTSpec_t *tSpec,
U8 srClass,
U8 srRank,
- U32 latency)
+ U32 latency,
+ U32 txRate)
{
AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
openavbEndpointMessage_t msgBuf;
@@ -129,13 +133,16 @@ bool openavbEptClntRegisterStream(int h,
memset(&msgBuf, 0, OPENAVB_ENDPOINT_MSG_LEN);
msgBuf.type = OPENAVB_ENDPOINT_TALKER_REGISTER;
memcpy(&(msgBuf.streamID), streamID, sizeof(AVBStreamID_t));
- if (destAddr)
+ if (destAddr) {
memcpy(msgBuf.params.talkerRegister.destAddr, destAddr, ETH_ALEN);
+ msgBuf.params.talkerRegister.noMaapAllocate = noMaapAllocate;
+ }
msgBuf.params.talkerRegister.tSpec.maxFrameSize = tSpec->maxFrameSize;
msgBuf.params.talkerRegister.tSpec.maxIntervalFrames = tSpec->maxIntervalFrames;
msgBuf.params.talkerRegister.srClass = srClass;
msgBuf.params.talkerRegister.srRank = srRank;
msgBuf.params.talkerRegister.latency = latency;
+ msgBuf.params.talkerRegister.txRate = txRate;
bool ret = openavbEptClntSendToServer(h, &msgBuf);
AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
@@ -153,7 +160,7 @@ bool openavbEptClntAttachStream(int h, AVBStreamID_t *streamID,
AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
return FALSE;
}
-
+
memset(&msgBuf, 0, OPENAVB_ENDPOINT_MSG_LEN);
msgBuf.type = OPENAVB_ENDPOINT_LISTENER_ATTACH;
memcpy(&(msgBuf.streamID), streamID, sizeof(AVBStreamID_t));
@@ -183,7 +190,7 @@ bool openavbEptClntStopStream(int h, AVBStreamID_t *streamID)
AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
return ret;
}
-
+
bool openavbEptClntRequestVersionFromServer(int h)
{
AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
@@ -196,4 +203,4 @@ bool openavbEptClntRequestVersionFromServer(int h)
AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
return ret;
}
-
+
diff --git a/lib/avtp_pipeline/endpoint/openavb_endpoint_server.c b/lib/avtp_pipeline/endpoint/openavb_endpoint_server.c
index 5d3c535b..22208333 100644
--- a/lib/avtp_pipeline/endpoint/openavb_endpoint_server.c
+++ b/lib/avtp_pipeline/endpoint/openavb_endpoint_server.c
@@ -1,16 +1,17 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
+
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -21,10 +22,10 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -35,7 +36,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
* "endpoint" process to create a reservation for their traffic.
*
* This code implements the endpoint (server) side of the IPC.
- *
+ *
* It provides proxy functions for the endpoint to call. The arguments
* for those calls are packed into messages, which are unpacked in the
* streamer processes and then used to call the real functions.
@@ -56,6 +57,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_log.h"
#include "openavb_qmgr.h" // for INVALID_FWMARK
#include "openavb_maap.h"
+#include "openavb_shaper.h"
// forward declarations
static bool openavbEptSrvrReceiveFromClient(int h, openavbEndpointMessage_t *msg);
@@ -76,17 +78,19 @@ static bool openavbEptSrvrReceiveFromClient(int h, openavbEndpointMessage_t *msg
AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
return FALSE;
}
-
+
bool ret = FALSE;
switch (msg->type) {
case OPENAVB_ENDPOINT_TALKER_REGISTER:
AVB_LOGF_DEBUG("TalkerRegister from client uid=%d", msg->streamID.uniqueID);
ret = openavbEptSrvrRegisterStream(h, &msg->streamID,
- msg->params.talkerRegister.destAddr,
- &msg->params.talkerRegister.tSpec,
- msg->params.talkerRegister.srClass,
- msg->params.talkerRegister.srRank,
- msg->params.talkerRegister.latency);
+ msg->params.talkerRegister.destAddr,
+ msg->params.talkerRegister.noMaapAllocate,
+ &msg->params.talkerRegister.tSpec,
+ msg->params.talkerRegister.srClass,
+ msg->params.talkerRegister.srRank,
+ msg->params.talkerRegister.latency,
+ msg->params.talkerRegister.txRate);
break;
case OPENAVB_ENDPOINT_LISTENER_ATTACH:
AVB_LOGF_DEBUG("ListenerAttach from client uid=%d", msg->streamID.uniqueID);
@@ -116,10 +120,11 @@ void openavbEptSrvrNotifyTlkrOfSrpCb(int h,
char *ifname,
U8 destAddr[ETH_ALEN],
openavbSrpLsnrDeclSubtype_t lsnrDecl,
+ U8 srClass,
U32 classRate,
U16 vlanID,
U8 priority,
- U16 fwmark)
+ U16 fwmark)
{
AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
openavbEndpointMessage_t msgBuf;
@@ -136,6 +141,7 @@ void openavbEptSrvrNotifyTlkrOfSrpCb(int h,
strncpy(msgBuf.params.talkerCallback.ifname, ifname, IFNAMSIZ - 1);
memcpy(msgBuf.params.talkerCallback.destAddr, destAddr, ETH_ALEN);
msgBuf.params.talkerCallback.lsnrDecl = lsnrDecl;
+ msgBuf.params.talkerCallback.srClass = srClass;
msgBuf.params.talkerCallback.classRate = classRate;
msgBuf.params.talkerCallback.vlanID = vlanID;
msgBuf.params.talkerCallback.priority = priority;
@@ -159,7 +165,7 @@ void openavbEptSrvrNotifyLstnrOfSrpCb(int h,
openavbEndpointMessage_t msgBuf;
// Check for valid parameters. DestAddr is optional and checked later.
- if (!streamID || !ifname) {
+ if (!streamID || !ifname) {
AVB_LOG_ERROR("Listener callback; invalid argument passed");
AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
return;
@@ -169,7 +175,7 @@ void openavbEptSrvrNotifyLstnrOfSrpCb(int h,
msgBuf.type = OPENAVB_ENDPOINT_LISTENER_CALLBACK;
memcpy(&(msgBuf.streamID), streamID, sizeof(AVBStreamID_t));
strncpy(msgBuf.params.listenerCallback.ifname, ifname, IFNAMSIZ - 1);
- if (destAddr)
+ if (destAddr)
memcpy(msgBuf.params.listenerCallback.destAddr, destAddr, ETH_ALEN);
msgBuf.params.listenerCallback.tlkrDecl = tlkrDecl;
if (tSpec)
@@ -200,17 +206,19 @@ void openavbEptSrvrSendServerVersionToClient(int h, U32 AVBVersion)
bool openavbEptSrvrRegisterStream(int h,
AVBStreamID_t *streamID,
U8 destAddr[],
+ U8 noMaapAllocation,
AVBTSpec_t *tSpec,
U8 srClass,
U8 srRank,
- U32 latency)
+ U32 latency,
+ U32 txRate)
{
openavbRC rc = OPENAVB_SUCCESS;
AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
clientStream_t *ps = findStream(streamID);
-
+
if (ps && ps->clientHandle != h) {
AVB_LOGF_ERROR("Error registering talker; multiple clients for stream %d", streamID->uniqueID);
AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
@@ -228,10 +236,12 @@ bool openavbEptSrvrRegisterStream(int h,
ps->srClass = (SRClassIdx_t)srClass;
ps->srRank = srRank;
ps->latency = latency;
+ ps->txRate = txRate;
ps->fwmark = INVALID_FWMARK;
- if (memcmp(ps->destAddr, destAddr, ETH_ALEN) == 0) {
- // no client-supplied address, use MAAP
+ // If MAAP is available, or no client-supplied address, allocate an address.
+ if ((!noMaapAllocation && openavbMaapDaemonAvailable()) ||
+ memcmp(ps->destAddr, destAddr, ETH_ALEN) == 0) {
struct ether_addr addr;
ps->hndMaap = openavbMaapAllocate(1, &addr);
if (ps->hndMaap) {
@@ -251,11 +261,24 @@ bool openavbEptSrvrRegisterStream(int h,
ps->hndMaap = NULL;
}
+ // If the Shaper is available, enable it.
+ if (openavbShaperDaemonAvailable() && ps->txRate) {
+ ps->hndShaper = openavbShaperHandle(
+ ps->srClass,
+ MICROSECONDS_PER_SECOND / ps->txRate, /* Note that division rounds down, which is what we want. */
+ tSpec->maxFrameSize + 18 /* Header size */,
+ 1,
+ ps->destAddr);
+ if (!ps->hndShaper) {
+ AVB_LOG_ERROR("Unable to start Shaping");
+ }
+ }
+
// Do SRP talker register
- AVB_LOGF_DEBUG("REGISTER: ps=%p, streamID=%d, tspec=%d,%d, srClass=%d, srRank=%d, latency=%d, da="ETH_FORMAT"",
+ AVB_LOGF_DEBUG("REGISTER: ps=%p, streamID=%d, tspec=%d,%d, srClass=%d, srRank=%d, latency=%d, tsRate=%d, da="ETH_FORMAT"",
ps, streamID->uniqueID,
tSpec->maxFrameSize, tSpec->maxIntervalFrames,
- ps->srClass, ps->srRank, ps->latency,
+ ps->srClass, ps->srRank, ps->latency, ps->txRate,
ETH_OCTETS(ps->destAddr));
@@ -273,12 +296,14 @@ bool openavbEptSrvrRegisterStream(int h,
if (!IS_OPENAVB_SUCCESS(rc)) {
if (ps->hndMaap)
openavbMaapRelease(ps->hndMaap);
+ if (ps->hndShaper)
+ openavbShaperRelease(ps->hndShaper);
delStream(ps);
}
}
openavbEndPtLogAllStaticStreams();
-
+
AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
return IS_OPENAVB_SUCCESS(rc);
}
@@ -372,7 +397,7 @@ bool openavbEptSrvrHndlVerRqstFromClient(int h)
return TRUE;
}
-/* Called if a client closes their end of the IPC
+/* Called if a client closes their end of the IPC
*/
void openavbEptSrvrCloseClientConnection(int h)
{
diff --git a/lib/avtp_pipeline/include/avb_sched.h b/lib/avtp_pipeline/include/avb_sched.h
index a4c7106c..5eaa3e81 100644
--- a/lib/avtp_pipeline/include/avb_sched.h
+++ b/lib/avtp_pipeline/include/avb_sched.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/include/openavb_audio_pub.h b/lib/avtp_pipeline/include/openavb_audio_pub.h
index 769481ff..46f3e03e 100644
--- a/lib/avtp_pipeline/include/openavb_audio_pub.h
+++ b/lib/avtp_pipeline/include/openavb_audio_pub.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/include/openavb_intf_pub.h b/lib/avtp_pipeline/include/openavb_intf_pub.h
index fdd00a11..fea0ffb1 100755
--- a/lib/avtp_pipeline/include/openavb_intf_pub.h
+++ b/lib/avtp_pipeline/include/openavb_intf_pub.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -65,20 +66,6 @@ typedef void (*openavb_intf_cfg_cb_t)(media_q_t *pMediaQ, const char *name, cons
*/
typedef void (*openavb_intf_gen_init_cb_t)(media_q_t *pMediaQ);
-/** AVDECC initialize callback for both a talker or listener.
- *
- * Entity model based configuration can be processed at this time.
- * This callback is optional and only executed when AVDECC is used to connect
- * streams.
- *
- * \param pMediaQ A pointer to the media queue for this stream
- * \param configIdx current configuration descriptor index for the Entity Model
- * \param descriptorType The descriptorType is expected to be of STREAM_INPUT
- * for listeners and STREAM_OUTPUT for talkers.
- * \param descriptorIdx descriptor index in the Entity Model
- */
-typedef void (*openavb_intf_avdecc_init_cb_t)(media_q_t *pMediaQ, U16 configIdx, U16 descriptorType, U16 descriptorIdx);
-
/** Initialize transmit callback into the interface module.
*
* This callback function is called anytime a stream reservation has completed
@@ -170,6 +157,37 @@ typedef void (*openavb_intf_gen_end_cb_t)(media_q_t *pMediaQ);
*/
typedef unsigned int (*openavb_intf_get_src_bitrate_t)(media_q_t *pMediaQ);
+/** Inform interface about stream_uid.
+ *
+ * Will be used for logging to distinguish information logged from different streams
+ * using the same interface.
+ * \param pMediaQ A pointer to the media queue for this stream
+ * \param stream_uid stream unique ID (last two bytes of streamID)
+ */
+typedef void (*openavb_intf_set_stream_uid_t)(media_q_t *pMediaQ, U16 stream_uid);
+
+/** Enable fixed timestamping in interface.
+ *
+ * Everytime interface needs to set media_q_item_t.pAvtpTime it calls openavbAvtpTimeSetToWallTime() to set.
+ *
+ * When fixed timestamping is enabled, interface only calls openavbAvtpTimeSetToWallTime() once
+ * for first media_q_item, then for next items it just adds fixed delay calculated
+ * from transmitInterval and batchFactor.
+ *
+ * If transmitInterval = 8000 and batchFactor = 1 then 125 us will be added.
+ * If batchFactor is 4, 4 items will have the same AVTP time set and
+ * then 125 * 4 = 500 us will be added to timestamp.
+ *
+ * \param pMediaQ A pointer to media queue for this stream
+ * \param enable true to enable, false to disable
+ * \param transmitInterval The transmit interval (in frames per second)
+ * \param batchFactor Number of intervals to handle at once
+ *
+ * \note This callback is optional, does not need to be implemented in the
+ * interface module.
+ */
+typedef void (*openavb_intf_enable_fixed_timestamp)(media_q_t *pMediaQ, bool enable, U32 transmitInterval, U32 batchFactor);
+
/** Interface callbacks structure.
*/
typedef struct {
@@ -177,8 +195,6 @@ typedef struct {
openavb_intf_cfg_cb_t intf_cfg_cb;
/// General initialize callback.
openavb_intf_gen_init_cb_t intf_gen_init_cb;
- /// AVDECC initialize callback.
- openavb_intf_avdecc_init_cb_t intf_avdecc_init_cb;
/// Initialize transmit callback.
openavb_intf_tx_init_cb_t intf_tx_init_cb;
/// Transmit callback.
@@ -197,6 +213,10 @@ typedef struct {
void * intf_host_cb_list;
/// Source bit rate callback.
openavb_intf_get_src_bitrate_t intf_get_src_bitrate_cb;
+ /// Callback for setting stream uid
+ openavb_intf_set_stream_uid_t intf_set_stream_uid_cb;
+ /// Enable fixed timestamp callback
+ openavb_intf_enable_fixed_timestamp intf_enable_fixed_timestamp;
} openavb_intf_cb_t;
/** Main initialization entry point into the interface module.
diff --git a/lib/avtp_pipeline/include/openavb_log.h b/lib/avtp_pipeline/include/openavb_log.h
index d5069111..fbcc91f2 100644
--- a/lib/avtp_pipeline/include/openavb_log.h
+++ b/lib/avtp_pipeline/include/openavb_log.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/include/openavb_log_pub.h b/lib/avtp_pipeline/include/openavb_log_pub.h
index 92a93c98..846c169e 100644
--- a/lib/avtp_pipeline/include/openavb_log_pub.h
+++ b/lib/avtp_pipeline/include/openavb_log_pub.h
@@ -1,246 +1,276 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-/*
-* MODULE SUMMARY : A simple logging facility for use during
-* development.
-*/
-
-#ifndef OPENAVB_LOG_PUB_H
-#define OPENAVB_LOG_PUB_H 1
-
-// ********
-// Merge Issue
-// TODO: Restructure to remove #ifdef code.
-// ********
-
-#include "openavb_platform_pub.h"
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-
-#include "openavb_types_pub.h"
-
-// Uncomment AVB_LOG_ON to enable logging.
-#define AVB_LOG_ON 1
-
-// Uncomment AVB_LOG_ON_OVERRIDE to override all AVB_LOG_ON usage in the stack to ensure all logs are off.
-//#define AVB_LOG_ON_OVERRIDE 1
-
-#ifdef AVB_LOG_ON_OVERRIDE
-#ifdef AVB_LOG_ON
-#undef AVB_LOG_ON
-#endif
-#endif
-
-#define AVB_LOG_LEVEL_NONE 0
-#define AVB_LOG_LEVEL_ERROR 1
-#define AVB_LOG_LEVEL_WARNING 2
-#define AVB_LOG_LEVEL_INFO 3
-#define AVB_LOG_LEVEL_STATUS 4
-#define AVB_LOG_LEVEL_DEBUG 5
-#define AVB_LOG_LEVEL_VERBOSE 6
-
-// Special case development logging levels for use with AVB_LOGF_DEV and AVB_LOG_DEV
-#define AVB_LOG_LEVEL_DEV_ON AVB_LOG_LEVEL_NONE
-#define AVB_LOG_LEVEL_DEV_OFF AVB_LOG_LEVEL_VERBOSE + 1
-
-// Default log level, can override in source files
-#ifndef AVB_LOG_LEVEL
-//#define AVB_LOG_LEVEL AVB_LOG_LEVEL_ERROR
-//#define AVB_LOG_LEVEL AVB_LOG_LEVEL_INFO
-#define AVB_LOG_LEVEL AVB_LOG_LEVEL_STATUS
-//#define AVB_LOG_LEVEL AVB_LOG_LEVEL_DEBUG
-//#define AVB_LOG_LEVEL AVB_LOG_LEVEL_VERBOSE
-#endif
-
-#ifndef AVB_LOG_COMPANY
-#define AVB_LOG_COMPANY "OPENAVB"
-#endif
-
-#ifndef AVB_LOG_COMPONENT
-#define AVB_LOG_COMPONENT "AVB Stack"
-#endif
-
-// Log format options and sizes. Uncomment to include the formatted info.
-#define LOG_MSG_LEN 1024
-
-// The length of the full message
-#define LOG_FULL_MSG_LEN 1024
-
-static const bool OPENAVB_LOG_TIME_INFO = FALSE;
-#define LOG_TIME_LEN 9
-//#define LOG_TIME_LEN 1
-
-static const bool OPENAVB_LOG_TIMESTAMP_INFO = TRUE;
-#define LOG_TIMESTAMP_LEN 32
-//#define LOG_TIMESTAMP_LEN 1
-
-static const bool OPENAVB_LOG_FILE_INFO = FALSE;
-//#define LOG_FILE_LEN 256
-#define LOG_FILE_LEN 1
-
-static const bool OPENAVB_LOG_PROC_INFO = FALSE;
-//#define LOG_PROC_LEN 64
-#define LOG_PROC_LEN 1
-
-static const bool OPENAVB_LOG_THREAD_INFO = FALSE;
-//#define LOG_THREAD_LEN 64
-#define LOG_THREAD_LEN 1
-
-#define LOG_RT_MSG_LEN 256
-//#define LOG_RT_MSG_LEN 1
-
-#define AVB_LOG_OUTPUT_FD stderr
-//#define AVB_LOG_OUTPUT_FD stdout
-
-// When OPENAVB_LOG_FROM_THREAD the message output will be output from a separate thread/task
-// Primary intended use is for debugging.
-// It is expected that OPENAVB_LOG_PULL_MODE will not be used at the same time as this optoin.
-static const bool OPENAVB_LOG_FROM_THREAD = TRUE;
-
-// When OPENAVB_LOG_PULL_MODE the messages will be queued and can be pulled using the
-// avbLogGetMsg() call. This could be from an logger interface module or host application.
-// It is expected that OPENAVB_LOG_FROM_THREAD will not be used at the same time as this option.
-static const bool OPENAVB_LOG_PULL_MODE = FALSE;
-
-// When using the OPENAVB_LOG_FROM_THREAD option. These defines control the behavior of the msg queue
-#define LOG_QUEUE_MSG_LEN 256
-#define LOG_QUEUE_MSG_SIZE (LOG_QUEUE_MSG_LEN + 1)
-#define LOG_QUEUE_MSG_CNT 82
-#define LOG_QUEUE_SLEEP_MSEC 100
-
-// RT (RealTime logging) related defines
-#define LOG_RT_QUEUE_CNT 128
-#define LOG_RT_BEGIN TRUE
-#define LOG_RT_ITEM TRUE
-#define LOG_RT_END TRUE
-typedef enum {
- LOG_RT_DATATYPE_NONE,
- LOG_RT_DATATYPE_CONST_STR,
- LOG_RT_DATATYPE_NOW_TS,
- LOG_RT_DATATYPE_U16,
- LOG_RT_DATATYPE_S16,
- LOG_RT_DATATYPE_U32,
- LOG_RT_DATATYPE_S32,
- LOG_RT_DATATYPE_U64,
- LOG_RT_DATATYPE_S64,
- LOG_RT_DATATYPE_FLOAT
-} log_rt_datatype_t;
-
-
-#define LOG_VARX(x, y) x ## y
-#define LOG_VAR(x, y) LOG_VARX(x, y)
-
-// Log a message once. Technically once every 4.2 billion attempts. Usage: LOG_ONCE AVB_LOG_INFO(...)
-#define IF_LOG_ONCE() static U32 LOG_VAR(logOnce,__LINE__); if (!LOG_VAR(logOnce,__LINE__)++)
-
-// Log a message at an interval. Usage: LOG_INTERVAL(100) AVB_LOG_INFO(...)
-#define IF_LOG_INTERVAL(x) static U32 LOG_VAR(logOnce,__LINE__); if (!(LOG_VAR(logOnce,__LINE__)++ % (x - 1)))
-
-
-#define ETH_FORMAT "%02x:%02x:%02x:%02x:%02x:%02x"
-#define ETH_OCTETS(a) (a)[0],(a)[1],(a)[2],(a)[3],(a)[4],(a)[5]
-
-#define STREAMID_FORMAT "%02x:%02x:%02x:%02x:%02x:%02x/%d"
-#define STREAMID_ARGS(s) (s)->addr[0],(s)->addr[1],(s)->addr[2],(s)->addr[3],(s)->addr[4],(s)->addr[5],(s)->uniqueID
-
-void avbLogInit(void);
-
-void avbLogExit(void);
-
-void avbLogFn(
- int level,
- const char *tag,
- const char *company,
- const char *component,
- const char *path,
- int line,
- const char *fmt,
- ...);
-
-void avbLogRT(int level, bool bBegin, bool bItem, bool bEnd, char *pFormat, log_rt_datatype_t dataType, void *pVar);
-
-
-#define avbLogFn2(level, tag, company, component, path, line, fmt, ...) \
- ({\
- if (level <= AVB_LOG_LEVEL) \
- avbLogFn(0, tag, company, component, path, line, fmt, __VA_ARGS__); \
- })
-
-#ifdef AVB_LOG_ON
-#define AVB_LOGF_DEV(LEVEL, FMT, ...) avbLogFn2(LEVEL, "DEV", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
-#define AVB_LOGF_ERROR(FMT, ...) avbLogFn2(AVB_LOG_LEVEL_ERROR, "ERROR", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
-#define AVB_LOGF_WARNING(FMT, ...) avbLogFn2(AVB_LOG_LEVEL_WARNING, "WARNING", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
-#define AVB_LOGF_INFO(FMT, ...) avbLogFn2(AVB_LOG_LEVEL_INFO, "INFO", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
-#define AVB_LOGF_STATUS(FMT, ...) avbLogFn2(AVB_LOG_LEVEL_STATUS, "STATUS", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
-#define AVB_LOGF_DEBUG(FMT, ...) avbLogFn2(AVB_LOG_LEVEL_DEBUG, "DEBUG", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
-#define AVB_LOGF_VERBOSE(FMT, ...) avbLogFn2(AVB_LOG_LEVEL_VERBOSE, "VERBOSE", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
-#define AVB_LOG_DEV(LEVEL, FMT, ...) avbLogFn2(LEVEL, "DEV", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
-#define AVB_LOG_ERROR(MSG) avbLogFn2(AVB_LOG_LEVEL_ERROR, "ERROR", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
-#define AVB_LOG_WARNING(MSG) avbLogFn2(AVB_LOG_LEVEL_WARNING, "WARNING", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
-#define AVB_LOG_INFO(MSG) avbLogFn2(AVB_LOG_LEVEL_INFO, "INFO", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
-#define AVB_LOG_STATUS(MSG) avbLogFn2(AVB_LOG_LEVEL_STATUS, "STATUS", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
-#define AVB_LOG_DEBUG(MSG) avbLogFn2(AVB_LOG_LEVEL_DEBUG, "DEBUG", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
-#define AVB_LOG_VERBOSE(MSG) avbLogFn2(AVB_LOG_LEVEL_VERBOSE, "VERBOSE", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
-#define AVB_LOGRT_ERROR(BEGIN, ITEM, END, FMT, TYPE, VAL) avbLogRT(AVB_LOG_LEVEL_ERROR, BEGIN, ITEM, END, FMT, TYPE, VAL)
-#define AVB_LOGRT_WARNING(BEGIN, ITEM, END, FMT, TYPE, VAL) avbLogRT(AVB_LOG_LEVEL_WARNING, BEGIN, ITEM, END, FMT, TYPE, VAL)
-#define AVB_LOGRT_INFO(BEGIN, ITEM, END, FMT, TYPE, VAL) avbLogRT(AVB_LOG_LEVEL_INFO, BEGIN, ITEM, END, FMT, TYPE, VAL)
-#define AVB_LOGRT_STATUS(BEGIN, ITEM, END, FMT, TYPE, VAL) avbLogRT(AVB_LOG_LEVEL_STATUS, BEGIN, ITEM, END, FMT, TYPE, VAL)
-#define AVB_LOGRT_DEBUG(BEGIN, ITEM, END, FMT, TYPE, VAL) avbLogRT(AVB_LOG_LEVEL_DEBUG, BEGIN, ITEM, END, FMT, TYPE, VAL)
-#define AVB_LOGRT_VERBOSE(BEGIN, ITEM, END, FMT, TYPE, VAL) avbLogRT(AVB_LOG_LEVEL_VERBOSE, BEGIN, ITEM, END, FMT, TYPE, VAL)
-#else
-#define AVB_LOGF_DEV(LEVEL, FMT, ...)
-#define AVB_LOGF_ERROR(FMT, ...)
-#define AVB_LOGF_WARNING(FMT, ...)
-#define AVB_LOGF_INFO(FMT, ...)
-#define AVB_LOGF_STATUS(FMT, ...)
-#define AVB_LOGF_DEBUG(FMT, ...)
-#define AVB_LOGF_VERBOSE(FMT, ...)
-#define AVB_LOG_DEV(LEVEL, FMT, ...)
-#define AVB_LOG_ERROR(MSG)
-#define AVB_LOG_WARNING(MSG)
-#define AVB_LOG_INFO(MSG)
-#define AVB_LOG_STATUS(MSG)
-#define AVB_LOG_DEBUG(MSG)
-#define AVB_LOG_VERBOSE(MSG)
-#define AVB_LOGRT_ERROR(BEGIN, ITEM, END, FMT, TYPE, VAL)
-#define AVB_LOGRT_WARNING(BEGIN, ITEM, END, FMT, TYPE, VAL)
-#define AVB_LOGRT_INFO(BEGIN, ITEM, END, FMT, TYPE, VAL)
-#define AVB_LOGRT_STATUS(BEGIN, ITEM, END, FMT, TYPE, VAL)
-#define AVB_LOGRT_DEBUG(BEGIN, ITEM, END, FMT, TYPE, VAL)
-#define AVB_LOGRT_VERBOSE(BEGIN, ITEM, END, FMT, TYPE, VAL)
-#endif // AVB_LOG_ON
-
-// Get a queued log message. Intended to be used with the OPENAVB_LOG_PULL_MODE option.
-// Message will not be null terminated.
-U32 avbLogGetMsg(U8 *pBuf, U32 bufSize);
-
-#endif // OPENAVB_LOG_PUB_H
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+* MODULE SUMMARY : A simple logging facility for use during
+* development.
+*/
+
+#ifndef OPENAVB_LOG_PUB_H
+#define OPENAVB_LOG_PUB_H 1
+
+// ********
+// Merge Issue
+// TODO: Restructure to remove #ifdef code.
+// ********
+
+#include "openavb_platform_pub.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "openavb_types_pub.h"
+
+// Uncomment AVB_LOG_ON to enable logging.
+#define AVB_LOG_ON 1
+
+// Uncomment AVB_LOG_ON_OVERRIDE to override all AVB_LOG_ON usage in the stack to ensure all logs are off.
+//#define AVB_LOG_ON_OVERRIDE 1
+
+#ifdef AVB_LOG_ON_OVERRIDE
+#ifdef AVB_LOG_ON
+#undef AVB_LOG_ON
+#endif
+#endif
+
+#define AVB_LOG_LEVEL_NONE 0
+#define AVB_LOG_LEVEL_ERROR 1
+#define AVB_LOG_LEVEL_WARNING 2
+#define AVB_LOG_LEVEL_INFO 3
+#define AVB_LOG_LEVEL_STATUS 4
+#define AVB_LOG_LEVEL_DEBUG 5
+#define AVB_LOG_LEVEL_VERBOSE 6
+
+// Special case development logging levels for use with AVB_LOGF_DEV and AVB_LOG_DEV
+#define AVB_LOG_LEVEL_DEV_ON AVB_LOG_LEVEL_NONE
+#define AVB_LOG_LEVEL_DEV_OFF AVB_LOG_LEVEL_VERBOSE + 1
+
+// Default log level, can override in source files
+#ifndef AVB_LOG_LEVEL
+//#define AVB_LOG_LEVEL AVB_LOG_LEVEL_ERROR
+//#define AVB_LOG_LEVEL AVB_LOG_LEVEL_INFO
+#define AVB_LOG_LEVEL AVB_LOG_LEVEL_STATUS
+//#define AVB_LOG_LEVEL AVB_LOG_LEVEL_DEBUG
+//#define AVB_LOG_LEVEL AVB_LOG_LEVEL_VERBOSE
+#endif
+
+#ifndef AVB_LOG_COMPANY
+#define AVB_LOG_COMPANY "OPENAVB"
+#endif
+
+#ifndef AVB_LOG_COMPONENT
+#define AVB_LOG_COMPONENT "AVB Stack"
+#endif
+
+// Log format options and sizes. Uncomment to include the formatted info.
+#define LOG_MSG_LEN 1024
+
+// The length of the full message
+#define LOG_FULL_MSG_LEN 1024
+
+static const bool OPENAVB_LOG_TIME_INFO = FALSE;
+#define LOG_TIME_LEN 9
+//#define LOG_TIME_LEN 1
+
+static const bool OPENAVB_LOG_TIMESTAMP_INFO = TRUE;
+#define LOG_TIMESTAMP_LEN 32
+//#define LOG_TIMESTAMP_LEN 1
+
+static const bool OPENAVB_LOG_FILE_INFO = FALSE;
+//#define LOG_FILE_LEN 256
+#define LOG_FILE_LEN 1
+
+static const bool OPENAVB_LOG_PROC_INFO = FALSE;
+//#define LOG_PROC_LEN 64
+#define LOG_PROC_LEN 1
+
+static const bool OPENAVB_LOG_THREAD_INFO = FALSE;
+//#define LOG_THREAD_LEN 64
+#define LOG_THREAD_LEN 1
+
+#define LOG_RT_MSG_LEN 256
+//#define LOG_RT_MSG_LEN 1
+
+#define AVB_LOG_OUTPUT_FD stderr
+//#define AVB_LOG_OUTPUT_FD stdout
+
+// When OPENAVB_LOG_FROM_THREAD the message output will be output from a separate thread/task
+// Primary intended use is for debugging.
+// It is expected that OPENAVB_LOG_PULL_MODE will not be used at the same time as this optoin.
+static const bool OPENAVB_LOG_FROM_THREAD = TRUE;
+
+// When OPENAVB_LOG_PULL_MODE the messages will be queued and can be pulled using the
+// avbLogGetMsg() call. This could be from an logger interface module or host application.
+// It is expected that OPENAVB_LOG_FROM_THREAD will not be used at the same time as this option.
+static const bool OPENAVB_LOG_PULL_MODE = FALSE;
+
+// When using the OPENAVB_LOG_FROM_THREAD option. These defines control the behavior of the msg queue
+#define LOG_QUEUE_MSG_LEN 256
+#define LOG_QUEUE_MSG_SIZE (LOG_QUEUE_MSG_LEN + 1)
+#define LOG_QUEUE_MSG_CNT 82
+#define LOG_QUEUE_SLEEP_MSEC 100
+
+// RT (RealTime logging) related defines
+#define LOG_RT_QUEUE_CNT 128
+#define LOG_RT_BEGIN TRUE
+#define LOG_RT_ITEM TRUE
+#define LOG_RT_END TRUE
+typedef enum {
+ LOG_RT_DATATYPE_NONE,
+ LOG_RT_DATATYPE_CONST_STR,
+ LOG_RT_DATATYPE_NOW_TS,
+ LOG_RT_DATATYPE_U16,
+ LOG_RT_DATATYPE_S16,
+ LOG_RT_DATATYPE_U32,
+ LOG_RT_DATATYPE_S32,
+ LOG_RT_DATATYPE_U64,
+ LOG_RT_DATATYPE_S64,
+ LOG_RT_DATATYPE_FLOAT
+} log_rt_datatype_t;
+
+
+#define LOG_VARX(x, y) x ## y
+#define LOG_VAR(x, y) LOG_VARX(x, y)
+
+// Log a message once. Technically once every 4.2 billion attempts. Usage: IF_LOG_ONCE() AVB_LOG_INFO(...)
+#define IF_LOG_ONCE() static U32 LOG_VAR(logOnce,__LINE__) = 0; if (!LOG_VAR(logOnce,__LINE__)++)
+
+// Log a message at an interval. Usage: IF_LOG_INTERVAL(100) AVB_LOG_INFO(...)
+#define IF_LOG_INTERVAL(x) static U32 LOG_VAR(logOnce,__LINE__) = 0; if (!(LOG_VAR(logOnce,__LINE__)++ % (x)))
+
+
+#define ETH_FORMAT "%02x:%02x:%02x:%02x:%02x:%02x"
+#define ETH_OCTETS(a) (a)[0],(a)[1],(a)[2],(a)[3],(a)[4],(a)[5]
+
+#define STREAMID_FORMAT "%02x:%02x:%02x:%02x:%02x:%02x/%u"
+#define STREAMID_ARGS(s) (s)->addr[0],(s)->addr[1],(s)->addr[2],(s)->addr[3],(s)->addr[4],(s)->addr[5],(s)->uniqueID
+
+#define ENTITYID_FORMAT "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
+#define ENTITYID_ARGS(a) (a)[0],(a)[1],(a)[2],(a)[3],(a)[4],(a)[5],(a)[6],(a)[7]
+
+void avbLogInitEx(FILE *file);
+
+void avbLogInit(void);
+
+void avbLogExit(void);
+
+void avbLogFn(
+ int level,
+ const char *tag,
+ const char *company,
+ const char *component,
+ const char *path,
+ int line,
+ const char *fmt,
+ ...);
+
+void avbLogRT(int level, bool bBegin, bool bItem, bool bEnd, char *pFormat, log_rt_datatype_t dataType, void *pVar);
+
+void avbLogBuffer(
+ int level,
+ const U8 *pData,
+ int dataLen,
+ int lineLen,
+ const char *company,
+ const char *component,
+ const char *path,
+ int line);
+
+
+#define avbLogFn2(level, tag, company, component, path, line, fmt, ...) \
+ {\
+ if (level <= AVB_LOG_LEVEL) \
+ avbLogFn(0, tag, company, component, path, line, fmt, __VA_ARGS__); \
+ }
+
+#define avbLogRT2(level, bBegin, bItem, bEnd, pFormat, dataType, pVar) \
+ {\
+ if (level <= AVB_LOG_LEVEL) \
+ avbLogRT(0, bBegin, bItem, bEnd, pFormat, dataType, pVar); \
+ }
+
+#define avbLogBuffer2(level, pData, dataLen, lineLen, company, component, path, line) \
+ {\
+ if (level <= AVB_LOG_LEVEL) \
+ avbLogBuffer(0, pData, dataLen, lineLen, company, component, path, line); \
+ }
+
+#ifdef AVB_LOG_ON
+#define AVB_LOGF_DEV(LEVEL, FMT, ...) avbLogFn2(LEVEL, "DEV", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
+#define AVB_LOGF_ERROR(FMT, ...) avbLogFn2(AVB_LOG_LEVEL_ERROR, "ERROR", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
+#define AVB_LOGF_WARNING(FMT, ...) avbLogFn2(AVB_LOG_LEVEL_WARNING, "WARNING", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
+#define AVB_LOGF_INFO(FMT, ...) avbLogFn2(AVB_LOG_LEVEL_INFO, "INFO", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
+#define AVB_LOGF_STATUS(FMT, ...) avbLogFn2(AVB_LOG_LEVEL_STATUS, "STATUS", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
+#define AVB_LOGF_DEBUG(FMT, ...) avbLogFn2(AVB_LOG_LEVEL_DEBUG, "DEBUG", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
+#define AVB_LOGF_VERBOSE(FMT, ...) avbLogFn2(AVB_LOG_LEVEL_VERBOSE, "VERBOSE", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, FMT, __VA_ARGS__)
+#define AVB_LOG_DEV(LEVEL, MSG) avbLogFn2(LEVEL, "DEV", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
+#define AVB_LOG_ERROR(MSG) avbLogFn2(AVB_LOG_LEVEL_ERROR, "ERROR", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
+#define AVB_LOG_WARNING(MSG) avbLogFn2(AVB_LOG_LEVEL_WARNING, "WARNING", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
+#define AVB_LOG_INFO(MSG) avbLogFn2(AVB_LOG_LEVEL_INFO, "INFO", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
+#define AVB_LOG_STATUS(MSG) avbLogFn2(AVB_LOG_LEVEL_STATUS, "STATUS", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
+#define AVB_LOG_DEBUG(MSG) avbLogFn2(AVB_LOG_LEVEL_DEBUG, "DEBUG", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
+#define AVB_LOG_VERBOSE(MSG) avbLogFn2(AVB_LOG_LEVEL_VERBOSE, "VERBOSE", AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__, "%s", MSG)
+#define AVB_LOGRT_ERROR(BEGIN, ITEM, END, FMT, TYPE, VAL) avbLogRT2(AVB_LOG_LEVEL_ERROR, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define AVB_LOGRT_WARNING(BEGIN, ITEM, END, FMT, TYPE, VAL) avbLogRT2(AVB_LOG_LEVEL_WARNING, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define AVB_LOGRT_INFO(BEGIN, ITEM, END, FMT, TYPE, VAL) avbLogRT2(AVB_LOG_LEVEL_INFO, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define AVB_LOGRT_STATUS(BEGIN, ITEM, END, FMT, TYPE, VAL) avbLogRT2(AVB_LOG_LEVEL_STATUS, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define AVB_LOGRT_DEBUG(BEGIN, ITEM, END, FMT, TYPE, VAL) avbLogRT2(AVB_LOG_LEVEL_DEBUG, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define AVB_LOGRT_VERBOSE(BEGIN, ITEM, END, FMT, TYPE, VAL) avbLogRT2(AVB_LOG_LEVEL_VERBOSE, BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define AVB_LOG_BUFFER(LEVEL, DATA, DATALEN, LINELINE) avbLogBuffer2(LEVEL, DATA, DATALEN, LINELINE, AVB_LOG_COMPANY, AVB_LOG_COMPONENT, __FILE__, __LINE__)
+#else
+#define AVB_LOGF_DEV(LEVEL, FMT, ...)
+#define AVB_LOGF_ERROR(FMT, ...)
+#define AVB_LOGF_WARNING(FMT, ...)
+#define AVB_LOGF_INFO(FMT, ...)
+#define AVB_LOGF_STATUS(FMT, ...)
+#define AVB_LOGF_DEBUG(FMT, ...)
+#define AVB_LOGF_VERBOSE(FMT, ...)
+#define AVB_LOG_DEV(LEVEL, FMT, ...)
+#define AVB_LOG_ERROR(MSG)
+#define AVB_LOG_WARNING(MSG)
+#define AVB_LOG_INFO(MSG)
+#define AVB_LOG_STATUS(MSG)
+#define AVB_LOG_DEBUG(MSG)
+#define AVB_LOG_VERBOSE(MSG)
+#define AVB_LOGRT_ERROR(BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define AVB_LOGRT_WARNING(BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define AVB_LOGRT_INFO(BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define AVB_LOGRT_STATUS(BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define AVB_LOGRT_DEBUG(BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define AVB_LOGRT_VERBOSE(BEGIN, ITEM, END, FMT, TYPE, VAL)
+#define AVB_LOG_BUFFER(LEVEL, DATA, DATALEN, LINELINE)
+#endif // AVB_LOG_ON
+
+// Get a queued log message. Intended to be used with the OPENAVB_LOG_PULL_MODE option.
+// Message will not be null terminated.
+U32 avbLogGetMsg(U8 *pBuf, U32 bufSize);
+
+#endif // OPENAVB_LOG_PUB_H
diff --git a/lib/avtp_pipeline/include/openavb_map_pub.h b/lib/avtp_pipeline/include/openavb_map_pub.h
index ff5e2a72..02a58957 100755
--- a/lib/avtp_pipeline/include/openavb_map_pub.h
+++ b/lib/avtp_pipeline/include/openavb_map_pub.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -103,22 +104,6 @@ typedef U32(*openavb_map_transmit_interval_cb_t)(media_q_t *pMediaQ);
*/
typedef void (*openavb_map_gen_init_cb_t)(media_q_t *pMediaQ);
-/** AVDECC initialize callback for both a talker or listener.
- *
- * Entity model based configuration can be processed at this time. This
- * callback is optional and only executed when AVDECC is used to connect
- * streams. The descriptorType is expected to be of STREAM_INPUT for listeners
- * and STREAM_OUTPUT for talkers.
- *
- * \param pMediaQ A pointer to the media queue for this stream
- * \param configIdx current configuration descriptor index for the Entity Model
- * \param descriptorType The descriptorType is expected to be of STREAM_INPUT
- * for listeners and STREAM_OUTPUT for talkers.
- * \param descriptorIdx descriptor index in the Entity Model
- * \see openavb_intf_avdecc_init_cb_t
- */
-typedef void (*openavb_map_avdecc_init_cb_t)(media_q_t *pMediaQ, U16 configIdx, U16 descriptorType, U16 descriptorIdx);
-
/** A call to this callback indicates that this mapping module will be a talker.
*
* Any talker initialization can be done in this function.
@@ -207,8 +192,6 @@ typedef struct {
openavb_map_transmit_interval_cb_t map_transmit_interval_cb;
/// General initialize callback.
openavb_map_gen_init_cb_t map_gen_init_cb;
- /// AVDECC initialize callback.
- openavb_map_avdecc_init_cb_t map_avdecc_init_cb;
/// Initialize transmit callback.
openavb_map_tx_init_cb_t map_tx_init_cb;
/// Transmit callback.
diff --git a/lib/avtp_pipeline/include/openavb_platform.h b/lib/avtp_pipeline/include/openavb_platform.h
index fb079d51..52a222ec 100644
--- a/lib/avtp_pipeline/include/openavb_platform.h
+++ b/lib/avtp_pipeline/include/openavb_platform.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/include/openavb_platform_pub.h b/lib/avtp_pipeline/include/openavb_platform_pub.h
index 61233712..1d91cc5b 100644
--- a/lib/avtp_pipeline/include/openavb_platform_pub.h
+++ b/lib/avtp_pipeline/include/openavb_platform_pub.h
@@ -1,42 +1,43 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-/*
-* MODULE : Public interface for platform specific functionality
-*/
-
-#ifndef _OPENAVB_PLATFORM_PUB_H
-#define _OPENAVB_PLATFORM_PUB_H
-
-#include "openavb_types_pub.h"
-#include "openavb_osal_pub.h"
-#include "openavb_mem_tcal_pub.h"
-
-#endif // _OPENAVB_PLATFORM_PUB_H
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+* MODULE : Public interface for platform specific functionality
+*/
+
+#ifndef _OPENAVB_PLATFORM_PUB_H
+#define _OPENAVB_PLATFORM_PUB_H
+
+#include "openavb_types_pub.h"
+#include "openavb_osal_pub.h"
+#include "openavb_mem_tcal_pub.h"
+
+#endif // _OPENAVB_PLATFORM_PUB_H
diff --git a/lib/avtp_pipeline/include/openavb_pub.h b/lib/avtp_pipeline/include/openavb_pub.h
index 1f67f10e..9e530cef 100644
--- a/lib/avtp_pipeline/include/openavb_pub.h
+++ b/lib/avtp_pipeline/include/openavb_pub.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -42,13 +43,15 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
//
// These must NOT be edited for project related work
/////////////////////////////////////////////////////////
-#define AVB_CORE_NAME "AVTP Pipeline"
+#if defined(AVB_FEATURE_AVDECC) && (AVB_FEATURE_AVDECC)
+ #define AVB_CORE_NAME "AVTP AVDECC"
+#else
+ #define AVB_CORE_NAME "AVTP Pipeline"
+#endif
#define AVB_CORE_VER_MAJOR (0)
#define AVB_CORE_VER_MINOR (1)
-#define AVB_CORE_VER_REVISION (0)
-
-#define AVB_CORE_VER_FULL (AVB_CORE_VER_MAJOR << 16 | AVB_CORE_VER_MINOR << 8 | AVB_CORE_VER_REVISION)
+#define AVB_CORE_VER_REVISION (3)
// Standard release designations. Uncomment one AVB_RELEASE_TYPE
#define AVB_CORE_RELEASE_TYPE "Development"
@@ -56,6 +59,8 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
//#define AVB_CORE_RELEASE_TYPE "Beta"
//#define AVB_CORE_RELEASE_TYPE "Release"
+#define AVB_CORE_VER_FULL (AVB_CORE_VER_MAJOR << 16 | AVB_CORE_VER_MINOR << 8 | AVB_CORE_VER_REVISION)
+
#define LOG_EAVB_CORE_VERSION() AVB_LOGF_INFO("%s: %i.%i.%i (%s)", AVB_CORE_NAME, AVB_CORE_VER_MAJOR, AVB_CORE_VER_MINOR, AVB_CORE_VER_REVISION, AVB_CORE_RELEASE_TYPE)
diff --git a/lib/avtp_pipeline/include/openavb_trace.h b/lib/avtp_pipeline/include/openavb_trace.h
index fd58cde6..759d55ae 100644
--- a/lib/avtp_pipeline/include/openavb_trace.h
+++ b/lib/avtp_pipeline/include/openavb_trace.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/include/openavb_trace_pub.h b/lib/avtp_pipeline/include/openavb_trace_pub.h
index c90a83d3..c5ba1ac6 100644
--- a/lib/avtp_pipeline/include/openavb_trace_pub.h
+++ b/lib/avtp_pipeline/include/openavb_trace_pub.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/include/openavb_types.h b/lib/avtp_pipeline/include/openavb_types.h
index c042c24c..9a33fc4d 100644
--- a/lib/avtp_pipeline/include/openavb_types.h
+++ b/lib/avtp_pipeline/include/openavb_types.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/include/openavb_types_base.h b/lib/avtp_pipeline/include/openavb_types_base.h
index 1a3e2628..1edf2d0d 100644
--- a/lib/avtp_pipeline/include/openavb_types_base.h
+++ b/lib/avtp_pipeline/include/openavb_types_base.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/include/openavb_types_base_pub.h b/lib/avtp_pipeline/include/openavb_types_base_pub.h
index f568477a..4f86364a 100644
--- a/lib/avtp_pipeline/include/openavb_types_base_pub.h
+++ b/lib/avtp_pipeline/include/openavb_types_base_pub.h
@@ -1,120 +1,121 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-/*
-* MODULE : Public AVB Base Types (have no dependencies)
-*/
-
-#ifndef AVB_TYPES_BASE_PUB_H
-#define AVB_TYPES_BASE_PUB_H 1
-
-#include "openavb_types_base_tcal_pub.h"
-#include <stdbool.h>
-#include <inttypes.h>
-
-/** \file
- * Common Base AVB Types that are exposed outside of the AVB
- * stack.
- */
-
-/*
- * Useful types for OPENAVB AVB
- *
- */
-/// Number of nanoseconds in second
-#define NANOSECONDS_PER_SECOND (1000000000ULL)
-/// Number of nanoseconds in milisecond
-#define NANOSECONDS_PER_MSEC (1000000L)
-/// Number of nanoseconds in microsecond
-#define NANOSECONDS_PER_USEC (1000L)
-/// Number of microseconds in second
-#define MICROSECONDS_PER_SECOND (1000000L)
-/// Number of microseconds in milisecond
-#define MICROSECONDS_PER_MSEC (1000L)
-
-#ifndef TRUE // possible confict with gboolean
-/// True boolean value
-#define TRUE true
-/// False boolean value
-#define FALSE false
-#endif
-
-#ifndef NULL
-/// Null pointer value
-#define NULL 0
-#endif
-
-/// Signed 8 bit type
-typedef int8_t S8;
-/// Unsigned 8 bit type
-typedef uint8_t U8;
-/// Signed 16 bit type
-typedef int16_t S16;
-/// Unsigned 16 bit type
-typedef uint16_t U16;
-/// Signed 32 bit type
-typedef int32_t S32;
-/// Unsigned 32 bit type
-typedef uint32_t U32;
-/// Signed 64 bit type
-typedef int64_t S64;
-/// Unsigned 64 bit type
-typedef uint64_t U64;
-
-/// Describes role of the host
-typedef enum {
- /// Role undefined or wrong handle
- AVB_ROLE_UNDEFINED = 0,
- /// Host acts as a talker
- AVB_ROLE_TALKER,
- /// Host acts as a listener
- AVB_ROLE_LISTENER
-} avb_role_t;
-
-
-
-/// Supported AVB classes.
-typedef enum {
- /// Stream reservation class A. 8000 packets per second
- SR_CLASS_A,
- /// Stream reservation class B. 4000 packets per second
- SR_CLASS_B,
-// SR_CLASS_C,
-// SR_CLASS_D,
- /// Number of supported stream reservation classes
- MAX_AVB_SR_CLASSES
-} SRClassIdx_t;
-
-/// Regular
-#define SR_RANK_REGULAR 1
-/// Emergency
-#define SR_RANK_EMERGENCY 0
-
-#endif // AVB_TYPES_BASE_PUB_H
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+* MODULE : Public AVB Base Types (have no dependencies)
+*/
+
+#ifndef AVB_TYPES_BASE_PUB_H
+#define AVB_TYPES_BASE_PUB_H 1
+
+#include "openavb_types_base_tcal_pub.h"
+#include <stdbool.h>
+#include <inttypes.h>
+
+/** \file
+ * Common Base AVB Types that are exposed outside of the AVB
+ * stack.
+ */
+
+/*
+ * Useful types for OPENAVB AVB
+ *
+ */
+/// Number of nanoseconds in second
+#define NANOSECONDS_PER_SECOND (1000000000ULL)
+/// Number of nanoseconds in milisecond
+#define NANOSECONDS_PER_MSEC (1000000L)
+/// Number of nanoseconds in microsecond
+#define NANOSECONDS_PER_USEC (1000L)
+/// Number of microseconds in second
+#define MICROSECONDS_PER_SECOND (1000000L)
+/// Number of microseconds in milisecond
+#define MICROSECONDS_PER_MSEC (1000L)
+
+#ifndef TRUE // possible confict with gboolean
+/// True boolean value
+#define TRUE true
+/// False boolean value
+#define FALSE false
+#endif
+
+#ifndef NULL
+/// Null pointer value
+#define NULL 0
+#endif
+
+/// Signed 8 bit type
+typedef int8_t S8;
+/// Unsigned 8 bit type
+typedef uint8_t U8;
+/// Signed 16 bit type
+typedef int16_t S16;
+/// Unsigned 16 bit type
+typedef uint16_t U16;
+/// Signed 32 bit type
+typedef int32_t S32;
+/// Unsigned 32 bit type
+typedef uint32_t U32;
+/// Signed 64 bit type
+typedef int64_t S64;
+/// Unsigned 64 bit type
+typedef uint64_t U64;
+
+/// Describes role of the host
+typedef enum {
+ /// Role undefined or wrong handle
+ AVB_ROLE_UNDEFINED = 0,
+ /// Host acts as a talker
+ AVB_ROLE_TALKER,
+ /// Host acts as a listener
+ AVB_ROLE_LISTENER
+} avb_role_t;
+
+
+
+/// Supported AVB classes.
+typedef enum {
+ /// Stream reservation class A. 8000 packets per second
+ SR_CLASS_A,
+ /// Stream reservation class B. 4000 packets per second
+ SR_CLASS_B,
+// SR_CLASS_C,
+// SR_CLASS_D,
+ /// Number of supported stream reservation classes
+ MAX_AVB_SR_CLASSES
+} SRClassIdx_t;
+
+/// Regular
+#define SR_RANK_REGULAR 1
+/// Emergency
+#define SR_RANK_EMERGENCY 0
+
+#endif // AVB_TYPES_BASE_PUB_H
diff --git a/lib/avtp_pipeline/include/openavb_types_pub.h b/lib/avtp_pipeline/include/openavb_types_pub.h
index 02e61466..da58b211 100644
--- a/lib/avtp_pipeline/include/openavb_types_pub.h
+++ b/lib/avtp_pipeline/include/openavb_types_pub.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/inih/ini.c b/lib/avtp_pipeline/inih/ini.c
index 4fad5c51..d38006c9 100644
--- a/lib/avtp_pipeline/inih/ini.c
+++ b/lib/avtp_pipeline/inih/ini.c
@@ -1,292 +1,302 @@
-/* inih -- simple .INI file parser
-
-inih is released under the New BSD license (see LICENSE.txt). Go to the project
-home page for more info:
-
-http://code.google.com/p/inih/
-
-*/
-
-#include <stdio.h>
-#include <ctype.h>
-#include <string.h>
-#include <stdlib.h>
-#include "ini.h"
-
-#if !INI_USE_STACK
-#include <stdlib.h>
-#endif
-
-#define MAX_SECTION 50
-#define MAX_NAME 50
-
-/* Strip whitespace chars off end of given string, in place. Return s. */
-static char* rstrip(char* s)
-{
- char* p = s + strlen(s);
- while (p > s && isspace(*--p))
- *p = '\0';
- return s;
-}
-
-/* Return pointer to first non-whitespace char in given string. */
-static char* lskip(const char* s)
-{
- while (*s && isspace(*s))
- s++;
- return (char*)s;
-}
-
-/* Return pointer to first char c or ';' comment in given string, or pointer to
- null at end of string if neither found. ';' must be prefixed by a whitespace
- character to register as a comment. */
-static char* find_char_or_comment(const char* s, char c)
-{
- int was_whitespace = 0;
- while (*s && *s != c && !(was_whitespace && *s == ';')) {
- was_whitespace = isspace(*s);
- s++;
- }
- return (char*)s;
-}
-
-/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
-static char* strncpy0(char* dest, const char* src, size_t size)
-{
- strncpy(dest, src, size);
- dest[size - 1] = '\0';
- return dest;
-}
-
-/* See documentation in header file. */
-int ini_parse_file(FILE* file,
- int (*handler)(void*, const char*, const char*,
- const char*),
- void* user)
-{
- /* Uses a fair bit of stack (use heap instead if you need to) */
-#if INI_USE_STACK
- char line[INI_MAX_LINE];
-#else
- char* line;
-#endif
- char section[MAX_SECTION] = "";
- char prev_name[MAX_NAME] = "";
-
- char* start;
- char* end;
- char* name;
- char* value;
- int lineno = 0;
- int error = 0;
-
-#if !INI_USE_STACK
- line = (char*)malloc(INI_MAX_LINE);
- if (!line) {
- return -2;
- }
-#endif
-
- /* Scan through file line by line */
- while (fgets(line, INI_MAX_LINE, file) != NULL) {
- lineno++;
-
- start = line;
-#if INI_ALLOW_BOM
- if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
- (unsigned char)start[1] == 0xBB &&
- (unsigned char)start[2] == 0xBF) {
- start += 3;
- }
-#endif
- start = lskip(rstrip(start));
-
- if (*start == ';' || *start == '#') {
- /* Per Python ConfigParser, allow '#' comments at start of line */
- }
-#if INI_ALLOW_MULTILINE
- else if (*prev_name && *start && start > line) {
- /* Non-black line with leading whitespace, treat as continuation
- of previous name's value (as per Python ConfigParser). */
- if (!handler(user, section, prev_name, start) && !error)
- error = lineno;
- }
-#endif
- else if (*start == '[') {
- /* A "[section]" line */
- end = find_char_or_comment(start + 1, ']');
- if (*end == ']') {
- *end = '\0';
- strncpy0(section, start + 1, sizeof(section));
- *prev_name = '\0';
- }
- else if (!error) {
- /* No ']' found on section line */
- error = lineno;
- }
- }
- else if (*start && *start != ';') {
- /* Not a comment, must be a name[=:]value pair */
- end = find_char_or_comment(start, '=');
- if (*end != '=') {
- end = find_char_or_comment(start, ':');
- }
- if (*end == '=' || *end == ':') {
- *end = '\0';
- name = rstrip(start);
- value = lskip(end + 1);
- end = find_char_or_comment(value, '\0');
- if (*end == ';')
- *end = '\0';
- rstrip(value);
-
- /* Valid name[=:]value pair found, call handler */
- strncpy0(prev_name, name, sizeof(prev_name));
- if (!handler(user, section, name, value) && !error)
- error = lineno;
- }
- else if (!error) {
- /* No '=' or ':' found on name[=:]value line */
- error = lineno;
- }
- }
- }
-
-#if !INI_USE_STACK
- free(line);
-#endif
-
- return error;
-}
-
-#define NULL_CHAR '\0'
-#define COMMA ','
-
-int ini_parse_override(char *override,
- int (*handler)(void*, const char*, const char*,
- const char*),
- void* user)
-{
-#if INI_USE_STACK
- char line[INI_MAX_LINE];
-#else
- char* line;
-#endif
- char section[MAX_SECTION] = "";
- char *name, *value;
-
- char *src = override;
- int error = -1;
- int i, j;
-
-#if !INI_USE_STACK
- line = (char*)malloc(INI_MAX_LINE);
- if (!line) {
- return -2;
- }
-#endif
-
- while (*src != NULL_CHAR)
- {
- if (*src == COMMA) {
- src++;
- }
- else if (*src == '[') {
- // section
- src++; // skip opening delim
- for (i = 0; i < MAX_SECTION; i++) {
- section[i] = *src++;
- if (section[i] == NULL_CHAR) {
- // error, section not completed
- goto out;
- }
- else if (section[i] == ']') {
- section[i] = NULL_CHAR;
- break;
- }
- }
- if (i > MAX_SECTION)
- goto out; // error, overflowed buffer
- }
- else {
- // name/value
- name = &line[0];
- for (i = 0; i < MAX_NAME; i++) {
- line[i] = *src++;
- if (line[i] == NULL_CHAR) {
- // error, name not completed
- goto out;
- }
- else if (line[i] == COMMA) {
- // error, no value
- goto out;
- }
- else if (line[i] == '=') {
- line[i] = NULL_CHAR;
- break;
- }
- }
- if (i > MAX_NAME)
- goto out; // error, overflowed buffer
-
- value = &line[i + 1];
- for (j = i + 1; j < INI_MAX_LINE; j++) {
- line[j] = *src++;
- if (line[j] == ',') {
- line[j] = NULL_CHAR;
- break;
- }
- if (line[j] == NULL_CHAR) {
- src--; // oops!
- break;
- }
-
- }
- if (j > INI_MAX_LINE)
- goto out; // error, overflowed buffer
-
- if (!handler(user, section, name, value) && !error)
- error = -3;
- }
- }
-
- // all parsed!
- error = 0;
-
- out:
-#if !INI_USE_STACK
- free(line);
-#endif
- return error;
-}
-
-/* See documentation in header file. */
-int ini_parse(const char* filename,
- int (*handler)(void*, const char*, const char*, const char*),
- void* user)
-{
- FILE* file;
- int error;
- char *pvtFilename = strdup(filename);
- if (!pvtFilename) {
- return -1;
- }
-
- char *override = strchr(pvtFilename, COMMA);
- if (override)
- *override++ = '\0';
-
- file = fopen(pvtFilename, "r");
- if (!file) {
- free (pvtFilename);
- return -1;
- }
- error = ini_parse_file(file, handler, user);
-
- if (error == 0 && override)
- error = ini_parse_override(override, handler, user);
- fclose(file);
- free (pvtFilename);
-
- return error;
-}
+/* inih -- simple .INI file parser
+
+inih is released under the New BSD license (see LICENSE.txt). Go to the project
+home page for more info:
+
+http://code.google.com/p/inih/
+
+*/
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include "ini.h"
+
+#if !INI_USE_STACK
+#include <stdlib.h>
+#endif
+
+#define MAX_SECTION 50
+#define MAX_NAME 50
+
+/* Strip whitespace chars off end of given string, in place. Return s. */
+static char* rstrip(char* s)
+{
+ char* p = s + strlen(s);
+ while (p > s && isspace(*--p))
+ *p = '\0';
+ return s;
+}
+
+/* Return pointer to first non-whitespace char in given string. */
+static char* lskip(const char* s)
+{
+ while (*s && isspace(*s))
+ s++;
+ return (char*)s;
+}
+
+/* Return pointer to first char c or ';' comment in given string, or pointer to
+ null at end of string if neither found. ';' must be prefixed by a whitespace
+ character to register as a comment. */
+static char* find_char_or_comment(const char* s, char c)
+{
+ int was_whitespace = 0;
+ while (*s && *s != c && !(was_whitespace && *s == ';')) {
+ was_whitespace = isspace(*s);
+ s++;
+ }
+ return (char*)s;
+}
+
+/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
+static char* strncpy0(char* dest, const char* src, size_t size)
+{
+ strncpy(dest, src, size);
+ dest[size - 1] = '\0';
+ return dest;
+}
+
+/* See documentation in header file. */
+int ini_parse_file(FILE* file,
+ int (*handler)(void*, const char*, const char*,
+ const char*),
+ void* user)
+{
+ /* Uses a fair bit of stack (use heap instead if you need to) */
+#if INI_USE_STACK
+ char line[INI_MAX_LINE];
+#else
+ char* line;
+#endif
+ char section[MAX_SECTION] = "";
+ char prev_name[MAX_NAME] = "";
+
+ char* start;
+ char* end;
+ char* name;
+ char* value;
+ int lineno = 0;
+ int error = 0;
+ int value_quoted = 0;
+
+#if !INI_USE_STACK
+ line = (char*)malloc(INI_MAX_LINE);
+ if (!line) {
+ return -2;
+ }
+#endif
+
+ /* Scan through file line by line */
+ while (fgets(line, INI_MAX_LINE, file) != NULL) {
+ lineno++;
+
+ start = line;
+#if INI_ALLOW_BOM
+ if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
+ (unsigned char)start[1] == 0xBB &&
+ (unsigned char)start[2] == 0xBF) {
+ start += 3;
+ }
+#endif
+ start = lskip(rstrip(start));
+
+ if (*start == ';' || *start == '#') {
+ /* Per Python ConfigParser, allow '#' comments at start of line */
+ }
+#if INI_ALLOW_MULTILINE
+ else if (*prev_name && *start && start > line) {
+ /* Non-black line with leading whitespace, treat as continuation
+ of previous name's value (as per Python ConfigParser). */
+ if (!handler(user, section, prev_name, start) && !error)
+ error = lineno;
+ }
+#endif
+ else if (*start == '[') {
+ /* A "[section]" line */
+ end = find_char_or_comment(start + 1, ']');
+ if (*end == ']') {
+ *end = '\0';
+ strncpy0(section, start + 1, sizeof(section));
+ *prev_name = '\0';
+ }
+ else if (!error) {
+ /* No ']' found on section line */
+ error = lineno;
+ }
+ }
+ else if (*start && *start != ';') {
+ /* Not a comment, must be a name[=:]value pair */
+ end = find_char_or_comment(start, '=');
+ if (*end != '=') {
+ end = find_char_or_comment(start, ':');
+ }
+ if (*end == '=' || *end == ':') {
+ *end = '\0';
+ name = rstrip(start);
+ value = lskip(end + 1);
+ end = find_char_or_comment(value, '\0');
+ if (*end == ';')
+ *end = '\0';
+ rstrip(value);
+
+ /* If the value starts and ends with a quote character, extract the string from inside the quotes. */
+ if (value[0] == '\"') {
+ char *end_quote = strchr(value + 1, '\"');
+ if (end_quote) {
+ *end_quote = '\0';
+ value_quoted = 1;
+ }
+ }
+
+ /* Valid name[=:]value pair found, call handler */
+ strncpy0(prev_name, name, sizeof(prev_name));
+ if (!handler(user, section, name, (value_quoted ? value + 1 : value)) && !error)
+ error = lineno;
+ }
+ else if (!error) {
+ /* No '=' or ':' found on name[=:]value line */
+ error = lineno;
+ }
+ }
+ }
+
+#if !INI_USE_STACK
+ free(line);
+#endif
+
+ return error;
+}
+
+#define NULL_CHAR '\0'
+#define COMMA ','
+
+int ini_parse_override(char *override,
+ int (*handler)(void*, const char*, const char*,
+ const char*),
+ void* user)
+{
+#if INI_USE_STACK
+ char line[INI_MAX_LINE];
+#else
+ char* line;
+#endif
+ char section[MAX_SECTION] = "";
+ char *name, *value;
+
+ char *src = override;
+ int error = -1;
+ int i, j;
+
+#if !INI_USE_STACK
+ line = (char*)malloc(INI_MAX_LINE);
+ if (!line) {
+ return -2;
+ }
+#endif
+
+ while (*src != NULL_CHAR)
+ {
+ if (*src == COMMA) {
+ src++;
+ }
+ else if (*src == '[') {
+ // section
+ src++; // skip opening delim
+ for (i = 0; i < MAX_SECTION; i++) {
+ section[i] = *src++;
+ if (section[i] == NULL_CHAR) {
+ // error, section not completed
+ goto out;
+ }
+ else if (section[i] == ']') {
+ section[i] = NULL_CHAR;
+ break;
+ }
+ }
+ if (i > MAX_SECTION)
+ goto out; // error, overflowed buffer
+ }
+ else {
+ // name/value
+ name = &line[0];
+ for (i = 0; i < MAX_NAME; i++) {
+ line[i] = *src++;
+ if (line[i] == NULL_CHAR) {
+ // error, name not completed
+ goto out;
+ }
+ else if (line[i] == COMMA) {
+ // error, no value
+ goto out;
+ }
+ else if (line[i] == '=') {
+ line[i] = NULL_CHAR;
+ break;
+ }
+ }
+ if (i > MAX_NAME)
+ goto out; // error, overflowed buffer
+
+ value = &line[i + 1];
+ for (j = i + 1; j < INI_MAX_LINE; j++) {
+ line[j] = *src++;
+ if (line[j] == ',') {
+ line[j] = NULL_CHAR;
+ break;
+ }
+ if (line[j] == NULL_CHAR) {
+ src--; // oops!
+ break;
+ }
+
+ }
+ if (j > INI_MAX_LINE)
+ goto out; // error, overflowed buffer
+
+ if (!handler(user, section, name, value) && !error)
+ error = -3;
+ }
+ }
+
+ // all parsed!
+ error = 0;
+
+ out:
+#if !INI_USE_STACK
+ free(line);
+#endif
+ return error;
+}
+
+/* See documentation in header file. */
+int ini_parse(const char* filename,
+ int (*handler)(void*, const char*, const char*, const char*),
+ void* user)
+{
+ FILE* file;
+ int error;
+ char *pvtFilename = strdup(filename);
+ if (!pvtFilename) {
+ return -1;
+ }
+
+ char *override = strchr(pvtFilename, COMMA);
+ if (override)
+ *override++ = '\0';
+
+ file = fopen(pvtFilename, "r");
+ if (!file) {
+ free (pvtFilename);
+ return -1;
+ }
+ error = ini_parse_file(file, handler, user);
+
+ if (error == 0 && override)
+ error = ini_parse_override(override, handler, user);
+ fclose(file);
+ free (pvtFilename);
+
+ return error;
+}
diff --git a/lib/avtp_pipeline/inih/ini.h b/lib/avtp_pipeline/inih/ini.h
index 9ebfd492..984d52b7 100644
--- a/lib/avtp_pipeline/inih/ini.h
+++ b/lib/avtp_pipeline/inih/ini.h
@@ -1,72 +1,72 @@
-/* inih -- simple .INI file parser
-
-inih is released under the New BSD license (see LICENSE.txt). Go to the project
-home page for more info:
-
-http://code.google.com/p/inih/
-
-*/
-
-#ifndef __INI_H__
-#define __INI_H__
-
-/* Make this header file easier to include in C++ code */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stdio.h>
-
-/* Parse given INI-style file. May have [section]s, name=value pairs
- (whitespace stripped), and comments starting with ';' (semicolon). Section
- is "" if name=value pair parsed before any section heading. name:value
- pairs are also supported as a concession to Python's ConfigParser.
-
- For each name=value pair parsed, call handler function with given user
- pointer as well as section, name, and value (data only valid for duration
- of handler call). Handler should return nonzero on success, zero on error.
-
- Returns 0 on success, line number of first error on parse error (doesn't
- stop on first error), -1 on file open error, or -2 on memory allocation
- error (only when INI_USE_STACK is zero).
-*/
-int ini_parse(const char* filename,
- int (*handler)(void* user, const char* section,
- const char* name, const char* value),
- void* user);
-
-/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't
- close the file when it's finished -- the caller must do that. */
-int ini_parse_file(FILE* file,
- int (*handler)(void* user, const char* section,
- const char* name, const char* value),
- void* user);
-
-/* Nonzero to allow multi-line value parsing, in the style of Python's
- ConfigParser. If allowed, ini_parse() will call the handler with the same
- name for each subsequent line parsed. */
-#ifndef INI_ALLOW_MULTILINE
-#define INI_ALLOW_MULTILINE 1
-#endif
-
-/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of
- the file. See http://code.google.com/p/inih/issues/detail?id=21 */
-#ifndef INI_ALLOW_BOM
-#define INI_ALLOW_BOM 1
-#endif
-
-/* Nonzero to use stack, zero to use heap (malloc/free). */
-#ifndef INI_USE_STACK
-#define INI_USE_STACK 1
-#endif
-
-/* Maximum line length for any line in INI file. */
-#ifndef INI_MAX_LINE
-#define INI_MAX_LINE 512
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __INI_H__ */
+/* inih -- simple .INI file parser
+
+inih is released under the New BSD license (see LICENSE.txt). Go to the project
+home page for more info:
+
+http://code.google.com/p/inih/
+
+*/
+
+#ifndef __INI_H__
+#define __INI_H__
+
+/* Make this header file easier to include in C++ code */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+
+/* Parse given INI-style file. May have [section]s, name=value pairs
+ (whitespace stripped), and comments starting with ';' (semicolon). Section
+ is "" if name=value pair parsed before any section heading. name:value
+ pairs are also supported as a concession to Python's ConfigParser.
+
+ For each name=value pair parsed, call handler function with given user
+ pointer as well as section, name, and value (data only valid for duration
+ of handler call). Handler should return nonzero on success, zero on error.
+
+ Returns 0 on success, line number of first error on parse error (doesn't
+ stop on first error), -1 on file open error, or -2 on memory allocation
+ error (only when INI_USE_STACK is zero).
+*/
+int ini_parse(const char* filename,
+ int (*handler)(void* user, const char* section,
+ const char* name, const char* value),
+ void* user);
+
+/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't
+ close the file when it's finished -- the caller must do that. */
+int ini_parse_file(FILE* file,
+ int (*handler)(void* user, const char* section,
+ const char* name, const char* value),
+ void* user);
+
+/* Nonzero to allow multi-line value parsing, in the style of Python's
+ ConfigParser. If allowed, ini_parse() will call the handler with the same
+ name for each subsequent line parsed. */
+#ifndef INI_ALLOW_MULTILINE
+#define INI_ALLOW_MULTILINE 1
+#endif
+
+/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of
+ the file. See http://code.google.com/p/inih/issues/detail?id=21 */
+#ifndef INI_ALLOW_BOM
+#define INI_ALLOW_BOM 1
+#endif
+
+/* Nonzero to use stack, zero to use heap (malloc/free). */
+#ifndef INI_USE_STACK
+#define INI_USE_STACK 1
+#endif
+
+/* Maximum line length for any line in INI file. */
+#ifndef INI_MAX_LINE
+#define INI_MAX_LINE 512
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INI_H__ */
diff --git a/lib/avtp_pipeline/intf_ctrl/ctrl_listener.ini b/lib/avtp_pipeline/intf_ctrl/ctrl_listener.ini
index 08c509a5..1ba2b6ba 100644
--- a/lib/avtp_pipeline/intf_ctrl/ctrl_listener.ini
+++ b/lib/avtp_pipeline/intf_ctrl/ctrl_listener.ini
@@ -5,6 +5,12 @@
# talker or listener
role = listener
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
stream_addr = 00:0c:29:f8:3e:c6
diff --git a/lib/avtp_pipeline/intf_ctrl/ctrl_mux_listener.ini b/lib/avtp_pipeline/intf_ctrl/ctrl_mux_listener.ini
index 19d6be55..1c01df87 100644
--- a/lib/avtp_pipeline/intf_ctrl/ctrl_mux_listener.ini
+++ b/lib/avtp_pipeline/intf_ctrl/ctrl_mux_listener.ini
@@ -5,6 +5,12 @@
# talker or listener
role = listener
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
stream_addr = 00:0c:29:f8:3e:c6
diff --git a/lib/avtp_pipeline/intf_ctrl/ctrl_mux_talker.ini b/lib/avtp_pipeline/intf_ctrl/ctrl_mux_talker.ini
index ad4c0716..2926d9b5 100644
--- a/lib/avtp_pipeline/intf_ctrl/ctrl_mux_talker.ini
+++ b/lib/avtp_pipeline/intf_ctrl/ctrl_mux_talker.ini
@@ -5,6 +5,12 @@
# talker or listener
role = talker
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
#stream_addr = 00:25:64:48:ca:a8
diff --git a/lib/avtp_pipeline/intf_ctrl/ctrl_talker.ini b/lib/avtp_pipeline/intf_ctrl/ctrl_talker.ini
index 747ff19b..33a150a6 100644
--- a/lib/avtp_pipeline/intf_ctrl/ctrl_talker.ini
+++ b/lib/avtp_pipeline/intf_ctrl/ctrl_talker.ini
@@ -5,6 +5,12 @@
# talker or listener
role = talker
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
#stream_addr = 00:25:64:48:ca:a8
diff --git a/lib/avtp_pipeline/intf_ctrl/openavb_intf_ctrl.c b/lib/avtp_pipeline/intf_ctrl/openavb_intf_ctrl.c
index 3a7ddec0..74e6dbb5 100755
--- a/lib/avtp_pipeline/intf_ctrl/openavb_intf_ctrl.c
+++ b/lib/avtp_pipeline/intf_ctrl/openavb_intf_ctrl.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/intf_ctrl/openavb_intf_ctrl_pub.h b/lib/avtp_pipeline/intf_ctrl/openavb_intf_ctrl_pub.h
index 6f4fc104..1cc242a7 100755
--- a/lib/avtp_pipeline/intf_ctrl/openavb_intf_ctrl_pub.h
+++ b/lib/avtp_pipeline/intf_ctrl/openavb_intf_ctrl_pub.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/intf_echo/echo_listener.ini b/lib/avtp_pipeline/intf_echo/echo_listener.ini
index e926dd5b..73e8cf00 100644
--- a/lib/avtp_pipeline/intf_echo/echo_listener.ini
+++ b/lib/avtp_pipeline/intf_echo/echo_listener.ini
@@ -5,6 +5,12 @@
# talker or listener
role = listener
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
stream_addr = 00:0c:29:f8:3e:c6
diff --git a/lib/avtp_pipeline/intf_echo/echo_listener_auto.ini b/lib/avtp_pipeline/intf_echo/echo_listener_auto.ini
index b3a9642e..5fa3df3d 100644
--- a/lib/avtp_pipeline/intf_echo/echo_listener_auto.ini
+++ b/lib/avtp_pipeline/intf_echo/echo_listener_auto.ini
@@ -5,6 +5,12 @@
# talker or listener
role = listener
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
stream_addr = ba:bc:1a:ba:bc:1a
diff --git a/lib/avtp_pipeline/intf_echo/echo_talker.ini b/lib/avtp_pipeline/intf_echo/echo_talker.ini
index 6987e03c..28e22d5f 100644
--- a/lib/avtp_pipeline/intf_echo/echo_talker.ini
+++ b/lib/avtp_pipeline/intf_echo/echo_talker.ini
@@ -5,6 +5,12 @@
# talker or listener
role = talker
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
stream_addr = a0:36:9f:66:8c:9f
diff --git a/lib/avtp_pipeline/intf_echo/echo_talker_auto.ini b/lib/avtp_pipeline/intf_echo/echo_talker_auto.ini
index 66326964..affa10a7 100644
--- a/lib/avtp_pipeline/intf_echo/echo_talker_auto.ini
+++ b/lib/avtp_pipeline/intf_echo/echo_talker_auto.ini
@@ -5,6 +5,12 @@
# talker or listener
role = talker
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
stream_addr = ba:bc:1a:ba:bc:1a
diff --git a/lib/avtp_pipeline/intf_echo/openavb_intf_echo.c b/lib/avtp_pipeline/intf_echo/openavb_intf_echo.c
index 4bc2f6ae..9385bb9f 100755
--- a/lib/avtp_pipeline/intf_echo/openavb_intf_echo.c
+++ b/lib/avtp_pipeline/intf_echo/openavb_intf_echo.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -77,6 +78,10 @@ typedef struct {
/////////////
// When increment is enable this is the counter
U32 Counter;
+
+ bool fixedTimestampEnabled;
+ U32 tsIncrement;
+ avtp_time_t walltime;
} pvt_data_t;
@@ -168,6 +173,9 @@ void openavbIntfEchoTxInitCB(media_q_t *pMediaQ)
}
pPvtData->Counter = 0;
+
+ if (pPvtData->fixedTimestampEnabled)
+ openavbAvtpTimeSetToWallTime(&pPvtData->walltime);
}
AVB_TRACE_EXIT(AVB_TRACE_INTF);
@@ -187,7 +195,7 @@ bool openavbIntfEchoTxCB(media_q_t *pMediaQ)
media_q_item_t *pMediaQItem = openavbMediaQHeadLock(pMediaQ);
if (pMediaQItem) {
- if (pMediaQItem->itemSize >= pPvtData->increment ? pPvtData->echoStringLen + 16 : pPvtData->echoStringLen) {
+ if (pMediaQItem->itemSize >= (pPvtData->increment ? pPvtData->echoStringLen + 16 : pPvtData->echoStringLen)) {
if (pPvtData->increment) {
int len = sprintf(pMediaQItem->pPubData, "%s %u", pPvtData->pEchoString, pPvtData->Counter++);
pMediaQItem->dataLen = len;
@@ -209,7 +217,12 @@ bool openavbIntfEchoTxCB(media_q_t *pMediaQ)
printf("%s\n\r", (char *)pMediaQItem->pPubData);
}
- openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
+ if (pPvtData->fixedTimestampEnabled) {
+ openavbAvtpTimeAddUSec(&pPvtData->walltime, pPvtData->tsIncrement);
+ *pMediaQItem->pAvtpTime = pPvtData->walltime;
+ } else {
+ openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
+ }
openavbMediaQHeadPush(pMediaQ);
AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
return TRUE;
@@ -311,6 +324,25 @@ void openavbIntfEchoGenEndCB(media_q_t *pMediaQ)
AVB_TRACE_EXIT(AVB_TRACE_INTF);
}
+void openavbIntfEchoEnableFixedTimestamp(media_q_t *pMediaQ, bool enabled, U32 transmitInterval, U32 batchFactor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ if (pMediaQ && pMediaQ->pPvtIntfInfo) {
+ pvt_data_t *pPvtData = (pvt_data_t *)pMediaQ->pPvtIntfInfo;
+
+ pPvtData->fixedTimestampEnabled = enabled;
+ if (pPvtData->fixedTimestampEnabled) {
+ pPvtData->tsIncrement = NANOSECONDS_PER_SECOND/transmitInterval;
+ }
+
+ if (batchFactor != 1) {
+ AVB_LOGF_WARNING("batchFactor of %d ignored (must be 1)", batchFactor);
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
// Main initialization entry point into the interface module
extern bool DLL_EXPORT openavbIntfEchoInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB)
{
@@ -334,6 +366,7 @@ extern bool DLL_EXPORT openavbIntfEchoInitialize(media_q_t *pMediaQ, openavb_int
pIntfCB->intf_rx_cb = openavbIntfEchoRxCB;
pIntfCB->intf_end_cb = openavbIntfEchoEndCB;
pIntfCB->intf_gen_end_cb = openavbIntfEchoGenEndCB;
+ pIntfCB->intf_enable_fixed_timestamp = openavbIntfEchoEnableFixedTimestamp;
pPvtData->pEchoString = NULL;
pPvtData->echoStringRepeat = 1;
@@ -342,6 +375,7 @@ extern bool DLL_EXPORT openavbIntfEchoInitialize(media_q_t *pMediaQ, openavb_int
pPvtData->txLocalEcho = FALSE;
pPvtData->noNewline = FALSE;
pPvtData->ignoreTimestamp = FALSE;
+ pPvtData->fixedTimestampEnabled = FALSE;
}
AVB_TRACE_EXIT(AVB_TRACE_INTF);
diff --git a/lib/avtp_pipeline/intf_logger/openavb_intf_logger.c b/lib/avtp_pipeline/intf_logger/openavb_intf_logger.c
index 38adaecc..dae91fce 100644
--- a/lib/avtp_pipeline/intf_logger/openavb_intf_logger.c
+++ b/lib/avtp_pipeline/intf_logger/openavb_intf_logger.c
@@ -1,201 +1,202 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-/*
-* Usage Notes: It is expected that there will be at most only 1 logger
-* interface module running.
-*/
-
-#include <stdlib.h>
-#include <string.h>
-#include "openavb_types_pub.h"
-#include "openavb_trace_pub.h"
-#include "openavb_mediaq_pub.h"
-#include "openavb_intf_pub.h"
-
-#define AVB_LOG_COMPONENT "Logger Interface"
-#include "openavb_log_pub.h"
-
-typedef struct {
- /////////////
- // Config data
- /////////////
- // Ignore timestamp at listener.
- bool ignoreTimestamp;
-
- /////////////
- // Variable data
- /////////////
-} pvt_data_t;
-
-
-// Each configuration name value pair for this mapping will result in this callback being called.
-void openavbIntfLoggerCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_INTF);
- if (pMediaQ) {
- //char *pEnd;
- //long tmp;
-
- pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
- if (!pPvtData) {
- AVB_LOG_ERROR("Private interface module data not allocated.");
- return;
- }
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_INTF);
-}
-
-void openavbIntfLoggerGenInitCB(media_q_t *pMediaQ)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_INTF);
- AVB_TRACE_EXIT(AVB_TRACE_INTF);
-}
-
-// A call to this callback indicates that this interface module will be
-// a talker. Any talker initialization can be done in this function.
-void openavbIntfLoggerTxInitCB(media_q_t *pMediaQ)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_INTF);
-
- if (pMediaQ) {
- pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
- if (!pPvtData) {
- AVB_LOG_ERROR("Private interface module data not allocated.");
- return;
- }
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_INTF);
-}
-
-// This callback will be called for each AVB transmit interval. Commonly this will be
-// 4000 or 8000 times per second.
-bool openavbIntfLoggerTxCB(media_q_t *pMediaQ)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
- if (pMediaQ) {
- pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
- if (!pPvtData) {
- AVB_LOG_ERROR("Private interface module data not allocated.");
- return FALSE;
- }
-
- media_q_item_t *pMediaQItem = openavbMediaQHeadLock(pMediaQ);
- if (pMediaQItem) {
- U32 dataLen = avbLogGetMsg(pMediaQItem->pPubData, pMediaQItem->itemSize);
- if (dataLen) {
- pMediaQItem->dataLen = dataLen;
- openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
- openavbMediaQHeadPush(pMediaQ);
- AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
- return TRUE;
- }
- else {
- openavbMediaQHeadUnlock(pMediaQ);
- }
- }
- else {
- AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
- return FALSE; // Media queue full
- }
- }
- AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
- return FALSE;
-}
-
-// A call to this callback indicates that this interface module will be
-// a listener. Any listener initialization can be done in this function.
-void openavbIntfLoggerRxInitCB(media_q_t *pMediaQ)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_INTF);
- AVB_TRACE_EXIT(AVB_TRACE_INTF);
-}
-
-// This callback is called when acting as a listener.
-bool openavbIntfLoggerRxCB(media_q_t *pMediaQ)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
- AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
- return FALSE;
-}
-
-// This callback will be called when the stream is closing.
-void openavbIntfLoggerEndCB(media_q_t *pMediaQ)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_INTF);
- AVB_TRACE_EXIT(AVB_TRACE_INTF);
-}
-
-// General shutdown callback regardless if a talker or listener. Called once during openavbTLClose()
-void openavbIntfLoggerGenEndCB(media_q_t *pMediaQ)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_INTF);
- if (pMediaQ) {
- pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
- if (!pPvtData) {
- AVB_LOG_ERROR("Private interface module data not allocated.");
- return;
- }
- }
- AVB_TRACE_EXIT(AVB_TRACE_INTF);
-}
-
-// Main initialization entry point into the interface module
-extern bool DLL_EXPORT openavbIntfLoggerInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_INTF);
-
- if (pMediaQ) {
- pMediaQ->pPvtIntfInfo = calloc(1, sizeof(pvt_data_t)); // Memory freed by the media queue when the media queue is destroyed.
-
- if (!pMediaQ->pPvtIntfInfo) {
- AVB_LOG_ERROR("Unable to allocate memory for AVTP interface module.");
- return FALSE;
- }
-
- pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
-
- pIntfCB->intf_cfg_cb = openavbIntfLoggerCfgCB;
- pIntfCB->intf_gen_init_cb = openavbIntfLoggerGenInitCB;
- pIntfCB->intf_tx_init_cb = openavbIntfLoggerTxInitCB;
- pIntfCB->intf_tx_cb = openavbIntfLoggerTxCB;
- pIntfCB->intf_rx_init_cb = openavbIntfLoggerRxInitCB;
- pIntfCB->intf_rx_cb = openavbIntfLoggerRxCB;
- pIntfCB->intf_end_cb = openavbIntfLoggerEndCB;
- pIntfCB->intf_gen_end_cb = openavbIntfLoggerGenEndCB;
-
- pPvtData->ignoreTimestamp = FALSE;
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_INTF);
- return TRUE;
-}
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+* Usage Notes: It is expected that there will be at most only 1 logger
+* interface module running.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include "openavb_types_pub.h"
+#include "openavb_trace_pub.h"
+#include "openavb_mediaq_pub.h"
+#include "openavb_intf_pub.h"
+
+#define AVB_LOG_COMPONENT "Logger Interface"
+#include "openavb_log_pub.h"
+
+typedef struct {
+ /////////////
+ // Config data
+ /////////////
+ // Ignore timestamp at listener.
+ bool ignoreTimestamp;
+
+ /////////////
+ // Variable data
+ /////////////
+} pvt_data_t;
+
+
+// Each configuration name value pair for this mapping will result in this callback being called.
+void openavbIntfLoggerCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ if (pMediaQ) {
+ //char *pEnd;
+ //long tmp;
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+void openavbIntfLoggerGenInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// A call to this callback indicates that this interface module will be
+// a talker. Any talker initialization can be done in this function.
+void openavbIntfLoggerTxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// This callback will be called for each AVB transmit interval. Commonly this will be
+// 4000 or 8000 times per second.
+bool openavbIntfLoggerTxCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return FALSE;
+ }
+
+ media_q_item_t *pMediaQItem = openavbMediaQHeadLock(pMediaQ);
+ if (pMediaQItem) {
+ U32 dataLen = avbLogGetMsg(pMediaQItem->pPubData, pMediaQItem->itemSize);
+ if (dataLen) {
+ pMediaQItem->dataLen = dataLen;
+ openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
+ openavbMediaQHeadPush(pMediaQ);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return TRUE;
+ }
+ else {
+ openavbMediaQHeadUnlock(pMediaQ);
+ }
+ }
+ else {
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE; // Media queue full
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE;
+}
+
+// A call to this callback indicates that this interface module will be
+// a listener. Any listener initialization can be done in this function.
+void openavbIntfLoggerRxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// This callback is called when acting as a listener.
+bool openavbIntfLoggerRxCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE;
+}
+
+// This callback will be called when the stream is closing.
+void openavbIntfLoggerEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// General shutdown callback regardless if a talker or listener. Called once during openavbTLClose()
+void openavbIntfLoggerGenEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// Main initialization entry point into the interface module
+extern bool DLL_EXPORT openavbIntfLoggerInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ pMediaQ->pPvtIntfInfo = calloc(1, sizeof(pvt_data_t)); // Memory freed by the media queue when the media queue is destroyed.
+
+ if (!pMediaQ->pPvtIntfInfo) {
+ AVB_LOG_ERROR("Unable to allocate memory for AVTP interface module.");
+ return FALSE;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+
+ pIntfCB->intf_cfg_cb = openavbIntfLoggerCfgCB;
+ pIntfCB->intf_gen_init_cb = openavbIntfLoggerGenInitCB;
+ pIntfCB->intf_tx_init_cb = openavbIntfLoggerTxInitCB;
+ pIntfCB->intf_tx_cb = openavbIntfLoggerTxCB;
+ pIntfCB->intf_rx_init_cb = openavbIntfLoggerRxInitCB;
+ pIntfCB->intf_rx_cb = openavbIntfLoggerRxCB;
+ pIntfCB->intf_end_cb = openavbIntfLoggerEndCB;
+ pIntfCB->intf_gen_end_cb = openavbIntfLoggerGenEndCB;
+
+ pPvtData->ignoreTimestamp = FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/intf_null/null_listener.ini b/lib/avtp_pipeline/intf_null/null_listener.ini
index 2645f0fa..f44dc602 100644
--- a/lib/avtp_pipeline/intf_null/null_listener.ini
+++ b/lib/avtp_pipeline/intf_null/null_listener.ini
@@ -5,6 +5,12 @@
# talker or listener
role = listener
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
stream_addr = 00:0c:29:f8:3e:c6
diff --git a/lib/avtp_pipeline/intf_null/null_talker.ini b/lib/avtp_pipeline/intf_null/null_talker.ini
index 3f440cbd..408fc6af 100644
--- a/lib/avtp_pipeline/intf_null/null_talker.ini
+++ b/lib/avtp_pipeline/intf_null/null_talker.ini
@@ -5,6 +5,12 @@
# talker or listener
role = talker
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
#stream_addr = 00:25:64:48:ca:a8
diff --git a/lib/avtp_pipeline/intf_null/openavb_intf_null.c b/lib/avtp_pipeline/intf_null/openavb_intf_null.c
index 6ce7bc42..b633bde9 100755
--- a/lib/avtp_pipeline/intf_null/openavb_intf_null.c
+++ b/lib/avtp_pipeline/intf_null/openavb_intf_null.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/intf_tonegen/openavb_intf_tonegen.c b/lib/avtp_pipeline/intf_tonegen/openavb_intf_tonegen.c
index d9b214a8..b6e0951d 100644
--- a/lib/avtp_pipeline/intf_tonegen/openavb_intf_tonegen.c
+++ b/lib/avtp_pipeline/intf_tonegen/openavb_intf_tonegen.c
@@ -1,524 +1,707 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-/*
-* MODULE SUMMARY : Tone generator interface module. Talker only.
-*
-* - This interface module generates and audio tone for use with -6 and AAF mappings
-* - Requires an OSAL sin implementation of reasonable performance.
-*/
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include "openavb_platform_pub.h"
-#include "openavb_osal_pub.h"
-#include "openavb_types_pub.h"
-#include "openavb_trace_pub.h"
-#include "openavb_mediaq_pub.h"
-#include "openavb_map_uncmp_audio_pub.h"
-#include "openavb_map_aaf_audio_pub.h"
-#include "openavb_intf_pub.h"
-
-#define AVB_LOG_COMPONENT "Tone Gen Interface"
-#include "openavb_log_pub.h"
-
-#define PI 3.14159265358979f
-
-typedef struct {
- /////////////
- // Config data
- /////////////
- // intf_nv_tone_hz: The tone hz to generate
- U32 toneHz;
-
- // intf_nv_on_off_interval_msec: Interval for turning tone on and off. A value of zero will keep the tone on.
- U32 onOffIntervalMSec;
-
- // Simple melody
- char *pMelodyString;
-
- // intf_nv_audio_rate
- avb_audio_rate_t audioRate;
-
- // intf_nv_audio_type
- avb_audio_bit_depth_t audioType;
-
- // intf_nv_audio_bit_depth
- avb_audio_bit_depth_t audioBitDepth;
-
- // intf_nv_audio_endian
- avb_audio_bit_depth_t audioEndian;
-
- // intf_nv_channels
- avb_audio_channels_t audioChannels;
-
- /////////////
- // Variable data
- /////////////
-
- // Packing interval
- U32 intervalCounter;
-
- // Keeps track of if the tone is currently on or off
- U32 freq;
-
- // Keeps track of how long before toggling the tone on / off
- U32 freqCountdown;
-
- // Ratio precalc
- float ratio;
-
- // Index to into the melody string
- U32 melodyIdx;
-
- // Length of the melody string
- U32 melodyLen;
-
-} pvt_data_t;
-
-#define MSEC_PER_COUNT 250
-static void xGetMelodyToneAndDuration(char note, char count, U32 *freq, U32 *sampleMSec)
-{
- switch (note) {
- case 'A':
- *freq = 220;
- break;
- case 'B':
- *freq = 246;
- break;
- case 'C':
- *freq = 261;
- break;
- case 'D':
- *freq = 293;
- break;
- case 'E':
- *freq = 329;
- break;
- case 'F':
- *freq = 349;
- break;
- case 'G':
- *freq = 391;
- break;
- case 'a':
- *freq = 440;
- break;
- case 'b':
- *freq = 493;
- break;
- case 'c':
- *freq = 523;
- break;
- case 'd':
- *freq = 587;
- break;
- case 'e':
- *freq = 659;
- break;
- case 'f':
- *freq = 698;
- break;
- case 'g':
- *freq = 783;
- break;
- case '-':
- default:
- *freq = 0;
- break;
- }
-
- switch (count) {
- case '1':
- *sampleMSec = MSEC_PER_COUNT * 1;
- break;
- case '2':
- *sampleMSec = MSEC_PER_COUNT * 2;
- break;
- case '3':
- *sampleMSec = MSEC_PER_COUNT * 3;
- break;
- case '4':
- *sampleMSec = MSEC_PER_COUNT * 4;
- break;
- default:
- *sampleMSec = MSEC_PER_COUNT * 4;
- break;
- }
-}
-
-static bool xSupportedMappingFormat(media_q_t *pMediaQ)
-{
- if (pMediaQ) {
- if (pMediaQ->pMediaQDataFormat) {
- if (strcmp(pMediaQ->pMediaQDataFormat, MapUncmpAudioMediaQDataFormat) == 0 || strcmp(pMediaQ->pMediaQDataFormat, MapAVTPAudioMediaQDataFormat) == 0) {
- return TRUE;
- }
- }
- }
- return FALSE;
-}
-
-// Each configuration name value pair for this mapping will result in this callback being called.
-void openavbIntfToneGenCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_INTF);
-
- char *pEnd;
- U32 val;
-
- if (pMediaQ) {
- pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
- if (!pPvtData) {
- AVB_LOG_ERROR("Private interface module data not allocated.");
- return;
- }
-
- media_q_pub_map_uncmp_audio_info_t *pPubMapUncmpAudioInfo;
- pPubMapUncmpAudioInfo = (media_q_pub_map_uncmp_audio_info_t *)pMediaQ->pPubMapInfo;
- if (!pPubMapUncmpAudioInfo) {
- AVB_LOG_ERROR("Public map data for audio info not allocated.");
- return;
- }
-
- if (strcmp(name, "intf_nv_tone_hz") == 0) {
- pPvtData->toneHz = strtol(value, &pEnd, 10);
- }
-
- else if (strcmp(name, "intf_nv_on_off_interval_msec") == 0) {
- pPvtData->onOffIntervalMSec = strtol(value, &pEnd, 10);
- }
-
- else if (strcmp(name, "intf_nv_melody_string") == 0) {
- if (pPvtData->pMelodyString)
- free(pPvtData->pMelodyString);
- pPvtData->pMelodyString = strdup(value);
- if (pPvtData->pMelodyString) {
- pPvtData->melodyLen = strlen(pPvtData->pMelodyString);
- }
- }
-
- else if (strcmp(name, "intf_nv_audio_rate") == 0) {
- val = strtol(value, &pEnd, 10);
- // TODO: Should check for specific values
- if (val >= AVB_AUDIO_RATE_8KHZ && val <= AVB_AUDIO_RATE_192KHZ) {
- pPvtData->audioRate = (avb_audio_rate_t)val;
- }
- else {
- AVB_LOG_ERROR("Invalid audio rate configured for intf_nv_audio_rate.");
- pPvtData->audioRate = AVB_AUDIO_RATE_44_1KHZ;
- }
-
- // Give the audio parameters to the mapping module.
- if (xSupportedMappingFormat(pMediaQ)) {
- pPubMapUncmpAudioInfo->audioRate = pPvtData->audioRate;
- }
- }
-
- else if (strcmp(name, "intf_nv_audio_bit_depth") == 0) {
- val = strtol(value, &pEnd, 10);
- // TODO: Should check for specific values
- if (val >= AVB_AUDIO_BIT_DEPTH_1BIT && val <= AVB_AUDIO_BIT_DEPTH_64BIT) {
- pPvtData->audioBitDepth = (avb_audio_bit_depth_t)val;
- }
- else {
- AVB_LOG_ERROR("Invalid audio type configured for intf_nv_audio_bits.");
- pPvtData->audioBitDepth = AVB_AUDIO_BIT_DEPTH_24BIT;
- }
-
- // Give the audio parameters to the mapping module.
- if (xSupportedMappingFormat(pMediaQ)) {
- pPubMapUncmpAudioInfo->audioBitDepth = pPvtData->audioBitDepth;
- }
- }
-
- else if (strcmp(name, "intf_nv_audio_type") == 0) {
- if (strncasecmp(value, "float", 5) == 0)
- pPvtData->audioType = (avb_audio_bit_depth_t)AVB_AUDIO_TYPE_FLOAT;
- else if (strncasecmp(value, "sign", 4) == 0 || strncasecmp(value, "int", 4) == 0)
- pPvtData->audioType = (avb_audio_bit_depth_t)AVB_AUDIO_TYPE_INT;
- else if (strncasecmp(value, "unsign", 6) == 0 || strncasecmp(value, "uint", 4) == 0)
- pPvtData->audioType = (avb_audio_bit_depth_t)AVB_AUDIO_TYPE_UINT;
- else {
- AVB_LOG_ERROR("Invalid audio type configured for intf_nv_audio_type.");
- pPvtData->audioType = (avb_audio_bit_depth_t)AVB_AUDIO_TYPE_UNSPEC;
- }
-
- // Give the audio parameters to the mapping module.
- if (xSupportedMappingFormat(pMediaQ)) {
- pPubMapUncmpAudioInfo->audioType = (avb_audio_type_t)pPvtData->audioType;
- }
- }
-
- else if (strcmp(name, "intf_nv_audio_endian") == 0) {
- if (strncasecmp(value, "big", 3) == 0)
- pPvtData->audioType = (avb_audio_bit_depth_t)AVB_AUDIO_ENDIAN_BIG;
- else if (strncasecmp(value, "little", 6) == 0)
- pPvtData->audioType = (avb_audio_bit_depth_t)AVB_AUDIO_ENDIAN_LITTLE;
- else {
- AVB_LOG_ERROR("Invalid audio type configured for intf_nv_audio_endian.");
- pPvtData->audioType = (avb_audio_bit_depth_t)AVB_AUDIO_ENDIAN_UNSPEC;
- }
-
- // Give the audio parameters to the mapping module.
- if (xSupportedMappingFormat(pMediaQ)) {
- pPubMapUncmpAudioInfo->audioEndian = (avb_audio_endian_t)pPvtData->audioEndian;
- }
- }
-
- else if (strcmp(name, "intf_nv_audio_channels") == 0) {
- val = strtol(value, &pEnd, 10);
- // TODO: Should check for specific values
- if (val >= AVB_AUDIO_CHANNELS_1 && val <= AVB_AUDIO_CHANNELS_8) {
- pPvtData->audioChannels = (avb_audio_channels_t)val;
- }
- else {
- AVB_LOG_ERROR("Invalid audio channels configured for intf_nv_audio_channels.");
- pPvtData->audioChannels = (avb_audio_channels_t)AVB_AUDIO_CHANNELS_2;
- }
-
- // Give the audio parameters to the mapping module.
- if (xSupportedMappingFormat(pMediaQ)) {
- pPubMapUncmpAudioInfo->audioChannels = pPvtData->audioChannels;
- }
- }
-
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_INTF);
-}
-
-void openavbIntfToneGenGenInitCB(media_q_t *pMediaQ)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_INTF);
- AVB_TRACE_EXIT(AVB_TRACE_INTF);
-}
-
-// A call to this callback indicates that this interface module will be
-// a talker. Any talker initialization can be done in this function.
-void openavbIntfToneGenTxInitCB(media_q_t *pMediaQ)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_INTF);
-
- if (pMediaQ) {
-
- // U8 b;
- pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
- if (!pPvtData) {
- AVB_LOG_ERROR("Private interface module data not allocated.");
- return;
- }
-
- media_q_pub_map_uncmp_audio_info_t *pPubMapUncmpAudioInfo;
- pPubMapUncmpAudioInfo = (media_q_pub_map_uncmp_audio_info_t *)pMediaQ->pPubMapInfo;
- if (!pPubMapUncmpAudioInfo) {
- AVB_LOG_ERROR("Public map data for audio info not allocated.");
- return;
- }
-
- // Will get toggle on at the first tx cb
- if (pPvtData->onOffIntervalMSec > 0) {
- pPvtData->freq = pPvtData->toneHz;
- pPvtData->freqCountdown = 0;
- }
- else {
- pPvtData->freq = 0;
- pPvtData->freqCountdown = 0;
- }
-
- pPvtData->melodyIdx = 0;
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_INTF);
-}
-
-// This callback will be called for each AVB transmit interval. Commonly this will be
-// 4000 or 8000 times per second.
-bool openavbIntfToneGenTxCB(media_q_t *pMediaQ)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
-
- if (pMediaQ) {
- media_q_pub_map_uncmp_audio_info_t *pPubMapUncmpAudioInfo = pMediaQ->pPubMapInfo;
- pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
- if (!pPvtData) {
- AVB_LOG_ERROR("Private interface module data not allocated.");
- return FALSE;
- }
-
- if (pPvtData->intervalCounter++ % pPubMapUncmpAudioInfo->packingFactor != 0)
- return TRUE;
-
- media_q_item_t *pMediaQItem = openavbMediaQHeadLock(pMediaQ);
- if (pMediaQItem) {
- if (pMediaQItem->itemSize < pPubMapUncmpAudioInfo->itemSize) {
- AVB_LOG_ERROR("Media queue item not large enough for samples");
- }
-
- // Tone on
- static U32 runningFrameCnt = 0;
- U32 frameCnt;
- U32 channelCnt;
- U32 idx = 0;
- for (frameCnt = 0; frameCnt < pPubMapUncmpAudioInfo->framesPerItem; frameCnt++) {
-
- // Check for tone on / off toggle
- if (!pPvtData->freqCountdown) {
- if (pPvtData->pMelodyString) {
- // Melody logic
- U32 intervalMSec;
- xGetMelodyToneAndDuration(
- pPvtData->pMelodyString[pPvtData->melodyIdx],
- pPvtData->pMelodyString[pPvtData->melodyIdx + 1],
- &pPvtData->freq, &intervalMSec);
- pPvtData->melodyIdx += 2;
-
- pPvtData->freqCountdown = (pPubMapUncmpAudioInfo->audioRate / 1000) * intervalMSec;
- if (pPvtData->melodyIdx >= pPvtData->melodyLen)
- pPvtData->melodyIdx = 0;
- }
- else {
- // Fixed tone
- if (pPvtData->onOffIntervalMSec > 0) {
- if (pPvtData->freq == 0)
- pPvtData->freq = pPvtData->toneHz;
- else
- pPvtData->freq = 0;
- pPvtData->freqCountdown = (pPubMapUncmpAudioInfo->audioRate / 1000) * pPvtData->onOffIntervalMSec;
- }
- else {
- pPvtData->freqCountdown = pPubMapUncmpAudioInfo->audioRate; // Just run steady for 1 sec
- }
- }
- pPvtData->ratio = pPvtData->freq / (float)pPubMapUncmpAudioInfo->audioRate;
- }
- pPvtData->freqCountdown--;
-
-
- float value = SIN(2 * PI * (runningFrameCnt++ % pPubMapUncmpAudioInfo->audioRate) * pPvtData->ratio);
-
- if (pPubMapUncmpAudioInfo->itemSampleSizeBytes == 2) {
- // 16 bit audio
- S16 sample = (S16)(value * 15000);
- for (channelCnt = 0; channelCnt < pPubMapUncmpAudioInfo->audioChannels; channelCnt++) {
- unsigned char c;
- U8 *pData = pMediaQItem->pPubData;
- c = (unsigned)sample % 256;
- pData[idx++] = c;
- c = (unsigned)sample / 256 % 256;
- pData[idx++] = c;
- }
- }
- else {
- // CORE_TODO
- AVB_LOG_ERROR("Audio sample size format not implemented yet for tone generator interface module");
- }
- }
-
- pMediaQItem->dataLen = pPubMapUncmpAudioInfo->itemSize;
-
- openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
- openavbMediaQHeadPush(pMediaQ);
-
- AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
- return TRUE;
- }
- else {
- AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
- return FALSE; // Media queue full
- }
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
- return FALSE;
-}
-
-// A call to this callback indicates that this interface module will be
-// a listener. Any listener initialization can be done in this function.
-void openavbIntfToneGenRxInitCB(media_q_t *pMediaQ)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_INTF);
- AVB_TRACE_EXIT(AVB_TRACE_INTF);
-}
-
-// This callback is called when acting as a listener.
-bool openavbIntfToneGenRxCB(media_q_t *pMediaQ)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
- AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
- return FALSE;
-}
-
-// This callback will be called when the interface needs to be closed. All shutdown should
-// occur in this function.
-void openavbIntfToneGenEndCB(media_q_t *pMediaQ)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_INTF);
- AVB_TRACE_EXIT(AVB_TRACE_INTF);
-}
-
-void openavbIntfToneGenGenEndCB(media_q_t *pMediaQ)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_INTF);
- AVB_TRACE_EXIT(AVB_TRACE_INTF);
-}
-
-// Main initialization entry point into the interface module
-extern DLL_EXPORT bool openavbIntfToneGenInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_INTF);
-
- if (pMediaQ) {
- pMediaQ->pPvtIntfInfo = calloc(1, sizeof(pvt_data_t)); // Memory freed by the media queue when the media queue is destroyed.
-
- if (!pMediaQ->pPvtIntfInfo) {
- AVB_LOG_ERROR("Unable to allocate memory for AVTP interface module.");
- return FALSE;
- }
-
- pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
-
- pIntfCB->intf_cfg_cb = openavbIntfToneGenCfgCB;
- pIntfCB->intf_gen_init_cb = openavbIntfToneGenGenInitCB;
- pIntfCB->intf_tx_init_cb = openavbIntfToneGenTxInitCB;
- pIntfCB->intf_tx_cb = openavbIntfToneGenTxCB;
- pIntfCB->intf_rx_init_cb = openavbIntfToneGenRxInitCB;
- pIntfCB->intf_rx_cb = openavbIntfToneGenRxCB;
- pIntfCB->intf_end_cb = openavbIntfToneGenEndCB;
- pIntfCB->intf_gen_end_cb = openavbIntfToneGenGenEndCB;
-
- pPvtData->intervalCounter = 0;
- pPvtData->melodyIdx = 0;
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_INTF);
- return TRUE;
-}
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+* MODULE SUMMARY : Tone generator interface module. Talker only.
+*
+* - This interface module generates and audio tone for use with -6 and AAF mappings
+* - Requires an OSAL sin implementation of reasonable performance.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <endian.h>
+#include "openavb_platform_pub.h"
+#include "openavb_osal_pub.h"
+#include "openavb_types_pub.h"
+#include "openavb_trace_pub.h"
+#include "openavb_mediaq_pub.h"
+#include "openavb_map_uncmp_audio_pub.h"
+#include "openavb_map_aaf_audio_pub.h"
+#include "openavb_intf_pub.h"
+#include "openavb_mcs.h"
+
+#define AVB_LOG_COMPONENT "Tone Gen Interface"
+#include "openavb_log_pub.h"
+
+#define PI 3.14159265358979f
+
+typedef struct {
+ /////////////
+ // Config data
+ /////////////
+ // intf_nv_tone_hz: The tone hz to generate
+ U32 toneHz;
+
+ // intf_nv_on_off_interval_msec: Interval for turning tone on and off. A value of zero will keep the tone on.
+ U32 onOffIntervalMSec;
+
+ // Simple melody
+ char *pMelodyString;
+
+ // intf_nv_audio_rate
+ avb_audio_rate_t audioRate;
+
+ // intf_nv_audio_type
+ avb_audio_type_t audioType;
+
+ // intf_nv_audio_bit_depth
+ avb_audio_bit_depth_t audioBitDepth;
+
+ // intf_nv_audio_endian
+ avb_audio_endian_t audioEndian;
+
+ // intf_nv_channels
+ avb_audio_channels_t audioChannels;
+
+ // Volume for the tone generation
+ float volume;
+
+ // Fixed 32 bit value 1
+ bool fv1Enabled;
+ U32 fv1;
+
+ // Fixed 32 bit value 2
+ bool fv2Enabled;
+ U32 fv2;
+
+ /////////////
+ // Variable data
+ /////////////
+
+ // Packing interval
+ U32 intervalCounter;
+
+ // Keeps track of if the tone is currently on or off
+ U32 freq;
+
+ // Keeps track of how long before toggling the tone on / off
+ U32 freqCountdown;
+
+ // Ratio precalc
+ float ratio;
+
+ // Index to into the melody string
+ U32 melodyIdx;
+
+ // Length of the melody string
+ U32 melodyLen;
+
+ U32 fvChannels;
+
+ // Media clock synthesis for precise timestamps
+ mcs_t mcs;
+
+ bool fixedTimestampEnabled;
+
+} pvt_data_t;
+
+#define MSEC_PER_COUNT 250
+static void xGetMelodyToneAndDuration(char note, char count, U32 *freq, U32 *sampleMSec)
+{
+ switch (note) {
+ case 'A':
+ *freq = 220;
+ break;
+ case 'B':
+ *freq = 246;
+ break;
+ case 'C':
+ *freq = 261;
+ break;
+ case 'D':
+ *freq = 293;
+ break;
+ case 'E':
+ *freq = 329;
+ break;
+ case 'F':
+ *freq = 349;
+ break;
+ case 'G':
+ *freq = 391;
+ break;
+ case 'a':
+ *freq = 440;
+ break;
+ case 'b':
+ *freq = 493;
+ break;
+ case 'c':
+ *freq = 523;
+ break;
+ case 'd':
+ *freq = 587;
+ break;
+ case 'e':
+ *freq = 659;
+ break;
+ case 'f':
+ *freq = 698;
+ break;
+ case 'g':
+ *freq = 783;
+ break;
+ case '-':
+ default:
+ *freq = 0;
+ break;
+ }
+
+ switch (count) {
+ case '1':
+ *sampleMSec = MSEC_PER_COUNT * 1;
+ break;
+ case '2':
+ *sampleMSec = MSEC_PER_COUNT * 2;
+ break;
+ case '3':
+ *sampleMSec = MSEC_PER_COUNT * 3;
+ break;
+ case '4':
+ *sampleMSec = MSEC_PER_COUNT * 4;
+ break;
+ default:
+ *sampleMSec = MSEC_PER_COUNT * 4;
+ break;
+ }
+}
+
+static bool xSupportedMappingFormat(media_q_t *pMediaQ)
+{
+ if (pMediaQ) {
+ if (pMediaQ->pMediaQDataFormat) {
+ if (strcmp(pMediaQ->pMediaQDataFormat, MapUncmpAudioMediaQDataFormat) == 0 || strcmp(pMediaQ->pMediaQDataFormat, MapAVTPAudioMediaQDataFormat) == 0) {
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+// Each configuration name value pair for this mapping will result in this callback being called.
+void openavbIntfToneGenCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ char *pEnd;
+ U32 val;
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ media_q_pub_map_uncmp_audio_info_t *pPubMapUncmpAudioInfo;
+ pPubMapUncmpAudioInfo = (media_q_pub_map_uncmp_audio_info_t *)pMediaQ->pPubMapInfo;
+ if (!pPubMapUncmpAudioInfo) {
+ AVB_LOG_ERROR("Public map data for audio info not allocated.");
+ return;
+ }
+
+ if (strcmp(name, "intf_nv_tone_hz") == 0) {
+ pPvtData->toneHz = strtol(value, &pEnd, 10);
+ }
+
+ else if (strcmp(name, "intf_nv_on_off_interval_msec") == 0) {
+ pPvtData->onOffIntervalMSec = strtol(value, &pEnd, 10);
+ }
+
+ else if (strcmp(name, "intf_nv_melody_string") == 0) {
+ if (pPvtData->pMelodyString)
+ free(pPvtData->pMelodyString);
+ pPvtData->pMelodyString = strdup(value);
+ if (pPvtData->pMelodyString) {
+ pPvtData->melodyLen = strlen(pPvtData->pMelodyString);
+ }
+ }
+
+ else if (strcmp(name, "intf_nv_audio_rate") == 0) {
+ val = strtol(value, &pEnd, 10);
+ // TODO: Should check for specific values
+ if (val >= AVB_AUDIO_RATE_8KHZ && val <= AVB_AUDIO_RATE_192KHZ) {
+ pPvtData->audioRate = (avb_audio_rate_t)val;
+ }
+ else {
+ AVB_LOG_ERROR("Invalid audio rate configured for intf_nv_audio_rate.");
+ pPvtData->audioRate = AVB_AUDIO_RATE_44_1KHZ;
+ }
+
+ // Give the audio parameters to the mapping module.
+ if (xSupportedMappingFormat(pMediaQ)) {
+ pPubMapUncmpAudioInfo->audioRate = pPvtData->audioRate;
+ }
+ }
+
+ else if (strcmp(name, "intf_nv_audio_bit_depth") == 0) {
+ val = strtol(value, &pEnd, 10);
+ // TODO: Should check for specific values
+ if (val >= AVB_AUDIO_BIT_DEPTH_1BIT && val <= AVB_AUDIO_BIT_DEPTH_64BIT) {
+ pPvtData->audioBitDepth = (avb_audio_bit_depth_t)val;
+ }
+ else {
+ AVB_LOG_ERROR("Invalid audio type configured for intf_nv_audio_bits.");
+ pPvtData->audioBitDepth = AVB_AUDIO_BIT_DEPTH_24BIT;
+ }
+
+ // Give the audio parameters to the mapping module.
+ if (xSupportedMappingFormat(pMediaQ)) {
+ pPubMapUncmpAudioInfo->audioBitDepth = pPvtData->audioBitDepth;
+ }
+ }
+
+ else if (strcmp(name, "intf_nv_audio_type") == 0) {
+ if (strncasecmp(value, "float", 5) == 0)
+ pPvtData->audioType = AVB_AUDIO_TYPE_FLOAT;
+ else if (strncasecmp(value, "sign", 4) == 0 || strncasecmp(value, "int", 4) == 0)
+ pPvtData->audioType = AVB_AUDIO_TYPE_INT;
+ else if (strncasecmp(value, "unsign", 6) == 0 || strncasecmp(value, "uint", 4) == 0)
+ pPvtData->audioType = AVB_AUDIO_TYPE_UINT;
+ else {
+ AVB_LOG_ERROR("Invalid audio type configured for intf_nv_audio_type.");
+ pPvtData->audioType = AVB_AUDIO_TYPE_UNSPEC;
+ }
+
+ // Give the audio parameters to the mapping module.
+ if (xSupportedMappingFormat(pMediaQ)) {
+ pPubMapUncmpAudioInfo->audioType = pPvtData->audioType;
+ }
+ }
+
+ else if (strcmp(name, "intf_nv_audio_endian") == 0) {
+ if (strncasecmp(value, "big", 3) == 0)
+ pPvtData->audioEndian = AVB_AUDIO_ENDIAN_BIG;
+ else if (strncasecmp(value, "little", 6) == 0)
+ pPvtData->audioEndian = AVB_AUDIO_ENDIAN_LITTLE;
+ else {
+ AVB_LOG_ERROR("Invalid audio type configured for intf_nv_audio_endian.");
+ pPvtData->audioEndian = AVB_AUDIO_ENDIAN_UNSPEC;
+ }
+
+ // Give the audio parameters to the mapping module.
+ if (xSupportedMappingFormat(pMediaQ)) {
+ pPubMapUncmpAudioInfo->audioEndian = pPvtData->audioEndian;
+ }
+ }
+
+ else if (strcmp(name, "intf_nv_audio_channels") == 0) {
+ val = strtol(value, &pEnd, 10);
+ // TODO: Should check for specific values
+ if (val >= AVB_AUDIO_CHANNELS_1) {
+ pPvtData->audioChannels = (avb_audio_channels_t)val;
+ }
+ else {
+ AVB_LOG_ERROR("Invalid audio channels configured for intf_nv_audio_channels.");
+ pPvtData->audioChannels = (avb_audio_channels_t)AVB_AUDIO_CHANNELS_2;
+ }
+
+ // Give the audio parameters to the mapping module.
+ if (xSupportedMappingFormat(pMediaQ)) {
+ pPubMapUncmpAudioInfo->audioChannels = pPvtData->audioChannels;
+ }
+ }
+
+ else if (strcmp(name, "intf_nv_volume") == 0) {
+ S32 vol = strtol(value, &pEnd, 10);
+ pPvtData->volume = pow(10.0, vol/10.0);
+ }
+
+ else if (strcmp(name, "intf_nv_fv1") == 0) {
+ pPvtData->fv1 = strtol(value, &pEnd, 10);
+ pPvtData->fv1Enabled = true;
+ pPvtData->fvChannels++;
+ }
+
+ else if (strcmp(name, "intf_nv_fv2") == 0) {
+ pPvtData->fv2 = strtol(value, &pEnd, 10);
+ pPvtData->fv2Enabled = true;
+ pPvtData->fvChannels++;
+ }
+
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+void openavbIntfToneGenGenInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// A call to this callback indicates that this interface module will be
+// a talker. Any talker initialization can be done in this function.
+void openavbIntfToneGenTxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+
+ // U8 b;
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ media_q_pub_map_uncmp_audio_info_t *pPubMapUncmpAudioInfo;
+ pPubMapUncmpAudioInfo = (media_q_pub_map_uncmp_audio_info_t *)pMediaQ->pPubMapInfo;
+ if (!pPubMapUncmpAudioInfo) {
+ AVB_LOG_ERROR("Public map data for audio info not allocated.");
+ return;
+ }
+
+ // Will get toggle on at the first tx cb
+ if (pPvtData->onOffIntervalMSec > 0) {
+ pPvtData->freq = pPvtData->toneHz;
+ pPvtData->freqCountdown = 0;
+ }
+ else {
+ pPvtData->freq = 0;
+ pPvtData->freqCountdown = 0;
+ }
+
+ pPvtData->melodyIdx = 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+
+#define SWAPU16(x) (((x) >> 8) | ((x) << 8))
+static U16 convertToDesiredEndianOrder16(U16 hostData, avb_audio_endian_t audioEndian)
+{
+#if defined __BYTE_ORDER && defined __BIG_ENDIAN && defined __LITTLE_ENDIAN
+#if __BYTE_ORDER == __BIG_ENDIAN
+ if (audioEndian == AVB_AUDIO_ENDIAN_LITTLE) { hostData = SWAPU16(hostData); }
+ return hostData;
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+ if (audioEndian == AVB_AUDIO_ENDIAN_BIG) { hostData = SWAPU16(hostData); }
+ return hostData;
+#else
+ #error Unsupported Endian format
+#endif
+#else
+ U16 test_var = 1;
+ unsigned char test_endian* = (unsigned char*)&test_var;
+ if (test_endian[0] == 0) {
+ // This is big-endian.
+ if (audioEndian == AVB_AUDIO_ENDIAN_LITTLE) { hostData = SWAPU16(hostData); }
+ } else {
+ // This is little-endian.
+ if (audioEndian == AVB_AUDIO_ENDIAN_BIG) { hostData = SWAPU16(hostData); }
+ }
+ return hostData;
+#endif
+}
+
+#define SWAPU32(x) (((x) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | ((x) << 24))
+static U32 convertToDesiredEndianOrder32(U32 hostData, avb_audio_endian_t audioEndian)
+{
+#if defined __BYTE_ORDER && defined __BIG_ENDIAN && defined __LITTLE_ENDIAN
+#if __BYTE_ORDER == __BIG_ENDIAN
+ if (audioEndian == AVB_AUDIO_ENDIAN_LITTLE) { hostData = SWAPU32(hostData); }
+ return hostData;
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+ if (audioEndian == AVB_AUDIO_ENDIAN_BIG) { hostData = SWAPU32(hostData); }
+ return hostData;
+#else
+ #error Unsupported Endian format
+#endif
+#else
+ U16 test_var = 1;
+ unsigned char test_endian* = (unsigned char*)&test_var;
+ if (test_endian[0] == 0) {
+ // This is big-endian.
+ if (audioEndian == AVB_AUDIO_ENDIAN_LITTLE) { hostData = SWAPU32(hostData); }
+ } else {
+ // This is little-endian.
+ if (audioEndian == AVB_AUDIO_ENDIAN_BIG) { hostData = SWAPU32(hostData); }
+ }
+ return hostData;
+#endif
+}
+
+// This callback will be called for each AVB transmit interval. Commonly this will be
+// 4000 or 8000 times per second.
+bool openavbIntfToneGenTxCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+
+ if (pMediaQ) {
+ media_q_pub_map_uncmp_audio_info_t *pPubMapUncmpAudioInfo = pMediaQ->pPubMapInfo;
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return FALSE;
+ }
+
+ if (pPvtData->intervalCounter++ % pPubMapUncmpAudioInfo->packingFactor != 0)
+ return TRUE;
+
+ media_q_item_t *pMediaQItem = openavbMediaQHeadLock(pMediaQ);
+ if (pMediaQItem) {
+ if (pMediaQItem->itemSize < pPubMapUncmpAudioInfo->itemSize) {
+ AVB_LOG_ERROR("Media queue item not large enough for samples");
+ }
+
+ // Tone on
+ static U32 runningFrameCnt = 0;
+ U32 frameCnt;
+ U32 channelCnt;
+ U8 *pData = pMediaQItem->pPubData;
+
+ for (frameCnt = 0; frameCnt < pPubMapUncmpAudioInfo->framesPerItem; frameCnt++) {
+
+ // Check for tone on / off toggle
+ if (!pPvtData->freqCountdown) {
+ if (pPvtData->pMelodyString) {
+ // Melody logic
+ U32 intervalMSec;
+ xGetMelodyToneAndDuration(
+ pPvtData->pMelodyString[pPvtData->melodyIdx],
+ pPvtData->pMelodyString[pPvtData->melodyIdx + 1],
+ &pPvtData->freq, &intervalMSec);
+ pPvtData->melodyIdx += 2;
+
+ pPvtData->freqCountdown = (pPubMapUncmpAudioInfo->audioRate / 1000) * intervalMSec;
+ if (pPvtData->melodyIdx >= pPvtData->melodyLen)
+ pPvtData->melodyIdx = 0;
+ }
+ else {
+ // Fixed tone
+ if (pPvtData->onOffIntervalMSec > 0) {
+ if (pPvtData->freq == 0) {
+ pPvtData->freq = pPvtData->toneHz;
+ } else {
+ pPvtData->freq = 0;
+ }
+ pPvtData->freqCountdown = (pPubMapUncmpAudioInfo->audioRate / 1000) * pPvtData->onOffIntervalMSec;
+ }
+ else {
+ pPvtData->freqCountdown = pPubMapUncmpAudioInfo->audioRate; // Just run steady for 1 sec
+ pPvtData->freq = pPvtData->toneHz;
+ }
+ }
+ pPvtData->ratio = (float)pPvtData->freq / (float)pPubMapUncmpAudioInfo->audioRate;
+ }
+ pPvtData->freqCountdown--;
+
+ float value = SIN(2 * PI * (runningFrameCnt++ % pPubMapUncmpAudioInfo->audioRate) * pPvtData->ratio) * pPvtData->volume;
+
+ for (channelCnt = 0; channelCnt < pPubMapUncmpAudioInfo->audioChannels - pPvtData->fvChannels; channelCnt++) {
+ if (pPvtData->audioType == AVB_AUDIO_TYPE_INT) {
+ if (pPvtData->audioBitDepth == 32) {
+ S32 sample32 = (S32)(value * (32000 << 16));
+ S32 tmp32 = convertToDesiredEndianOrder32(sample32, pPvtData->audioEndian);
+ memcpy(pData, (U8 *)&tmp32, 4);
+ pData += 4;
+ } else if (pPvtData->audioBitDepth == 24) {
+ S32 sample24 = (S32)(value * (32000 << 16));
+ S32 tmp24 = convertToDesiredEndianOrder32(sample24, pPvtData->audioEndian);
+ if (pPvtData->audioEndian == AVB_AUDIO_ENDIAN_BIG) {
+ memcpy(pData, (U8 *)&tmp24, 3);
+ } else {
+ memcpy(pData, ((U8 *)&tmp24) + 1, 3);
+ }
+ pData += 3;
+ } else if (pPvtData->audioBitDepth == 16) {
+ S16 sample16 = (S32)(value * 32000);
+ S16 tmp16 = convertToDesiredEndianOrder16(sample16, pPvtData->audioEndian);
+ memcpy(pData, (U8 *)&tmp16, 2);
+ pData += 2;
+ }
+ } else if (pPvtData->audioType == AVB_AUDIO_TYPE_FLOAT) {
+ U32 tmp32f;
+ // value *= .75; // attenuate value
+ memcpy((U8 *)&tmp32f, (U8 *)&value, 4); // done so no warning with -Wstrict-aliasing
+ tmp32f = convertToDesiredEndianOrder32(tmp32f, pPvtData->audioEndian);
+ memcpy(pData, (U8 *)&tmp32f, 4);
+ pData += 4;
+ } else {
+ // CORE_TODO
+ AVB_LOG_ERROR("Audio sample size format not implemented yet for tone generator interface module");
+ }
+ }
+
+ if (pPvtData->fvChannels > 0) {
+ if (pPvtData->audioType == AVB_AUDIO_TYPE_INT) {
+ if (pPvtData->audioBitDepth == 32) {
+ if (pPvtData->fv1Enabled) {
+ S32 tmp32 = convertToDesiredEndianOrder32(pPvtData->fv1, pPvtData->audioEndian);
+ memcpy(pData, (U8 *)&tmp32, 4);
+ pData += 4;
+ }
+
+ if (pPvtData->fv2Enabled) {
+ S32 tmp32 = convertToDesiredEndianOrder32(pPvtData->fv2, pPvtData->audioEndian);
+ memcpy(pData, (U8 *)&tmp32, 4);
+ pData += 4;
+ }
+ }
+ }
+ }
+ }
+
+ pMediaQItem->dataLen = pPubMapUncmpAudioInfo->itemSize;
+
+ if (!pPvtData->fixedTimestampEnabled) {
+ openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
+ } else {
+ openavbMcsAdvance(&pPvtData->mcs);
+ openavbAvtpTimeSetToTimestampNS(pMediaQItem->pAvtpTime, pPvtData->mcs.edgeTime);
+ }
+
+ openavbMediaQHeadPush(pMediaQ);
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return TRUE;
+ }
+ else {
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE; // Media queue full
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE;
+}
+
+// A call to this callback indicates that this interface module will be
+// a listener. Any listener initialization can be done in this function.
+void openavbIntfToneGenRxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// This callback is called when acting as a listener.
+bool openavbIntfToneGenRxCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE;
+}
+
+// This callback will be called when the interface needs to be closed. All shutdown should
+// occur in this function.
+void openavbIntfToneGenEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+void openavbIntfToneGenGenEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+void openavbIntfToneGenEnableFixedTimestamp(media_q_t *pMediaQ, bool enabled, U32 transmitInterval, U32 batchFactor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ if (pMediaQ && pMediaQ->pPvtIntfInfo && pMediaQ->pPubMapInfo) {
+ media_q_pub_map_uncmp_audio_info_t *pPubMapUncmpAudioInfo = pMediaQ->pPubMapInfo;
+ pvt_data_t *pPvtData = (pvt_data_t *)pMediaQ->pPvtIntfInfo;
+
+ pPvtData->fixedTimestampEnabled = enabled;
+ if (pPvtData->fixedTimestampEnabled) {
+ U32 per, rate, rem;
+ /* Ignore passed in transmit interval and use framesPerItem and audioRate so
+ we work with both AAF and 61883-6 */
+ /* Carefully scale values to avoid U32 overflow or loss of precision */
+ per = MICROSECONDS_PER_SECOND * pPubMapUncmpAudioInfo->framesPerItem * 10;
+ rate = pPvtData->audioRate/100;
+ transmitInterval = per/rate;
+ rem = per % rate;
+ if (rem != 0) {
+ rem *= 10;
+ rem /= rate;
+ }
+ openavbMcsInit(&pPvtData->mcs, transmitInterval, rem, 10);
+ AVB_LOGF_INFO("Fixed timestamping enabled: %d %d/%d", transmitInterval, rem, 10);
+ }
+
+ if (batchFactor != 1) {
+ AVB_LOGF_WARNING("batchFactor of %d ignored (must be 1)", batchFactor);
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// Main initialization entry point into the interface module
+//extern DLL_EXPORT bool openavbIntfToneGenInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB)
+extern bool DLL_EXPORT openavbIntfToneGenInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ pMediaQ->pPvtIntfInfo = calloc(1, sizeof(pvt_data_t)); // Memory freed by the media queue when the media queue is destroyed.
+
+ if (!pMediaQ->pPvtIntfInfo) {
+ AVB_LOG_ERROR("Unable to allocate memory for AVTP interface module.");
+ return FALSE;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+
+ pIntfCB->intf_cfg_cb = openavbIntfToneGenCfgCB;
+ pIntfCB->intf_gen_init_cb = openavbIntfToneGenGenInitCB;
+ pIntfCB->intf_tx_init_cb = openavbIntfToneGenTxInitCB;
+ pIntfCB->intf_tx_cb = openavbIntfToneGenTxCB;
+ pIntfCB->intf_rx_init_cb = openavbIntfToneGenRxInitCB;
+ pIntfCB->intf_rx_cb = openavbIntfToneGenRxCB;
+ pIntfCB->intf_end_cb = openavbIntfToneGenEndCB;
+ pIntfCB->intf_gen_end_cb = openavbIntfToneGenGenEndCB;
+ pIntfCB->intf_enable_fixed_timestamp = openavbIntfToneGenEnableFixedTimestamp;
+
+ pPvtData->intervalCounter = 0;
+ pPvtData->melodyIdx = 0;
+ pPvtData->audioType = AVB_AUDIO_TYPE_INT;
+ pPvtData->audioEndian = AVB_AUDIO_ENDIAN_BIG;
+
+ pPvtData->volume = 1.0f;
+ pPvtData->fv1Enabled = false;
+ pPvtData->fv1 = 0;
+ pPvtData->fv2Enabled = false;
+ pPvtData->fv2 = 0;
+ pPvtData->fvChannels = 0;
+
+ pPvtData->fixedTimestampEnabled = false;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/intf_tonegen/openavb_intf_tonegen.md b/lib/avtp_pipeline/intf_tonegen/openavb_intf_tonegen.md
index 6afd810a..ce0d3b12 100644
--- a/lib/avtp_pipeline/intf_tonegen/openavb_intf_tonegen.md
+++ b/lib/avtp_pipeline/intf_tonegen/openavb_intf_tonegen.md
@@ -14,17 +14,11 @@ Name | Description
-----------------------------|---------------------------
intf_nv_tone_hz | The frequency of the generated tone
intf_nv_on_off_interval_msec | How many millisecs to turn on and off the tone
-intf_nv_melody_string | A simple melody to play. When a melody string is \
- set the on/off tone hz is not used. The string \
- holds the notes in a 2 octave range with the use \
- of letters A B C D E F G a b c d e f g followed \
- by a duration of the note. For example the full \
- scale is A4B4C4D4E4F4G4a4b4c4d4e4f4g4.
-intf_nv_audio_rate | Audio rate, numberic values defined by \
- @ref avb_audio_rate_t
-intf_nv_audio_bit_depth | Bit depth of audio, numeric values defined by \
- @ref avb_audio_bit_depth_t
-intf_nv_audio_channels | Number of audio channels, numeric values should \
- be within range of values in \
- @ref avb_audio_channels_t
-
+intf_nv_melody_string | A simple melody to play. When a melody string is set the on/off tone hz is not used. The string holds the notes in a 2 octave range with the use of letters A B C D E F G a b c d e f g followed by a duration of the note. For example the full scale is A4B4C4D4E4F4G4a4b4c4d4e4f4g4.
+intf_nv_audio_rate | Audio rate, numberic values defined by @ref avb_audio_rate_t
+intf_nv_audio_bit_depth | Bit depth of audio, numeric values defined by @ref avb_audio_bit_depth_t
+intf_nv_audio_channels | Number of audio channels, numeric values should be within range of values in @ref avb_audio_channels_t
+intf_nv_audio_endian | Data endianess possible values <ul><li>big</li><li>little</li></ul>
+intf_nv_audio_channels | Number of audio channels, numeric values should be within range of values in @ref avb_audio_channels_t
+intf_nv_volume | The volune of the tone generation PCM in dB
+intf_nv_fv1 and intf_nv_fv2 | Optionally replace the last channel, or last two channels if both are defined, with fixed 32-bit sample values
diff --git a/lib/avtp_pipeline/intf_tonegen/tonegen_talker.ini b/lib/avtp_pipeline/intf_tonegen/tonegen_talker.ini
index 24a207c9..ece6eec2 100644
--- a/lib/avtp_pipeline/intf_tonegen/tonegen_talker.ini
+++ b/lib/avtp_pipeline/intf_tonegen/tonegen_talker.ini
@@ -5,6 +5,12 @@
# talker or listener
role = talker
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
#stream_addr = 00:25:64:48:ca:a8
@@ -118,7 +124,7 @@ map_nv_packing_factor = 1
intf_lib = ./libopenavb_intf_tonegen.so
# intf_fn: The name of the initialize function in the interface.
-intf_fn = openavbIntfTonegenInitialize
+intf_fn = openavbIntfToneGenInitialize
# intf_nv_tone_hz: The frequence of the tone
intf_nv_tone_hz = 261
@@ -143,7 +149,15 @@ intf_nv_audio_bit_depth = 16
# intf_nv_audio_channels: The number of channels of the generated audio
intf_nv_audio_channels = 2
+# intf_nv_volume: The volune of the tone generation PCM in dB
+intf_nv_volume = 0
+
+# Optionally replace the last one or two channels with fixed sample values
+# intf_nv_fv1: First fixed 32-bit value
+#intf_nv_fv1 = 1234
+# intf_nv_fv2: Second fixed 32-bit value
+#intf_nv_fv2 = 5678
diff --git a/lib/avtp_pipeline/intf_tonegen/tonegen_talker_lowlatency.ini b/lib/avtp_pipeline/intf_tonegen/tonegen_talker_lowlatency.ini
new file mode 100644
index 00000000..1696c363
--- /dev/null
+++ b/lib/avtp_pipeline/intf_tonegen/tonegen_talker_lowlatency.ini
@@ -0,0 +1,174 @@
+#####################################################################
+# General Talker configuration
+#####################################################################
+# role: Sets the process as a talker or listener. Valid values are
+# talker or listener
+role = talker
+
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
+# stream_addr: Used on the listener and should be set to the
+# mac address of the talker.
+#stream_addr = 00:25:64:48:ca:a8
+
+# stream_uid: The unique stream ID. The talker and listener must
+# both have this set the same.
+stream_uid = 1
+
+# dest_addr: destination multicast address for the stream.
+#
+# If using SRP and MAAP, dynamic destination addresses are generated
+# automatically by the talker and passed to the listner, and don't
+# need to be configured.
+#
+# Without MAAP, locally administered (static) addresses must be
+# configured. Thouse addresses are in the range of:
+# 91:E0:F0:00:FE:00 - 91:E0:F0:00:FE:FF.
+# Typically use :00 for the first stream, :01 for the second, etc.
+#
+# When SRP is being used the static destination address only needs to
+# be set in the talker. If SRP is not being used the destination address
+# needs to be set (to the same value) in both the talker and listener.
+#
+# The destination is a multicast address, not a real MAC address, so it
+# does not match the talker or listener's interface MAC. There are
+# several pools of those addresses for use by AVTP defined in 1722.
+#
+#dest_addr = 91:e0:f0:00:fe:00
+
+# max_interval_frames: The maximum number of packets that will be sent during
+# an observation interval. This is only used on the talker.
+max_interval_frames = 1
+
+# sr_class: A talker only setting. Values are either A or B. If not set an internal
+# default is used.
+sr_class = A
+
+# sr_rank: A talker only setting. If not set an internal default is used.
+#sr_rank = 1
+
+# max_transit_usec: Allows manually specifying a maximum transit time.
+# On the talker this value is added to the PTP walltime to create the AVTP Timestamp.
+# On the listener this value is used to validate an expected valid timestamp range.
+# Note: For the listener the map_nv_item_count value must be set large enough to
+# allow buffering at least as many AVTP packets that can be transmitted during this
+# max transit time.
+max_transit_usec = 2000
+
+# internal_latency: Allows mannually specifying an internal latency time. This is used
+# only on the talker.
+#internal_latency = 0
+
+# max_stale: The number of microseconds beyond the presentation time that media queue items will be purged
+# because they are too old (past the presentation time). This is only used on listener end stations.
+# Note: needing to purge old media queue items is often a sign of some other problem. For example: a delay at
+# stream startup before incoming packets are ready to be processed by the media sink. If this deficit
+# in processing or purging the old (stale) packets is not handled, syncing multiple listeners will be problematic.
+#max_stale = 1000
+
+# raw_tx_buffers: The number of raw socket transmit buffers. Typically 4 - 8 are good values.
+# This is only used by the talker. If not set internal defaults are used.
+#raw_tx_buffers = 1
+
+# raw_rx_buffers: The number of raw socket receive buffers. Typically 50 - 100 are good values.
+# This is only used by the listener. If not set internal defaults are used.
+#raw_rx_buffers = 100
+
+# report_seconds: How often to output stats. Defaults to 10 seconds. 0 turns off the stats.
+# report_seconds = 0
+
+# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
+# ifname = eth0
+
+# vlan_id: VLAN Identifier (1-4094). Used in "no endpoint" builds. Defaults to 2.
+# vlan_id = 2
+
+# Enable fixed timestamping in interface. Defaults to disable (0).
+fixed_timestamp = 1
+
+# Bit mask used for CPU pinning. Defaults to all cpus can be used (0xffffffff).
+thread_affinity = 12
+
+# Enable real time scheduling with this priority. Defaults to not use RT sched (0).
+thread_rt_priority = 10
+
+#####################################################################
+# Mapping module configuration
+#####################################################################
+# map_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. Comment out the map_lib name
+# and link in the .c file to the openavb_tl executable to embed the mapper
+# directly into the executable unit. There is no need to change anything
+# else. The Initialize function will still be dynamically linked in.
+map_lib = ./libopenavb_map_aaf_audio.so
+
+# map_fn: The name of the initialize function in the mapper.
+map_fn = openavbMapAVTPAudioInitialize
+
+# map_nv_item_count: The number of media queue elements to hold.
+map_nv_item_count = 20
+
+# map_nv_tx_rate: Transmit rate.
+# This must be set for the uncompressed audio mapping module.
+map_nv_tx_rate = 8000
+
+# map_nv_packing_factor: Multiple of how many packets of audio frames to place in a media queue item.
+# Note: Typically when decreasing the map_nv_tx_rate the packing factor will also be decreased since
+# the number of frames per packet will be increasing.
+map_nv_packing_factor = 1
+
+#####################################################################
+# Interface module configuration
+#####################################################################
+# intf_lib: The name of the library file (commonly a .so file) that
+# implements the Initialize function. Comment out the intf_lib name
+# and link in the .c file to the openavb_tl executable to embed the interface
+# directly into the executable unit. There is no need to change anything
+# else. The Initialize function will still be dynamically linked in.
+# intf_fn: The name of the initialize function in the interface.
+intf_lib = ./libopenavb_intf_tonegen.so
+
+# intf_fn: The name of the initialize function in the interface.
+intf_fn = openavbIntfToneGenInitialize
+
+# intf_nv_tone_hz: The frequence of the tone
+intf_nv_tone_hz = 261
+
+# intf_nv_on_off_interval_msec: How many millisecs to turn on and off the tone
+intf_nv_on_off_interval_msec = 1000
+
+# intf_nv_melody_string: A simple melody to play. When a melody string is set the on/off tone hz is not used.
+# Full range of supported notes
+# intf_nv_melody_string = A4B4C4D4E4F4G4a4b4c4d4e4f4g4
+# DoRaMi...
+# intf_nv_melody_string = A4B4C4D4E4F4G4a4
+# Twinkle Twinkle little star
+# intf_nv_melody_string = C2C2G2G2a2a2G2 2F2F2E2E2D2D2C2 2C2C2G2G2a2a2G2 2F2F2E2E2D2D2C2 2G2G2F2F2E2E2D2 2G2G2F2F2E2E2D2 2C2C2G2G2a2a2G2 2F2F2E2E2D2D2C2 2
+
+# intf_nv_audio_rate: Sampling rate of the generated audio
+intf_nv_audio_rate = 48000
+
+# intf_nv_audio_bit_depth: Bit depth of the generated audio
+intf_nv_audio_bit_depth = 16
+
+# intf_nv_audio_channels: The number of channels of the generated audio
+intf_nv_audio_channels = 2
+
+# intf_nv_volume: The volune of the tone generation PCM in dB
+intf_nv_volume = 0
+
+# Optionally replace the last one or two channels with fixed sample values
+# intf_nv_fv1: First fixed 32-bit value
+#intf_nv_fv1 = 1234
+
+# intf_nv_fv2: Second fixed 32-bit value
+#intf_nv_fv2 = 5678
+
+
+
+
+
diff --git a/lib/avtp_pipeline/intf_viewer/latency_listener.ini b/lib/avtp_pipeline/intf_viewer/latency_listener.ini
index b85d4e18..ff003baa 100644
--- a/lib/avtp_pipeline/intf_viewer/latency_listener.ini
+++ b/lib/avtp_pipeline/intf_viewer/latency_listener.ini
@@ -15,6 +15,12 @@
# talker or listener
role = listener
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
stream_addr = 84:7E:40:2C:8F:DE
diff --git a/lib/avtp_pipeline/intf_viewer/latency_talker.ini b/lib/avtp_pipeline/intf_viewer/latency_talker.ini
index f69a6673..515e7b22 100644
--- a/lib/avtp_pipeline/intf_viewer/latency_talker.ini
+++ b/lib/avtp_pipeline/intf_viewer/latency_talker.ini
@@ -15,6 +15,12 @@
# talker or listener
role = talker
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
#stream_addr = 00:25:64:48:ca:a8
diff --git a/lib/avtp_pipeline/intf_viewer/openavb_intf_viewer.c b/lib/avtp_pipeline/intf_viewer/openavb_intf_viewer.c
index 3ad743ca..c942089f 100755
--- a/lib/avtp_pipeline/intf_viewer/openavb_intf_viewer.c
+++ b/lib/avtp_pipeline/intf_viewer/openavb_intf_viewer.c
@@ -1,520 +1,521 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-/*
-* MODULE SUMMARY : Viewer interface module.
-*
-* This interface module is only a listener and is used to simply display
-* contents recieved in a number of different formats. Additionally it is
-* mapping type aware and can display header values for different mappings
-*/
-
-#include <stdlib.h>
-#include <string.h>
-#include "openavb_platform_pub.h"
-#include "openavb_types_pub.h"
-#include "openavb_trace_pub.h"
-#include "openavb_mediaq_pub.h"
-#include "openavb_intf_pub.h"
-
-#define AVB_LOG_COMPONENT "Viewer Interface"
-#include "openavb_log_pub.h"
-
-typedef enum {
- VIEWER_MODE_DETAIL = 0,
- VIEWER_MODE_MAPPING_AWARE = 1,
- VIEWER_MODE_AVTP_TIMESTAMP = 2,
- VIEWER_MODE_LATENCY = 3,
- VIEWER_MODE_SELECTIVE_TIMESTAMP = 4,
- VIEWER_MODE_LATE = 5,
- VIEWER_MODE_GAP = 6,
-} viewer_mode_t;
-
-typedef struct {
- /////////////
- // Config data
- /////////////
- viewer_mode_t viewType;
-
- // Frequency of output
- U32 viewInterval;
-
- // Offest into the raw frame to output
- U32 rawOffset;
-
- // Length of the raw frame to output
- U32 rawLength;
-
- // Ignore timestamp at listener.
- bool ignoreTimestamp;
-
- /////////////
- // Variable data
- /////////////
- U32 servicedCount;
-
- S64 accumLateNS;
-
- S32 maxLateNS;
-
- U64 accumGapNS;
-
- U32 maxGapNS;
-
- U64 prevNowTime;
-
- S64 accumAvtpDeltaNS;
-
- S32 maxAvtpDeltaNS;
-
- U64 prevAvtpTimestampTime;
-
- U32 skipCountdown;
-
- float jitter;
-
- S32 avgForJitter;
-
-} pvt_data_t;
-
-// Each configuration name value pair for this mapping will result in this callback being called.
-void openavbIntfViewerCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_INTF);
-
- if (pMediaQ) {
- char *pEnd;
- long tmp;
-
- pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
- if (!pPvtData) {
- AVB_LOG_ERROR("Private interface module data not allocated.");
- return;
- }
-
- // intf_nv_view_type: Type of viewing output. 0 = raw, 1 = mapping aware, 2 = timestamps only, 3 = latency output, 4 = Selective timestamp error reporting
- if (strcmp(name, "intf_nv_view_type") == 0) {
- pPvtData->viewType = (viewer_mode_t)strtol(value, &pEnd, 10);
- }
-
- else if (strcmp(name, "intf_nv_view_interval") == 0) {
- pPvtData->viewInterval = strtol(value, &pEnd, 10);
- if (pPvtData->viewInterval == 0) {
- pPvtData->viewInterval = 1000;
- }
- }
-
- else if (strcmp(name, "intf_nv_raw_offset") == 0) {
- pPvtData->rawOffset = strtol(value, &pEnd, 10);
- }
-
- else if (strcmp(name, "intf_nv_raw_length") == 0) {
- pPvtData->rawLength = strtol(value, &pEnd, 10);
- if (pPvtData->rawLength < 1)
- pPvtData->rawLength = 1000;
- }
-
- else if (strcmp(name, "intf_nv_ignore_timestamp") == 0) {
- tmp = strtol(value, &pEnd, 10);
- if (*pEnd == '\0' && tmp == 1) {
- pPvtData->ignoreTimestamp = (tmp == 1);
- }
- }
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_INTF);
-}
-
-void openavbIntfViewerGenInitCB(media_q_t *pMediaQ)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_INTF);
- AVB_TRACE_EXIT(AVB_TRACE_INTF);
-}
-
-// No talker functionality in this interface
-void openavbIntfViewerTxInitCB(media_q_t *pMediaQ)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_INTF);
- AVB_TRACE_EXIT(AVB_TRACE_INTF);
-}
-
-// No talker functionality in this interface
-bool openavbIntfViewerTxCB(media_q_t *pMediaQ)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
- AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
- return FALSE;
-}
-
-// A call to this callback indicates that this interface module will be
-// a listener. Any listener initialization can be done in this function.
-void openavbIntfViewerRxInitCB(media_q_t *pMediaQ)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_INTF);
-
- if (pMediaQ) {
- pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
- if (!pPvtData) {
- AVB_LOG_ERROR("Private interface module data not allocated.");
- return;
- }
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_INTF);
-}
-
-// This callback is called when acting as a listener.
-bool openavbIntfViewerRxCB(media_q_t *pMediaQ)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
- if (pMediaQ) {
- pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
- if (!pPvtData) {
- AVB_LOG_ERROR("Private interface module data not allocated.");
- return FALSE;
- }
-
- media_q_item_t *pMediaQItem = openavbMediaQTailLock(pMediaQ, pPvtData->ignoreTimestamp);
- if (pMediaQItem) {
-
- // The skip countdown allow the viewer modes to set a number of packets to ignore
- // after logging to reduce or eliminate the logging from affecting the stats.
- if (pPvtData->skipCountdown)
- pPvtData->skipCountdown--;
-
- if (pMediaQItem->dataLen && !pPvtData->skipCountdown) {
- pPvtData->servicedCount++;
-
- if (pPvtData->viewType == VIEWER_MODE_DETAIL) {
- U32 avtpTimestamp;
- U64 avtpTimestampTime;
- bool avtpTimestampValid;
- U32 nowTimestamp;
- U64 nowTimestampTime;
- bool nowTimestampValid;
- U64 nowTime;
- S32 lateNS = 0;
- U64 gapNS = 0;
-
- avtpTimestamp = openavbAvtpTimeGetAvtpTimestamp(pMediaQItem->pAvtpTime);
- avtpTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime);
- avtpTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime);
-
- openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
- nowTimestamp = openavbAvtpTimeGetAvtpTimestamp(pMediaQItem->pAvtpTime);
- nowTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime);
- nowTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime);
-
- CLOCK_GETTIME64(OPENAVB_CLOCK_REALTIME, &nowTime);
-
- if (avtpTimestampValid && nowTimestampValid) {
- lateNS = nowTimestampTime - avtpTimestampTime;
- if (lateNS > pPvtData->maxLateNS) {
- pPvtData->maxLateNS = lateNS;
- }
- pPvtData->accumLateNS += lateNS;
-
- if (pPvtData->servicedCount > 1) {
- gapNS = nowTime - pPvtData->prevNowTime;
- if (gapNS > pPvtData->maxGapNS) {
- pPvtData->maxGapNS = gapNS;
- }
- pPvtData->accumGapNS += gapNS;
- }
- pPvtData->prevNowTime = nowTime;
-
- if ((pPvtData->servicedCount % pPvtData->viewInterval) == 0) {
- S32 lateAvg = pPvtData->accumLateNS / pPvtData->servicedCount;
- S32 gapAvg = pPvtData->accumGapNS / (pPvtData->servicedCount - 1);
- AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "****************************", LOG_RT_DATATYPE_CONST_STR, NULL);
- AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Packets: %u", LOG_RT_DATATYPE_U32, &pPvtData->servicedCount);
- AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "AVTP Timestamp: %u NS", LOG_RT_DATATYPE_U32, &avtpTimestamp);
- AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Now Timestamp: %u NS", LOG_RT_DATATYPE_U32, &nowTimestamp);
- AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Late: %d NS", LOG_RT_DATATYPE_S32, &lateNS);
- AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Late Avg: %d NS", LOG_RT_DATATYPE_S32, &lateAvg);
- AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Late Max: %d NS", LOG_RT_DATATYPE_S32, &pPvtData->maxLateNS);
- AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Gap: %u NS", LOG_RT_DATATYPE_U32, &gapNS);
- AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Gap Avg: %u NS", LOG_RT_DATATYPE_U32, &gapAvg);
- AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Gap Max: %u NS", LOG_RT_DATATYPE_U32, &pPvtData->maxGapNS);
- AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Data length: %u", LOG_RT_DATATYPE_U32, &pMediaQItem->dataLen);
-
- pPvtData->accumLateNS = 0;
- pPvtData->maxLateNS = 0;
- pPvtData->accumGapNS = 0;
- pPvtData->maxGapNS = 0;
- pPvtData->prevNowTime = 0;
- pPvtData->servicedCount = 0;
- pPvtData->skipCountdown = 10;
- }
- }
- }
-
- else if (pPvtData->viewType == VIEWER_MODE_MAPPING_AWARE) {
- }
-
- else if (pPvtData->viewType == VIEWER_MODE_AVTP_TIMESTAMP) {
- U64 avtpTimestampTime;
- bool avtpTimestampValid;
- S32 deltaNS = 0;
-
- avtpTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime);
- avtpTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime);
-
- if (avtpTimestampValid) {
- if (pPvtData->servicedCount > 1) {
- deltaNS = avtpTimestampTime - pPvtData->prevAvtpTimestampTime;
- if (deltaNS > pPvtData->maxAvtpDeltaNS) {
- pPvtData->maxAvtpDeltaNS = deltaNS;
- }
- pPvtData->accumAvtpDeltaNS += deltaNS;
-
- if (pPvtData->avgForJitter != 0) {
- S32 deltaJitter = pPvtData->avgForJitter - deltaNS;
- if (deltaJitter < 0) deltaJitter = -deltaJitter;
- pPvtData->jitter += (1.0/16.0) * ((float)deltaJitter - pPvtData->jitter);
- }
- }
- pPvtData->prevAvtpTimestampTime = avtpTimestampTime;
-
- if ((pPvtData->servicedCount % pPvtData->viewInterval) == 0) {
- S32 deltaAvg = pPvtData->accumAvtpDeltaNS / (pPvtData->servicedCount - 1);
- U32 jitter = (U32)(pPvtData->jitter);
-
- AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "AVTP Timestamp Delta: %d NS ", LOG_RT_DATATYPE_S32, &deltaNS);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "AVTP Timestamp Delta Avg: %d NS ", LOG_RT_DATATYPE_S32, &deltaAvg);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "AVTP Timestamp Delta Max: %d NS ", LOG_RT_DATATYPE_S32, &pPvtData->maxAvtpDeltaNS);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "Jitter: %d", LOG_RT_DATATYPE_S32, &jitter);
-
- pPvtData->accumAvtpDeltaNS = 0;
- pPvtData->maxAvtpDeltaNS = 0;
- pPvtData->servicedCount = 0;
- pPvtData->prevAvtpTimestampTime = 0;
- pPvtData->skipCountdown = 10;
- pPvtData->jitter = 0.0;
- pPvtData->avgForJitter = deltaAvg;
- }
- }
- }
-
- else if (pPvtData->viewType == VIEWER_MODE_LATENCY) {
- U64 avtpTimestampTime;
- bool avtpTimestampValid;
- U64 nowTimestampTime;
- bool nowTimestampValid;
- S32 lateNS = 0;
-
- avtpTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime);
- avtpTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime);
-
- openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
- nowTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime);
- nowTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime);
-
- if (avtpTimestampValid && nowTimestampValid) {
- lateNS = nowTimestampTime - avtpTimestampTime;
- if (lateNS > pPvtData->maxLateNS) {
- pPvtData->maxLateNS = lateNS;
- }
- pPvtData->accumLateNS += lateNS;
-
- if (pPvtData->avgForJitter != 0) {
- S32 lateJitter = pPvtData->avgForJitter - lateNS;
- if (lateJitter < 0) lateJitter = -lateJitter;
- pPvtData->jitter += (1.0/16.0) * ((float)lateJitter - pPvtData->jitter);
- }
-
- if ((pPvtData->servicedCount % pPvtData->viewInterval) == 0) {
- S32 lateAvg = pPvtData->accumLateNS / pPvtData->servicedCount;
- U32 jitter = (U32)(pPvtData->jitter);
-
- AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "Latency: %d NS ", LOG_RT_DATATYPE_S32, &lateNS);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Latency Avg: %d NS ", LOG_RT_DATATYPE_S32, &lateAvg);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Latency Max: %d NS ", LOG_RT_DATATYPE_S32, &pPvtData->maxLateNS);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "Jitter: %d", LOG_RT_DATATYPE_S32, &jitter);
-
- pPvtData->accumLateNS = 0;
- pPvtData->maxLateNS = 0;
- pPvtData->servicedCount = 0;
- pPvtData->skipCountdown = 10;
- pPvtData->jitter = 0.0;
- pPvtData->avgForJitter = lateAvg;
- }
- }
- }
-
- else if (pPvtData->viewType == VIEWER_MODE_SELECTIVE_TIMESTAMP) {
- }
-
- else if (pPvtData->viewType == VIEWER_MODE_LATE) {
- U64 avtpTimestampTime;
- bool avtpTimestampValid;
- U64 nowTimestampTime;
- bool nowTimestampValid;
- S32 lateNS = 0;
-
- avtpTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime);
- avtpTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime);
-
- openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
- nowTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime);
- nowTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime);
-
- if (avtpTimestampValid && nowTimestampValid) {
- lateNS = nowTimestampTime - avtpTimestampTime;
- if (lateNS > pPvtData->maxLateNS) {
- pPvtData->maxLateNS = lateNS;
- }
- pPvtData->accumLateNS += lateNS;
-
- if (pPvtData->avgForJitter != 0) {
- S32 lateJitter = pPvtData->avgForJitter - lateNS;
- if (lateJitter < 0) lateJitter = -lateJitter;
- pPvtData->jitter += (1.0/16.0) * ((float)lateJitter - pPvtData->jitter);
- }
-
- if ((pPvtData->servicedCount % pPvtData->viewInterval) == 0) {
- S32 lateAvg = pPvtData->accumLateNS / pPvtData->servicedCount;
- U32 jitter = (U32)(pPvtData->jitter);
-
- AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "Late: %d NS ", LOG_RT_DATATYPE_S32, &lateNS);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Late Avg: %d NS ", LOG_RT_DATATYPE_S32, &lateAvg);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Late Max: %d NS ", LOG_RT_DATATYPE_S32, &pPvtData->maxLateNS);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "Jitter: %d", LOG_RT_DATATYPE_S32, &jitter);
-
- pPvtData->accumLateNS = 0;
- pPvtData->maxLateNS = 0;
- pPvtData->servicedCount = 0;
- pPvtData->skipCountdown = 10;
- pPvtData->jitter = 0.0;
- pPvtData->avgForJitter = lateAvg;
- }
- }
- }
-
- else if (pPvtData->viewType == VIEWER_MODE_GAP) {
- U64 nowTime;
- U64 gapNS = 0;
-
- CLOCK_GETTIME64(OPENAVB_CLOCK_REALTIME, &nowTime);
-
- if (pPvtData->servicedCount > 1) {
- gapNS = nowTime - pPvtData->prevNowTime;
- if (gapNS > pPvtData->maxGapNS) {
- pPvtData->maxGapNS = gapNS;
- }
- pPvtData->accumGapNS += gapNS;
-
- if (pPvtData->avgForJitter != 0) {
- S32 gapJitter = pPvtData->avgForJitter - gapNS;
- if (gapJitter < 0) gapJitter = -gapJitter;
- pPvtData->jitter += (1.0/16.0) * ((float)gapJitter - pPvtData->jitter);
- }
- }
- pPvtData->prevNowTime = nowTime;
-
- if ((pPvtData->servicedCount % pPvtData->viewInterval) == 0) {
- S32 gapAvg = pPvtData->accumGapNS / (pPvtData->servicedCount - 1);
- U32 jitter = (U32)(pPvtData->jitter);
-
- AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "Gap: %d NS ", LOG_RT_DATATYPE_S32, &gapNS);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Gap Avg: %d NS ", LOG_RT_DATATYPE_S32, &gapAvg);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Gap Max: %d NS ", LOG_RT_DATATYPE_S32, &pPvtData->maxGapNS);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "Jitter: %d", LOG_RT_DATATYPE_S32, &jitter);
-
- pPvtData->accumGapNS = 0;
- pPvtData->maxGapNS = 0;
- pPvtData->prevNowTime = 0;
- pPvtData->servicedCount = 0;
- pPvtData->skipCountdown = 10;
- pPvtData->jitter = 0.0;
- pPvtData->avgForJitter = gapAvg;
- }
- }
-
- }
- openavbMediaQTailPull(pMediaQ);
- }
- }
- AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
- return TRUE;
-}
-
-
-// This callback will be called when the interface needs to be closed. All shutdown should
-// occur in this function.
-void openavbIntfViewerEndCB(media_q_t *pMediaQ)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_INTF);
- AVB_TRACE_EXIT(AVB_TRACE_INTF);
-}
-
-void openavbIntfViewerGenEndCB(media_q_t *pMediaQ)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_INTF);
- AVB_TRACE_EXIT(AVB_TRACE_INTF);
-}
-
-// Main initialization entry point into the interface module
-extern DLL_EXPORT bool openavbIntfViewerInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_INTF);
-
- if (pMediaQ) {
- pMediaQ->pPvtIntfInfo = calloc(1, sizeof(pvt_data_t)); // Memory freed by the media queue when the media queue is destroyed.
-
- if (!pMediaQ->pPvtIntfInfo) {
- AVB_LOG_ERROR("Unable to allocate memory for AVTP interface module.");
- return FALSE;
- }
-
- pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
-
- pIntfCB->intf_cfg_cb = openavbIntfViewerCfgCB;
- pIntfCB->intf_gen_init_cb = openavbIntfViewerGenInitCB;
- pIntfCB->intf_tx_init_cb = openavbIntfViewerTxInitCB;
- pIntfCB->intf_tx_cb = openavbIntfViewerTxCB;
- pIntfCB->intf_rx_init_cb = openavbIntfViewerRxInitCB;
- pIntfCB->intf_rx_cb = openavbIntfViewerRxCB;
- pIntfCB->intf_end_cb = openavbIntfViewerEndCB;
- pIntfCB->intf_gen_end_cb = openavbIntfViewerGenEndCB;
-
- pPvtData->viewType = VIEWER_MODE_DETAIL;
- pPvtData->viewInterval = 1000;
- pPvtData->rawOffset = 0;
- pPvtData->rawLength = 20;
- pPvtData->ignoreTimestamp = FALSE;
- pPvtData->skipCountdown = 0;
- pPvtData->jitter = 0.0;
- pPvtData->avgForJitter = 0;
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_INTF);
- return TRUE;
-}
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+* MODULE SUMMARY : Viewer interface module.
+*
+* This interface module is only a listener and is used to simply display
+* contents recieved in a number of different formats. Additionally it is
+* mapping type aware and can display header values for different mappings
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include "openavb_platform_pub.h"
+#include "openavb_types_pub.h"
+#include "openavb_trace_pub.h"
+#include "openavb_mediaq_pub.h"
+#include "openavb_intf_pub.h"
+
+#define AVB_LOG_COMPONENT "Viewer Interface"
+#include "openavb_log_pub.h"
+
+typedef enum {
+ VIEWER_MODE_DETAIL = 0,
+ VIEWER_MODE_MAPPING_AWARE = 1,
+ VIEWER_MODE_AVTP_TIMESTAMP = 2,
+ VIEWER_MODE_LATENCY = 3,
+ VIEWER_MODE_SELECTIVE_TIMESTAMP = 4,
+ VIEWER_MODE_LATE = 5,
+ VIEWER_MODE_GAP = 6,
+} viewer_mode_t;
+
+typedef struct {
+ /////////////
+ // Config data
+ /////////////
+ viewer_mode_t viewType;
+
+ // Frequency of output
+ U32 viewInterval;
+
+ // Offest into the raw frame to output
+ U32 rawOffset;
+
+ // Length of the raw frame to output
+ U32 rawLength;
+
+ // Ignore timestamp at listener.
+ bool ignoreTimestamp;
+
+ /////////////
+ // Variable data
+ /////////////
+ U32 servicedCount;
+
+ S64 accumLateNS;
+
+ S32 maxLateNS;
+
+ U64 accumGapNS;
+
+ U32 maxGapNS;
+
+ U64 prevNowTime;
+
+ S64 accumAvtpDeltaNS;
+
+ S32 maxAvtpDeltaNS;
+
+ U64 prevAvtpTimestampTime;
+
+ U32 skipCountdown;
+
+ float jitter;
+
+ S32 avgForJitter;
+
+} pvt_data_t;
+
+// Each configuration name value pair for this mapping will result in this callback being called.
+void openavbIntfViewerCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ char *pEnd;
+ long tmp;
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+
+ // intf_nv_view_type: Type of viewing output. 0 = raw, 1 = mapping aware, 2 = timestamps only, 3 = latency output, 4 = Selective timestamp error reporting
+ if (strcmp(name, "intf_nv_view_type") == 0) {
+ pPvtData->viewType = (viewer_mode_t)strtol(value, &pEnd, 10);
+ }
+
+ else if (strcmp(name, "intf_nv_view_interval") == 0) {
+ pPvtData->viewInterval = strtol(value, &pEnd, 10);
+ if (pPvtData->viewInterval == 0) {
+ pPvtData->viewInterval = 1000;
+ }
+ }
+
+ else if (strcmp(name, "intf_nv_raw_offset") == 0) {
+ pPvtData->rawOffset = strtol(value, &pEnd, 10);
+ }
+
+ else if (strcmp(name, "intf_nv_raw_length") == 0) {
+ pPvtData->rawLength = strtol(value, &pEnd, 10);
+ if (pPvtData->rawLength < 1)
+ pPvtData->rawLength = 1000;
+ }
+
+ else if (strcmp(name, "intf_nv_ignore_timestamp") == 0) {
+ tmp = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && tmp == 1) {
+ pPvtData->ignoreTimestamp = (tmp == 1);
+ }
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+void openavbIntfViewerGenInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// No talker functionality in this interface
+void openavbIntfViewerTxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// No talker functionality in this interface
+bool openavbIntfViewerTxCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE;
+}
+
+// A call to this callback indicates that this interface module will be
+// a listener. Any listener initialization can be done in this function.
+void openavbIntfViewerRxInitCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// This callback is called when acting as a listener.
+bool openavbIntfViewerRxCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
+ if (pMediaQ) {
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return FALSE;
+ }
+
+ media_q_item_t *pMediaQItem = openavbMediaQTailLock(pMediaQ, pPvtData->ignoreTimestamp);
+ if (pMediaQItem) {
+
+ // The skip countdown allow the viewer modes to set a number of packets to ignore
+ // after logging to reduce or eliminate the logging from affecting the stats.
+ if (pPvtData->skipCountdown)
+ pPvtData->skipCountdown--;
+
+ if (pMediaQItem->dataLen && !pPvtData->skipCountdown) {
+ pPvtData->servicedCount++;
+
+ if (pPvtData->viewType == VIEWER_MODE_DETAIL) {
+ U32 avtpTimestamp;
+ U64 avtpTimestampTime;
+ bool avtpTimestampValid;
+ U32 nowTimestamp;
+ U64 nowTimestampTime;
+ bool nowTimestampValid;
+ U64 nowTime;
+ S32 lateNS = 0;
+ U64 gapNS = 0;
+
+ avtpTimestamp = openavbAvtpTimeGetAvtpTimestamp(pMediaQItem->pAvtpTime);
+ avtpTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime);
+ avtpTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime);
+
+ openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
+ nowTimestamp = openavbAvtpTimeGetAvtpTimestamp(pMediaQItem->pAvtpTime);
+ nowTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime);
+ nowTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime);
+
+ CLOCK_GETTIME64(OPENAVB_CLOCK_REALTIME, &nowTime);
+
+ if (avtpTimestampValid && nowTimestampValid) {
+ lateNS = nowTimestampTime - avtpTimestampTime;
+ if (lateNS > pPvtData->maxLateNS) {
+ pPvtData->maxLateNS = lateNS;
+ }
+ pPvtData->accumLateNS += lateNS;
+
+ if (pPvtData->servicedCount > 1) {
+ gapNS = nowTime - pPvtData->prevNowTime;
+ if (gapNS > pPvtData->maxGapNS) {
+ pPvtData->maxGapNS = gapNS;
+ }
+ pPvtData->accumGapNS += gapNS;
+ }
+ pPvtData->prevNowTime = nowTime;
+
+ if ((pPvtData->servicedCount % pPvtData->viewInterval) == 0) {
+ S32 lateAvg = pPvtData->accumLateNS / pPvtData->servicedCount;
+ S32 gapAvg = pPvtData->accumGapNS / (pPvtData->servicedCount - 1);
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "****************************", LOG_RT_DATATYPE_CONST_STR, NULL);
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Packets: %u", LOG_RT_DATATYPE_U32, &pPvtData->servicedCount);
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "AVTP Timestamp: %u NS", LOG_RT_DATATYPE_U32, &avtpTimestamp);
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Now Timestamp: %u NS", LOG_RT_DATATYPE_U32, &nowTimestamp);
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Late: %d NS", LOG_RT_DATATYPE_S32, &lateNS);
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Late Avg: %d NS", LOG_RT_DATATYPE_S32, &lateAvg);
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Late Max: %d NS", LOG_RT_DATATYPE_S32, &pPvtData->maxLateNS);
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Gap: %u NS", LOG_RT_DATATYPE_U32, &gapNS);
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Gap Avg: %u NS", LOG_RT_DATATYPE_U32, &gapAvg);
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Gap Max: %u NS", LOG_RT_DATATYPE_U32, &pPvtData->maxGapNS);
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, LOG_RT_END, "Data length: %u", LOG_RT_DATATYPE_U32, &pMediaQItem->dataLen);
+
+ pPvtData->accumLateNS = 0;
+ pPvtData->maxLateNS = 0;
+ pPvtData->accumGapNS = 0;
+ pPvtData->maxGapNS = 0;
+ pPvtData->prevNowTime = 0;
+ pPvtData->servicedCount = 0;
+ pPvtData->skipCountdown = 10;
+ }
+ }
+ }
+
+ else if (pPvtData->viewType == VIEWER_MODE_MAPPING_AWARE) {
+ }
+
+ else if (pPvtData->viewType == VIEWER_MODE_AVTP_TIMESTAMP) {
+ U64 avtpTimestampTime;
+ bool avtpTimestampValid;
+ S32 deltaNS = 0;
+
+ avtpTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime);
+ avtpTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime);
+
+ if (avtpTimestampValid) {
+ if (pPvtData->servicedCount > 1) {
+ deltaNS = avtpTimestampTime - pPvtData->prevAvtpTimestampTime;
+ if (deltaNS > pPvtData->maxAvtpDeltaNS) {
+ pPvtData->maxAvtpDeltaNS = deltaNS;
+ }
+ pPvtData->accumAvtpDeltaNS += deltaNS;
+
+ if (pPvtData->avgForJitter != 0) {
+ S32 deltaJitter = pPvtData->avgForJitter - deltaNS;
+ if (deltaJitter < 0) deltaJitter = -deltaJitter;
+ pPvtData->jitter += (1.0/16.0) * ((float)deltaJitter - pPvtData->jitter);
+ }
+ }
+ pPvtData->prevAvtpTimestampTime = avtpTimestampTime;
+
+ if ((pPvtData->servicedCount % pPvtData->viewInterval) == 0) {
+ S32 deltaAvg = pPvtData->accumAvtpDeltaNS / (pPvtData->servicedCount - 1);
+ U32 jitter = (U32)(pPvtData->jitter);
+
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "AVTP Timestamp Delta: %d NS ", LOG_RT_DATATYPE_S32, &deltaNS);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "AVTP Timestamp Delta Avg: %d NS ", LOG_RT_DATATYPE_S32, &deltaAvg);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "AVTP Timestamp Delta Max: %d NS ", LOG_RT_DATATYPE_S32, &pPvtData->maxAvtpDeltaNS);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "Jitter: %d", LOG_RT_DATATYPE_S32, &jitter);
+
+ pPvtData->accumAvtpDeltaNS = 0;
+ pPvtData->maxAvtpDeltaNS = 0;
+ pPvtData->servicedCount = 0;
+ pPvtData->prevAvtpTimestampTime = 0;
+ pPvtData->skipCountdown = 10;
+ pPvtData->jitter = 0.0;
+ pPvtData->avgForJitter = deltaAvg;
+ }
+ }
+ }
+
+ else if (pPvtData->viewType == VIEWER_MODE_LATENCY) {
+ U64 avtpTimestampTime;
+ bool avtpTimestampValid;
+ U64 nowTimestampTime;
+ bool nowTimestampValid;
+ S32 lateNS = 0;
+
+ avtpTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime);
+ avtpTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime);
+
+ openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
+ nowTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime);
+ nowTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime);
+
+ if (avtpTimestampValid && nowTimestampValid) {
+ lateNS = nowTimestampTime - avtpTimestampTime;
+ if (lateNS > pPvtData->maxLateNS) {
+ pPvtData->maxLateNS = lateNS;
+ }
+ pPvtData->accumLateNS += lateNS;
+
+ if (pPvtData->avgForJitter != 0) {
+ S32 lateJitter = pPvtData->avgForJitter - lateNS;
+ if (lateJitter < 0) lateJitter = -lateJitter;
+ pPvtData->jitter += (1.0/16.0) * ((float)lateJitter - pPvtData->jitter);
+ }
+
+ if ((pPvtData->servicedCount % pPvtData->viewInterval) == 0) {
+ S32 lateAvg = pPvtData->accumLateNS / pPvtData->servicedCount;
+ U32 jitter = (U32)(pPvtData->jitter);
+
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "Latency: %d NS ", LOG_RT_DATATYPE_S32, &lateNS);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Latency Avg: %d NS ", LOG_RT_DATATYPE_S32, &lateAvg);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Latency Max: %d NS ", LOG_RT_DATATYPE_S32, &pPvtData->maxLateNS);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "Jitter: %d", LOG_RT_DATATYPE_S32, &jitter);
+
+ pPvtData->accumLateNS = 0;
+ pPvtData->maxLateNS = 0;
+ pPvtData->servicedCount = 0;
+ pPvtData->skipCountdown = 10;
+ pPvtData->jitter = 0.0;
+ pPvtData->avgForJitter = lateAvg;
+ }
+ }
+ }
+
+ else if (pPvtData->viewType == VIEWER_MODE_SELECTIVE_TIMESTAMP) {
+ }
+
+ else if (pPvtData->viewType == VIEWER_MODE_LATE) {
+ U64 avtpTimestampTime;
+ bool avtpTimestampValid;
+ U64 nowTimestampTime;
+ bool nowTimestampValid;
+ S32 lateNS = 0;
+
+ avtpTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime);
+ avtpTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime);
+
+ openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
+ nowTimestampTime = openavbAvtpTimeGetAvtpTimeNS(pMediaQItem->pAvtpTime);
+ nowTimestampValid = openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime);
+
+ if (avtpTimestampValid && nowTimestampValid) {
+ lateNS = nowTimestampTime - avtpTimestampTime;
+ if (lateNS > pPvtData->maxLateNS) {
+ pPvtData->maxLateNS = lateNS;
+ }
+ pPvtData->accumLateNS += lateNS;
+
+ if (pPvtData->avgForJitter != 0) {
+ S32 lateJitter = pPvtData->avgForJitter - lateNS;
+ if (lateJitter < 0) lateJitter = -lateJitter;
+ pPvtData->jitter += (1.0/16.0) * ((float)lateJitter - pPvtData->jitter);
+ }
+
+ if ((pPvtData->servicedCount % pPvtData->viewInterval) == 0) {
+ S32 lateAvg = pPvtData->accumLateNS / pPvtData->servicedCount;
+ U32 jitter = (U32)(pPvtData->jitter);
+
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "Late: %d NS ", LOG_RT_DATATYPE_S32, &lateNS);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Late Avg: %d NS ", LOG_RT_DATATYPE_S32, &lateAvg);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Late Max: %d NS ", LOG_RT_DATATYPE_S32, &pPvtData->maxLateNS);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "Jitter: %d", LOG_RT_DATATYPE_S32, &jitter);
+
+ pPvtData->accumLateNS = 0;
+ pPvtData->maxLateNS = 0;
+ pPvtData->servicedCount = 0;
+ pPvtData->skipCountdown = 10;
+ pPvtData->jitter = 0.0;
+ pPvtData->avgForJitter = lateAvg;
+ }
+ }
+ }
+
+ else if (pPvtData->viewType == VIEWER_MODE_GAP) {
+ U64 nowTime;
+ U64 gapNS = 0;
+
+ CLOCK_GETTIME64(OPENAVB_CLOCK_REALTIME, &nowTime);
+
+ if (pPvtData->servicedCount > 1) {
+ gapNS = nowTime - pPvtData->prevNowTime;
+ if (gapNS > pPvtData->maxGapNS) {
+ pPvtData->maxGapNS = gapNS;
+ }
+ pPvtData->accumGapNS += gapNS;
+
+ if (pPvtData->avgForJitter != 0) {
+ S32 gapJitter = pPvtData->avgForJitter - gapNS;
+ if (gapJitter < 0) gapJitter = -gapJitter;
+ pPvtData->jitter += (1.0/16.0) * ((float)gapJitter - pPvtData->jitter);
+ }
+ }
+ pPvtData->prevNowTime = nowTime;
+
+ if ((pPvtData->servicedCount % pPvtData->viewInterval) == 0) {
+ S32 gapAvg = pPvtData->accumGapNS / (pPvtData->servicedCount - 1);
+ U32 jitter = (U32)(pPvtData->jitter);
+
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "Gap: %d NS ", LOG_RT_DATATYPE_S32, &gapNS);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Gap Avg: %d NS ", LOG_RT_DATATYPE_S32, &gapAvg);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "Gap Max: %d NS ", LOG_RT_DATATYPE_S32, &pPvtData->maxGapNS);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "Jitter: %d", LOG_RT_DATATYPE_S32, &jitter);
+
+ pPvtData->accumGapNS = 0;
+ pPvtData->maxGapNS = 0;
+ pPvtData->prevNowTime = 0;
+ pPvtData->servicedCount = 0;
+ pPvtData->skipCountdown = 10;
+ pPvtData->jitter = 0.0;
+ pPvtData->avgForJitter = gapAvg;
+ }
+ }
+
+ }
+ openavbMediaQTailPull(pMediaQ);
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return TRUE;
+}
+
+
+// This callback will be called when the interface needs to be closed. All shutdown should
+// occur in this function.
+void openavbIntfViewerEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+void openavbIntfViewerGenEndCB(media_q_t *pMediaQ)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
+// Main initialization entry point into the interface module
+extern DLL_EXPORT bool openavbIntfViewerInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+
+ if (pMediaQ) {
+ pMediaQ->pPvtIntfInfo = calloc(1, sizeof(pvt_data_t)); // Memory freed by the media queue when the media queue is destroyed.
+
+ if (!pMediaQ->pPvtIntfInfo) {
+ AVB_LOG_ERROR("Unable to allocate memory for AVTP interface module.");
+ return FALSE;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+
+ pIntfCB->intf_cfg_cb = openavbIntfViewerCfgCB;
+ pIntfCB->intf_gen_init_cb = openavbIntfViewerGenInitCB;
+ pIntfCB->intf_tx_init_cb = openavbIntfViewerTxInitCB;
+ pIntfCB->intf_tx_cb = openavbIntfViewerTxCB;
+ pIntfCB->intf_rx_init_cb = openavbIntfViewerRxInitCB;
+ pIntfCB->intf_rx_cb = openavbIntfViewerRxCB;
+ pIntfCB->intf_end_cb = openavbIntfViewerEndCB;
+ pIntfCB->intf_gen_end_cb = openavbIntfViewerGenEndCB;
+
+ pPvtData->viewType = VIEWER_MODE_DETAIL;
+ pPvtData->viewInterval = 1000;
+ pPvtData->rawOffset = 0;
+ pPvtData->rawLength = 20;
+ pPvtData->ignoreTimestamp = FALSE;
+ pPvtData->skipCountdown = 0;
+ pPvtData->jitter = 0.0;
+ pPvtData->avgForJitter = 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/intf_viewer/viewer_listener.ini b/lib/avtp_pipeline/intf_viewer/viewer_listener.ini
index 01e4f726..378a1e2c 100644
--- a/lib/avtp_pipeline/intf_viewer/viewer_listener.ini
+++ b/lib/avtp_pipeline/intf_viewer/viewer_listener.ini
@@ -5,6 +5,12 @@
# talker or listener
role = listener
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
stream_addr = 00:0c:29:f8:3e:c6
diff --git a/lib/avtp_pipeline/maap/openavb_maap.h b/lib/avtp_pipeline/maap/openavb_maap.h
index acf9ffcc..277ae4a7 100644
--- a/lib/avtp_pipeline/maap/openavb_maap.h
+++ b/lib/avtp_pipeline/maap/openavb_maap.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -27,35 +28,25 @@ Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyrig
Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
+
#ifndef OPENAVB_MAAP_H
#define OPENAVB_MAAP_H 1
#include "openavb_types.h"
typedef void (openavbMaapRestartCb_t)(void *handle, struct ether_addr *addr);
-typedef enum {
- MAAP_ALLOC_GENERATE, // normal, random allocation
- MAAP_ALLOC_PROBE, // specify address to be allocated
- MAAP_ALLOC_DEFEND // specify address, and skip to DEFEND state
-} openavbMaapAllocAction_t;
-
// MAAP library lifecycle
-bool openavbMaapInitialize(const char *ifname, openavbMaapRestartCb_t* cbfn);
+bool openavbMaapInitialize(const char *ifname, unsigned int maapPort, struct ether_addr *maapPrefAddr, openavbMaapRestartCb_t* cbfn);
void openavbMaapFinalize();
+bool openavbMaapDaemonAvailable(void);
+
// Normal address allocation
-void* openavbMaapAllocate(int count,
- /* out */ struct ether_addr *addr);
-// Extended address allocation (testing)
-void* openavbMaapExtAlloc(int count,
- openavbMaapAllocAction_t action,
- /* in/out */ struct ether_addr *addr);
+// Will allocate the daemon-reserved address if available,
+// or one from the MAAP locally administered Pool otherwise.
+void* openavbMaapAllocate(int count, /* out */ struct ether_addr *addr);
+
// Release an allocated address range
void openavbMaapRelease(void* handle);
-// Dump state info for MAAP
-void openavbMaapListAllocs();
-// Dump heard announcements
-void openavbMaapListHeard();
-
#endif // OPENAVB_MAAP_H
diff --git a/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio.c b/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio.c
index d17788f1..ef3b4a91 100755
--- a/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio.c
+++ b/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio.c
@@ -1,16 +1,17 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
+
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -21,17 +22,17 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
/*
* MODULE SUMMARY : Implementation for AAF mapping module
*
- * AAF is defined in IEEE 1722-rev1/D12 (still in draft as of Feb 2015).
+ * AAF (AVTP Audio Format) is defined in IEEE 1722-2016 Clause 7.
*/
#include <stdlib.h>
@@ -57,6 +58,9 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
// - 1 Byte - TV bit (timestamp valid)
#define HIDX_AVTP_HIDE7_TV1 1
+// - 1 Byte - Sequence number
+#define HIDX_AVTP_SEQ_NUM 2
+
// - 1 Byte - TU bit (timestamp uncertain)
#define HIDX_AVTP_HIDE7_TU1 3
@@ -86,6 +90,7 @@ typedef enum {
AAF_FORMAT_INT_32,
AAF_FORMAT_INT_24,
AAF_FORMAT_INT_16,
+ AAF_FORMAT_AES3_32, // AVDECC_TODO: Implement this
} aaf_sample_format_t;
typedef enum {
@@ -97,6 +102,13 @@ typedef enum {
AAF_MAX_CHANNELS_LAYOUT = 15,
} aaf_automotive_channels_layout_t;
+typedef enum {
+ // Disabled - timestamp is valid in every avtp packet
+ TS_SPARSE_MODE_DISABLED = 0,
+ // Enabled - timestamp is valid in every 8th avtp packet
+ TS_SPARSE_MODE_ENABLED = 1
+} avb_audio_sparse_mode_t;
+
typedef struct {
/////////////
// Config data
@@ -114,12 +126,12 @@ typedef struct {
// MCR mode
avb_audio_mcr_t audioMcr;
- // MCR timestamp interval
+ // MCR timestamp interval
U32 mcrTimestampInterval;
- // MCR clock recovery interval
+ // MCR clock recovery interval
U32 mcrRecoveryInterval;
-
+
/////////////
// Variable data
/////////////
@@ -129,6 +141,7 @@ typedef struct {
aaf_sample_format_t aaf_format;
U8 aaf_bit_depth;
U32 payloadSize;
+ U32 payloadSizeMax;
U8 aaf_event_field;
@@ -136,7 +149,7 @@ typedef struct {
U32 intervalCounter;
- U32 sparseMode;
+ avb_audio_sparse_mode_t sparseMode;
bool mediaQItemSyncTS;
@@ -261,13 +274,19 @@ static void x_calculateSizes(media_q_t *pMediaQ)
// AAF packet size calculations
pPubMapInfo->packetFrameSizeBytes = pPubMapInfo->packetSampleSizeBytes * pPubMapInfo->audioChannels;
- pPvtData->payloadSize = pPubMapInfo->framesPerPacket * pPubMapInfo->packetFrameSizeBytes;
+ pPvtData->payloadSize = pPvtData->payloadSizeMax =
+ pPubMapInfo->framesPerPacket * pPubMapInfo->packetFrameSizeBytes;
AVB_LOGF_INFO("packet: sampleSz=%d * channels=%d => frameSz=%d * %d => payloadSz=%d",
pPubMapInfo->packetSampleSizeBytes,
pPubMapInfo->audioChannels,
pPubMapInfo->packetFrameSizeBytes,
pPubMapInfo->framesPerPacket,
pPvtData->payloadSize);
+ if (pPvtData->aaf_format >= AAF_FORMAT_INT_32 && pPvtData->aaf_format <= AAF_FORMAT_INT_16) {
+ // Determine the largest size we could receive before adjustments.
+ pPvtData->payloadSizeMax = 4 * pPubMapInfo->audioChannels * pPubMapInfo->framesPerPacket;
+ AVB_LOGF_DEBUG("packet: payloadSizeMax=%d", pPvtData->payloadSizeMax);
+ }
// MediaQ item size calculations
pPubMapInfo->packingFactor = pPvtData->packingFactor;
@@ -366,7 +385,7 @@ U16 openavbMapAVTPAudioMaxDataSizeCB(media_q_t *pMediaQ)
}
AVB_TRACE_EXIT(AVB_TRACE_MAP);
- return pPvtData->payloadSize + TOTAL_HEADER_SIZE;
+ return pPvtData->payloadSizeMax + TOTAL_HEADER_SIZE;
}
AVB_TRACE_EXIT(AVB_TRACE_MAP);
return 0;
@@ -405,13 +424,6 @@ void openavbMapAVTPAudioGenInitCB(media_q_t *pMediaQ)
openavbMediaQSetSize(pMediaQ, pPvtData->itemCount, pPubMapInfo->itemSize);
pPvtData->dataValid = TRUE;
-
- pPubMapInfo->sparseMode = pPvtData->sparseMode;
- if (pPubMapInfo->sparseMode == TS_SPARSE_MODE_ENABLED) {
- AVB_LOG_INFO("Sparse timestamping mode: enabled");
- } else {
- AVB_LOG_INFO("Sparse timestamping mode: disabled");
- }
}
AVB_TRACE_EXIT(AVB_TRACE_MAP);
}
@@ -424,7 +436,7 @@ void openavbMapAVTPAudioTxInitCB(media_q_t *pMediaQ)
AVB_TRACE_EXIT(AVB_TRACE_MAP);
}
-// CORE_TODO: This callback should be updated to work in a similiar way the uncompressed audio mapping. With allowing AVTP packets to be built
+// CORE_TODO: This callback should be updated to work in a similar way the uncompressed audio mapping. With allowing AVTP packets to be built
// from multiple media queue items. This allows interface to set into the media queue blocks of audio frames to properly correspond to
// a SYT_INTERVAL. Additionally the public data member sytInterval needs to be set in the same way the uncompressed audio mapping does.
// This talker callback will be called for each AVB observation interval.
@@ -433,30 +445,68 @@ tx_cb_ret_t openavbMapAVTPAudioTxCB(media_q_t *pMediaQ, U8 *pData, U32 *dataLen)
media_q_item_t *pMediaQItem = NULL;
AVB_TRACE_ENTRY(AVB_TRACE_MAP_DETAIL);
+ if (!pMediaQ) {
+ AVB_LOG_ERROR("Mapping module invalid MediaQ");
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TX_CB_RET_PACKET_NOT_READY;
+ }
+
if (!pData || !dataLen) {
AVB_LOG_ERROR("Mapping module data or data length argument incorrect.");
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
return TX_CB_RET_PACKET_NOT_READY;
}
- if (pMediaQ)
- pMediaQItem = openavbMediaQTailLock(pMediaQ, TRUE);
+ media_q_pub_map_aaf_audio_info_t *pPubMapInfo = pMediaQ->pPubMapInfo;
- if (pMediaQItem) {
- if (pMediaQItem->dataLen > 0) {
+ U32 bytesNeeded = pPubMapInfo->itemFrameSizeBytes * pPubMapInfo->framesPerPacket;
+ if (!openavbMediaQIsAvailableBytes(pMediaQ, pPubMapInfo->itemFrameSizeBytes * pPubMapInfo->framesPerPacket, TRUE)) {
+ AVB_LOG_VERBOSE("Not enough bytes are ready");
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TX_CB_RET_PACKET_NOT_READY;
+ }
+
+ pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
+ if (!pPvtData) {
+ AVB_LOG_ERROR("Private mapping module data not allocated.");
+ openavbMediaQTailUnlock(pMediaQ);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TX_CB_RET_PACKET_NOT_READY;
+ }
+
+ if ((*dataLen - TOTAL_HEADER_SIZE) < pPvtData->payloadSize) {
+ AVB_LOG_ERROR("Not enough room in packet for payload");
+ openavbMediaQTailUnlock(pMediaQ);
+ AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
+ return TX_CB_RET_PACKET_NOT_READY;
+ }
+
+ U32 bytesProcessed = 0;
+ while (bytesProcessed < bytesNeeded) {
+ pMediaQItem = openavbMediaQTailLock(pMediaQ, TRUE);
+ if (pMediaQItem && pMediaQItem->pPubData && pMediaQItem->dataLen > 0) {
U32 tmp32;
U8 *pHdrV0 = pData;
U32 *pHdr = (U32 *)(pData + AVTP_V0_HEADER_SIZE);
U8 *pPayload = pData + TOTAL_HEADER_SIZE;
- media_q_pub_map_aaf_audio_info_t *pPubMapInfo = pMediaQ->pPubMapInfo;
- pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
- if (!pPvtData) {
- AVB_LOG_ERROR("Private mapping module data not allocated.");
- return TX_CB_RET_PACKET_NOT_READY;
- }
- // timestamp set in the interface module, here just validate
- if (openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime)) {
+ // timestamp set in the interface module, here just validate
+ // In sparse mode, the timestamp valid flag should be set every eighth AAF AVPTDU.
+ if (pPvtData->sparseMode == TS_SPARSE_MODE_ENABLED && (pHdrV0[HIDX_AVTP_SEQ_NUM] & 0x07) != 0) {
+ // Skip over this timestamp, as using sparse mode.
+ pHdrV0[HIDX_AVTP_HIDE7_TV1] &= ~0x01;
+ pHdrV0[HIDX_AVTP_HIDE7_TU1] &= ~0x01;
+ *pHdr++ = 0; // Clear the timestamp field
+ }
+ else if (!openavbAvtpTimeTimestampIsValid(pMediaQItem->pAvtpTime)) {
+ // Error getting the timestamp. Clear timestamp valid flag.
+ AVB_LOG_ERROR("Unable to get the timestamp value");
+ pHdrV0[HIDX_AVTP_HIDE7_TV1] &= ~0x01;
+ pHdrV0[HIDX_AVTP_HIDE7_TU1] &= ~0x01;
+ *pHdr++ = 0; // Clear the timestamp field
+ }
+ else {
// Add the max transit time.
openavbAvtpTimeAddUSec(pMediaQItem->pAvtpTime, pPvtData->maxTransitUsec);
@@ -473,11 +523,6 @@ tx_cb_ret_t openavbMapAVTPAudioTxCB(media_q_t *pMediaQ, U8 *pData, U32 *dataLen)
openavbAvtpTimeSetTimestampValid(pMediaQItem->pAvtpTime, FALSE);
}
- else {
- // Clear timestamp valid flag
- pHdrV0[HIDX_AVTP_HIDE7_TV1] &= ~0x01;
- pHdr++; // Move past the timestamp field
- }
// - 4 bytes format info (format, sample rate, channels per frame, bit depth)
tmp32 = pPvtData->aaf_format << 24;
@@ -498,12 +543,6 @@ tx_cb_ret_t openavbMapAVTPAudioTxCB(media_q_t *pMediaQ, U8 *pData, U32 *dataLen)
pHdrV0[HIDX_AVTP_HIDE7_SP] &= ~SP_M0_BIT;
}
- if ((*dataLen - TOTAL_HEADER_SIZE) < pPvtData->payloadSize) {
- AVB_LOG_ERROR("Not enough room in packet for payload");
- AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
- return TX_CB_RET_PACKET_NOT_READY;
- }
-
if ((pMediaQItem->dataLen - pMediaQItem->readIdx) < pPvtData->payloadSize) {
// This should not happen so we will just toss it away.
AVB_LOG_ERROR("Not enough data in media queue item for packet");
@@ -513,6 +552,7 @@ tx_cb_ret_t openavbMapAVTPAudioTxCB(media_q_t *pMediaQ, U8 *pData, U32 *dataLen)
}
memcpy(pPayload, (uint8_t *)pMediaQItem->pPubData + pMediaQItem->readIdx, pPvtData->payloadSize);
+ bytesProcessed += pPvtData->payloadSize;
pMediaQItem->readIdx += pPvtData->payloadSize;
if (pMediaQItem->readIdx >= pMediaQItem->dataLen) {
@@ -523,23 +563,17 @@ tx_cb_ret_t openavbMapAVTPAudioTxCB(media_q_t *pMediaQ, U8 *pData, U32 *dataLen)
// More to read next interval
openavbMediaQTailUnlock(pMediaQ);
}
-
- // Set outbound data length (entire packet length)
- *dataLen = pPvtData->payloadSize + TOTAL_HEADER_SIZE;
-
- AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
- return TX_CB_RET_PACKET_READY;
}
else {
openavbMediaQTailPull(pMediaQ);
- AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
- return TX_CB_RET_PACKET_NOT_READY; // No payload
}
-
}
+ // Set out bound data length (entire packet length)
+ *dataLen = bytesNeeded + TOTAL_HEADER_SIZE;
+
AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
- return TX_CB_RET_PACKET_NOT_READY;
+ return TX_CB_RET_PACKET_READY;
}
// A call to this callback indicates that this mapping module will be
@@ -561,12 +595,16 @@ void openavbMapAVTPAudioRxInitCB(media_q_t *pMediaQ)
// sparse mode enabled so check packing factor
// listener should work correct for packing_factors:
// 1, 2, 4, 8, 16, 24, 32, 40, 48, (+8) ...
- if (pPvtData->packingFactor < 8) {
+ if (pPvtData->packingFactor == 0) {
+ badPckFctrValue = TRUE;
+ }
+ else if (pPvtData->packingFactor < 8) {
// check if power of 2
if ((pPvtData->packingFactor & (pPvtData->packingFactor - 1)) != 0) {
badPckFctrValue = TRUE;
}
- } else {
+ }
+ else {
// check if multiple of 8
if (pPvtData->packingFactor % 8 != 0) {
badPckFctrValue = TRUE;
@@ -595,8 +633,11 @@ bool openavbMapAVTPAudioRxCB(media_q_t *pMediaQ, U8 *pData, U32 dataLen)
return FALSE;
}
+ aaf_sample_format_t incoming_aaf_format;
+ U8 incoming_bit_depth;
int tmp;
bool dataValid = TRUE;
+ bool dataConversionEnabled = FALSE;
U32 timestamp = ntohl(*pHdr++);
U32 format_info = ntohl(*pHdr++);
@@ -606,18 +647,26 @@ bool openavbMapAVTPAudioRxCB(media_q_t *pMediaQ, U8 *pData, U32 dataLen)
bool streamSparseMode = (pHdrV0[HIDX_AVTP_HIDE7_SP] & SP_M0_BIT) ? TRUE : FALSE;
U16 payloadLen = ntohs(*(U16 *)(&pHdrV0[HIDX_STREAM_DATA_LEN16]));
- if (payloadLen > dataLen - TOTAL_HEADER_SIZE) {
+ if (payloadLen > dataLen - TOTAL_HEADER_SIZE) {
if (pPvtData->dataValid)
AVB_LOGF_ERROR("header data len %d > actual data len %d",
payloadLen, dataLen - TOTAL_HEADER_SIZE);
dataValid = FALSE;
}
- if ((tmp = ((format_info >> 24) & 0xFF)) != pPvtData->aaf_format) {
- if (pPvtData->dataValid)
- AVB_LOGF_ERROR("Listener format %d doesn't match received data (%d)",
- pPvtData->aaf_format, tmp);
- dataValid = FALSE;
+ if ((incoming_aaf_format = (aaf_sample_format_t) ((format_info >> 24) & 0xFF)) != pPvtData->aaf_format) {
+ // Check if we can convert the incoming data.
+ if (incoming_aaf_format >= AAF_FORMAT_INT_32 && incoming_aaf_format <= AAF_FORMAT_INT_16 &&
+ pPvtData->aaf_format >= AAF_FORMAT_INT_32 && pPvtData->aaf_format <= AAF_FORMAT_INT_16) {
+ // Integer conversion should be supported.
+ dataConversionEnabled = TRUE;
+ }
+ else {
+ if (pPvtData->dataValid)
+ AVB_LOGF_ERROR("Listener format %d doesn't match received data (%d)",
+ pPvtData->aaf_format, incoming_aaf_format);
+ dataValid = FALSE;
+ }
}
if ((tmp = ((format_info >> 20) & 0x0F)) != pPvtData->aaf_rate) {
if (pPvtData->dataValid)
@@ -631,28 +680,44 @@ bool openavbMapAVTPAudioRxCB(media_q_t *pMediaQ, U8 *pData, U32 dataLen)
pPubMapInfo->audioChannels, tmp);
dataValid = FALSE;
}
- if ((tmp = (format_info & 0xFF)) != pPvtData->aaf_bit_depth) {
+ if ((incoming_bit_depth = (U8) (format_info & 0xFF)) == 0) {
if (pPvtData->dataValid)
- AVB_LOGF_ERROR("Listener bit depth (%d) doesn't match received data (%d)",
- pPvtData->aaf_bit_depth, tmp);
+ AVB_LOGF_ERROR("Listener bit depth (%d) not valid",
+ incoming_bit_depth);
dataValid = FALSE;
}
if ((tmp = ((packet_info >> 16) & 0xFFFF)) != pPvtData->payloadSize) {
- if (pPvtData->dataValid)
- AVB_LOGF_ERROR("Listener payload size (%d) doesn't match received data (%d)",
- pPvtData->payloadSize, tmp);
- dataValid = FALSE;
+ if (!dataConversionEnabled) {
+ if (pPvtData->dataValid)
+ AVB_LOGF_ERROR("Listener payload size (%d) doesn't match received data (%d)",
+ pPvtData->payloadSize, tmp);
+ dataValid = FALSE;
+ }
+ else {
+ int nInSampleLength = 6 - incoming_aaf_format; // Calculate the number of integer bytes per sample received
+ int nOutSampleLength = 6 - pPvtData->aaf_format; // Calculate the number of integer bytes per sample we want
+ if (tmp / nInSampleLength != pPvtData->payloadSize / nOutSampleLength) {
+ if (pPvtData->dataValid)
+ AVB_LOGF_ERROR("Listener payload samples (%d) doesn't match received data samples (%d)",
+ pPvtData->payloadSize / nOutSampleLength, tmp / nInSampleLength);
+ dataValid = FALSE;
+ }
+ }
}
if ((tmp = ((packet_info >> 8) & 0x0F)) != pPvtData->aaf_event_field) {
if (pPvtData->dataValid)
AVB_LOGF_ERROR("Listener event field (%d) doesn't match received data (%d)",
pPvtData->aaf_event_field, tmp);
}
- if (streamSparseMode != listenerSparseMode) {
- if (pPvtData->dataValid)
- AVB_LOGF_ERROR("Listener sparse mode (%d) doesn't match stream sparse mode (%d)",
- listenerSparseMode, streamSparseMode);
- dataValid = FALSE;
+ if (streamSparseMode && !listenerSparseMode) {
+ AVB_LOG_INFO("Listener enabling sparse mode to match incoming stream");
+ pPvtData->sparseMode = TS_SPARSE_MODE_ENABLED;
+ listenerSparseMode = TRUE;
+ }
+ if (!streamSparseMode && listenerSparseMode) {
+ AVB_LOG_INFO("Listener disabling sparse mode to match incoming stream");
+ pPvtData->sparseMode = TS_SPARSE_MODE_DISABLED;
+ listenerSparseMode = FALSE;
}
if (dataValid) {
@@ -689,11 +754,53 @@ bool openavbMapAVTPAudioRxCB(media_q_t *pMediaQ, U8 *pData, U32 dataLen)
}
}
if (dataValid) {
- if (pPubMapInfo->intf_rx_translate_cb) {
- pPubMapInfo->intf_rx_translate_cb(pMediaQ, pPayload, pPvtData->payloadSize);
+ if (!dataConversionEnabled) {
+ // Just use the raw incoming data, and ignore the incoming bit_depth.
+ if (pPubMapInfo->intf_rx_translate_cb) {
+ pPubMapInfo->intf_rx_translate_cb(pMediaQ, pPayload, pPvtData->payloadSize);
+ }
+
+ memcpy((uint8_t *)pMediaQItem->pPubData + pMediaQItem->dataLen, pPayload, pPvtData->payloadSize);
+ }
+ else {
+ static U8 s_audioBuffer[1500];
+ U8 *pInData = pPayload;
+ U8 *pInDataEnd = pPayload + payloadLen;
+ U8 *pOutData = s_audioBuffer;
+ int nInSampleLength = 6 - incoming_aaf_format; // Calculate the number of integer bytes per sample received
+ int nOutSampleLength = 6 - pPvtData->aaf_format; // Calculate the number of integer bytes per sample we want
+ int i;
+ if (nInSampleLength < nOutSampleLength) {
+ // We need to pad the data supplied.
+ while (pInData < pInDataEnd) {
+ for (i = 0; i < nInSampleLength; ++i) {
+ *pOutData++ = *pInData++;
+ }
+ for ( ; i < nOutSampleLength; ++i) {
+ *pOutData++ = 0; // Value specified in Clause 7.3.4.
+ }
+ }
+ }
+ else {
+ // We need to truncate the data supplied.
+ while (pInData < pInDataEnd) {
+ for (i = 0; i < nOutSampleLength; ++i) {
+ *pOutData++ = *pInData++;
+ }
+ pInData += (nInSampleLength - nOutSampleLength);
+ }
+ }
+ if (pOutData - s_audioBuffer != pPvtData->payloadSize) {
+ AVB_LOGF_ERROR("Output not expected size (%d instead of %d)", pOutData - s_audioBuffer, pPvtData->payloadSize);
+ }
+
+ if (pPubMapInfo->intf_rx_translate_cb) {
+ pPubMapInfo->intf_rx_translate_cb(pMediaQ, s_audioBuffer, pPvtData->payloadSize);
+ }
+
+ memcpy((uint8_t *)pMediaQItem->pPubData + pMediaQItem->dataLen, s_audioBuffer, pPvtData->payloadSize);
}
- memcpy((uint8_t *)pMediaQItem->pPubData + pMediaQItem->dataLen, pPayload, pPvtData->payloadSize);
pMediaQItem->dataLen += pPvtData->payloadSize;
}
diff --git a/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio_pub.h b/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio_pub.h
index c7761b80..213f3bb6 100755
--- a/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio_pub.h
+++ b/lib/avtp_pipeline/map_aaf_audio/openavb_map_aaf_audio_pub.h
@@ -1,16 +1,17 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
+
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -21,17 +22,17 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
/*
* HEADER SUMMARY : AVTP Audio Format mapping module public interface
*
- * AAF is defined in IEEE 1722a (still in draft as of Feb 2015).
+ * AAF (AVTP Audio Format) is defined in IEEE 1722-2016 Clause 7.
*
* map_nv_tx_rate must be set in the .ini file.
*/
diff --git a/lib/avtp_pipeline/map_ctrl/openavb_map_ctrl.c b/lib/avtp_pipeline/map_ctrl/openavb_map_ctrl.c
index 34a353e8..8237f29f 100755
--- a/lib/avtp_pipeline/map_ctrl/openavb_map_ctrl.c
+++ b/lib/avtp_pipeline/map_ctrl/openavb_map_ctrl.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/map_ctrl/openavb_map_ctrl_pub.h b/lib/avtp_pipeline/map_ctrl/openavb_map_ctrl_pub.h
index a89429b0..41ae5430 100755
--- a/lib/avtp_pipeline/map_ctrl/openavb_map_ctrl_pub.h
+++ b/lib/avtp_pipeline/map_ctrl/openavb_map_ctrl_pub.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/map_h264/openavb_map_h264.c b/lib/avtp_pipeline/map_h264/openavb_map_h264.c
index 6898a5ad..5fd114ac 100755
--- a/lib/avtp_pipeline/map_h264/openavb_map_h264.c
+++ b/lib/avtp_pipeline/map_h264/openavb_map_h264.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/map_h264/openavb_map_h264_pub.h b/lib/avtp_pipeline/map_h264/openavb_map_h264_pub.h
index c685d967..307b4ba1 100755
--- a/lib/avtp_pipeline/map_h264/openavb_map_h264_pub.h
+++ b/lib/avtp_pipeline/map_h264/openavb_map_h264_pub.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/map_mjpeg/openavb_map_mjpeg.c b/lib/avtp_pipeline/map_mjpeg/openavb_map_mjpeg.c
index a348439a..4f53904f 100755
--- a/lib/avtp_pipeline/map_mjpeg/openavb_map_mjpeg.c
+++ b/lib/avtp_pipeline/map_mjpeg/openavb_map_mjpeg.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/map_mjpeg/openavb_map_mjpeg_pub.h b/lib/avtp_pipeline/map_mjpeg/openavb_map_mjpeg_pub.h
index 41cf34f0..fc5aaded 100755
--- a/lib/avtp_pipeline/map_mjpeg/openavb_map_mjpeg_pub.h
+++ b/lib/avtp_pipeline/map_mjpeg/openavb_map_mjpeg_pub.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/map_mpeg2ts/demo_listener.ini b/lib/avtp_pipeline/map_mpeg2ts/demo_listener.ini
index f48dbba4..7a30e9b1 100644
--- a/lib/avtp_pipeline/map_mpeg2ts/demo_listener.ini
+++ b/lib/avtp_pipeline/map_mpeg2ts/demo_listener.ini
@@ -5,6 +5,12 @@
# talker or listener
role = listener
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
stream_addr = 00:25:64:48:ca:a8
diff --git a/lib/avtp_pipeline/map_mpeg2ts/demo_talker.ini b/lib/avtp_pipeline/map_mpeg2ts/demo_talker.ini
index 77e6d698..a805e1b6 100644
--- a/lib/avtp_pipeline/map_mpeg2ts/demo_talker.ini
+++ b/lib/avtp_pipeline/map_mpeg2ts/demo_talker.ini
@@ -5,6 +5,12 @@
# talker or listener
role = talker
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
#stream_addr = 00:25:64:48:ca:a8
diff --git a/lib/avtp_pipeline/map_mpeg2ts/openavb_map_mpeg2ts.c b/lib/avtp_pipeline/map_mpeg2ts/openavb_map_mpeg2ts.c
index 8b12bdb3..ba039b99 100755
--- a/lib/avtp_pipeline/map_mpeg2ts/openavb_map_mpeg2ts.c
+++ b/lib/avtp_pipeline/map_mpeg2ts/openavb_map_mpeg2ts.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/map_mpeg2ts/openavb_map_mpeg2ts_pub.h b/lib/avtp_pipeline/map_mpeg2ts/openavb_map_mpeg2ts_pub.h
index 7f4257dd..b54e998c 100755
--- a/lib/avtp_pipeline/map_mpeg2ts/openavb_map_mpeg2ts_pub.h
+++ b/lib/avtp_pipeline/map_mpeg2ts/openavb_map_mpeg2ts_pub.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/map_mpeg2ts/ts_packet_size.c b/lib/avtp_pipeline/map_mpeg2ts/ts_packet_size.c
index a9b30998..cca41d3a 100644
--- a/lib/avtp_pipeline/map_mpeg2ts/ts_packet_size.c
+++ b/lib/avtp_pipeline/map_mpeg2ts/ts_packet_size.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/map_null/openavb_map_null.c b/lib/avtp_pipeline/map_null/openavb_map_null.c
index 7dd24556..5efb4359 100755
--- a/lib/avtp_pipeline/map_null/openavb_map_null.c
+++ b/lib/avtp_pipeline/map_null/openavb_map_null.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/map_null/openavb_map_null_pub.h b/lib/avtp_pipeline/map_null/openavb_map_null_pub.h
index 7fb086c6..4c5da720 100755
--- a/lib/avtp_pipeline/map_null/openavb_map_null_pub.h
+++ b/lib/avtp_pipeline/map_null/openavb_map_null_pub.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/map_pipe/openavb_map_pipe.c b/lib/avtp_pipeline/map_pipe/openavb_map_pipe.c
index 016bb8d4..d65eb38a 100755
--- a/lib/avtp_pipeline/map_pipe/openavb_map_pipe.c
+++ b/lib/avtp_pipeline/map_pipe/openavb_map_pipe.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -182,7 +183,7 @@ void openavbMapPipeCfgCB(media_q_t *pMediaQ, const char *name, const char *value
char *pEnd;
pPvtData->maxPayloadSize = strtol(value, &pEnd, 10);
pPvtData->maxDataSize = (pPvtData->maxPayloadSize + TOTAL_HEADER_SIZE);
- pPvtData->itemSize = pPvtData->maxDataSize;
+ pPvtData->itemSize = pPvtData->maxPayloadSize;
}
else if (strcmp(name, "map_nv_push_header") == 0) {
char *pEnd;
diff --git a/lib/avtp_pipeline/map_pipe/openavb_map_pipe_pub.h b/lib/avtp_pipeline/map_pipe/openavb_map_pipe_pub.h
index 66e5f338..082f79bf 100755
--- a/lib/avtp_pipeline/map_pipe/openavb_map_pipe_pub.h
+++ b/lib/avtp_pipeline/map_pipe/openavb_map_pipe_pub.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/map_uncmp_audio/openavb_map_uncmp_audio.c b/lib/avtp_pipeline/map_uncmp_audio/openavb_map_uncmp_audio.c
index 7c3ff8aa..ca342b2b 100755
--- a/lib/avtp_pipeline/map_uncmp_audio/openavb_map_uncmp_audio.c
+++ b/lib/avtp_pipeline/map_uncmp_audio/openavb_map_uncmp_audio.c
@@ -1,16 +1,17 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
+
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -21,10 +22,10 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -38,10 +39,6 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_trace_pub.h"
#include "openavb_avtp_time_pub.h"
#include "openavb_mediaq_pub.h"
-
-// TODO_OPENAVB : Is this needed?
-//#include "openavb_avdecc_pub.h"
-
#include "openavb_map_pub.h"
#include "openavb_map_uncmp_audio_pub.h"
@@ -204,7 +201,7 @@ static void x_calculateSizes(media_q_t *pMediaQ)
break;
default:
- AVB_LOG_ERROR("Invalid audio frequency configured.");
+ AVB_LOGF_ERROR("Invalid audio frequency configured: %u", pPubMapInfo->audioRate);
pPvtData->cip_sfc = 2;
pPubMapInfo->sytInterval = 8;
break;
@@ -224,16 +221,13 @@ static void x_calculateSizes(media_q_t *pMediaQ)
if (pPubMapInfo->packingFactor > 1) {
// Packing multiple packets of sampling into a media queue item
pPubMapInfo->framesPerItem = pPubMapInfo->framesPerPacket * pPvtData->packingFactor;
- if (pPubMapInfo->framesPerItem < 1) {
- pPubMapInfo->framesPerItem = 1;
- }
}
else {
// No packing. SYT_INTERVAL is used for media queue item size.
pPubMapInfo->framesPerItem = pPubMapInfo->sytInterval;
- if (pPubMapInfo->framesPerItem < 1) {
- pPubMapInfo->framesPerItem = 1;
- }
+ }
+ if (pPubMapInfo->framesPerItem < 1) {
+ pPubMapInfo->framesPerItem = 1;
}
pPubMapInfo->packetSampleSizeBytes = 4;
@@ -281,7 +275,7 @@ static void x_calculateSizes(media_q_t *pMediaQ)
break;
default:
- AVB_LOG_ERROR("Invalid audio format configured.");
+ AVB_LOGF_ERROR("Invalid audio bit depth configured: %u", pPubMapInfo->audioBitDepth);
pPvtData->AM824_label = 0x40000000;
break;
}
@@ -474,14 +468,15 @@ tx_cb_ret_t openavbMapUncmpAudioTxCB(media_q_t *pMediaQ, U8 *pData, U32 *dataLen
U32 framesProcessed = 0;
U8 *pAVTPDataUnit = pPayload;
bool timestampSet = FALSE; // index of the timestamp
+ U32 sytInt = pPubMapInfo->sytInterval;
+ U8 dbc = pPvtData->DBC;
while (framesProcessed < pPubMapInfo->framesPerPacket) {
pMediaQItem = openavbMediaQTailLock(pMediaQ, TRUE);
+ if (pMediaQItem && pMediaQItem->pPubData && pMediaQItem->dataLen > 0) {
+ U8 *pItemData = (U8 *)pMediaQItem->pPubData + pMediaQItem->readIdx;
- if (pMediaQItem && pMediaQItem->dataLen > 0) {
if (pMediaQItem->readIdx == 0) {
- // Timestamp from the media queue is always assoicated with the first data point.
-
- // Update time stamp
+ // Timestamp from the media queue is always associated with the first data point.
// PTP walltime already set in the interface module. Just add the max transit time.
openavbAvtpTimeAddUSec(pMediaQItem->pAvtpTime, pPvtData->maxTransitUsec);
@@ -496,14 +491,11 @@ tx_cb_ret_t openavbMapUncmpAudioTxCB(media_q_t *pMediaQ, U8 *pData, U32 *dataLen
// Set timestamp uncertain flag
if (openavbAvtpTimeTimestampIsUncertain(pMediaQItem->pAvtpTime))
pHdr[HIDX_AVTP_HIDE7_TU1] |= 0x01; // Set
- else pHdr[HIDX_AVTP_HIDE7_TU1] &= ~0x01; // Clear
+ else
+ pHdr[HIDX_AVTP_HIDE7_TU1] &= ~0x01; // Clear
- *(U32 *)(&pHdr[HIDX_AVTP_TIMESTAMP32]) = htonl(openavbAvtpTimeGetAvtpTimestamp(pMediaQItem->pAvtpTime));
-
- timestampSet = TRUE;
}
- U8 *pItemData = (U8 *)pMediaQItem->pPubData + pMediaQItem->readIdx;
while (framesProcessed < pPubMapInfo->framesPerPacket && pMediaQItem->readIdx < pMediaQItem->dataLen) {
int i1;
for (i1 = 0; i1 < pPubMapInfo->audioChannels; i1++) {
@@ -528,6 +520,12 @@ tx_cb_ret_t openavbMapUncmpAudioTxCB(media_q_t *pMediaQ, U8 *pData, U32 *dataLen
}
}
framesProcessed++;
+ if (dbc % sytInt == 0) {
+ *(U32 *)(&pHdr[HIDX_AVTP_TIMESTAMP32]) = htonl(openavbAvtpTimeGetAvtpTimestamp(pMediaQItem->pAvtpTime));
+
+ timestampSet = TRUE;
+ }
+ dbc++;
pMediaQItem->readIdx += pPubMapInfo->itemFrameSizeBytes;
}
@@ -548,12 +546,12 @@ tx_cb_ret_t openavbMapUncmpAudioTxCB(media_q_t *pMediaQ, U8 *pData, U32 *dataLen
// Check if timestamp was set
if (!timestampSet) {
// Timestamp wasn't set so mark it as invalid
- pHdr[HIDX_AVTP_HIDE7_TV1] &= ~0x01;
+ pHdr[HIDX_AVTP_HIDE7_TV1] &= ~0x01;
}
// Set the block continutity and data length
pHdr[HIDX_DBC8] = pPvtData->DBC;
- pPvtData->DBC += pPubMapInfo->framesPerPacket;
+ pPvtData->DBC = dbc;
*(U16 *)(&pHdr[HIDX_DATALEN16]) = htons((pPubMapInfo->framesPerPacket * pPubMapInfo->packetFrameSizeBytes) + CIP_HEADER_SIZE);
@@ -631,7 +629,7 @@ bool openavbMapUncmpAudioRxCB(media_q_t *pMediaQ, U8 *pData, U32 dataLen)
if (pMediaQItem->dataLen == 0) {
// This is the first set of frames for the media queue item, must align based on SYT_INTERVAL for proper synchronization of listeners
if (dbcIdx > 0) {
- // Failed to make alignment with this packet. This AVTP packet will be tossed. Once alignment is reached
+ // Failed to make alignment with this packet. This AVTP packet will be tossed. Once alignment is reached
// it is expected not to need to toss packets anymore.
openavbMediaQHeadUnlock(pMediaQ);
AVB_TRACE_EXIT(AVB_TRACE_MAP_DETAIL);
@@ -726,7 +724,6 @@ extern DLL_EXPORT bool openavbMapUncmpAudioInitialize(media_q_t *pMediaQ, openav
}
pvt_data_t *pPvtData = pMediaQ->pPvtMapInfo;
- media_q_pub_map_uncmp_audio_info_t *pPubMapInfo = pMediaQ->pPubMapInfo;
pMapCB->map_cfg_cb = openavbMapUncmpAudioCfgCB;
pMapCB->map_subtype_cb = openavbMapUncmpAudioSubtypeCB;
@@ -734,7 +731,6 @@ extern DLL_EXPORT bool openavbMapUncmpAudioInitialize(media_q_t *pMediaQ, openav
pMapCB->map_max_data_size_cb = openavbMapUncmpAudioMaxDataSizeCB;
pMapCB->map_transmit_interval_cb = openavbMapUncmpAudioTransmitIntervalCB;
pMapCB->map_gen_init_cb = openavbMapUncmpAudioGenInitCB;
- pMapCB->map_avdecc_init_cb = openavbMapUncmpAudioAVDECCInitCB;
pMapCB->map_tx_init_cb = openavbMapUncmpAudioTxInitCB;
pMapCB->map_tx_cb = openavbMapUncmpAudioTxCB;
pMapCB->map_rx_init_cb = openavbMapUncmpAudioRxInitCB;
@@ -749,8 +745,6 @@ extern DLL_EXPORT bool openavbMapUncmpAudioInitialize(media_q_t *pMediaQ, openav
pPvtData->DBC = 0;
pPvtData->audioMcr = AVB_MCR_NONE;
- pPubMapInfo->sparseMode = TS_SPARSE_MODE_UNSPEC;
-
openavbMediaQSetMaxLatency(pMediaQ, inMaxTransitUsec);
}
diff --git a/lib/avtp_pipeline/map_uncmp_audio/openavb_map_uncmp_audio_pub.h b/lib/avtp_pipeline/map_uncmp_audio/openavb_map_uncmp_audio_pub.h
index 7a324d46..aab1f973 100755
--- a/lib/avtp_pipeline/map_uncmp_audio/openavb_map_uncmp_audio_pub.h
+++ b/lib/avtp_pipeline/map_uncmp_audio/openavb_map_uncmp_audio_pub.h
@@ -1,16 +1,17 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
+
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -21,20 +22,20 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
/*
* HEADER SUMMARY : Uncompressed Audio mapping module public interface
-*
+*
* Refer to IEC 61883-6 for details of the "source packet" structure.
-*
+*
* The protocol_specific_header and CIP header.
-*
+*
* map_nv_tx_rate must be set in the .ini file.
*/
@@ -59,19 +60,6 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*/
#define MapUncmpAudioMediaQDataFormat "UncmpAudio"
-/** Defines AAF timestamping mode:
- * - TS_SPARSE_MODE_DISABLED - timestamp is valid in every avtp packet
- * - TS_SPARSE_MODE_ENABLED - timestamp is valid in every 8th avtp packet
- */
-typedef enum {
- /// Unspecified
- TS_SPARSE_MODE_UNSPEC = 0,
- /// Disabled
- TS_SPARSE_MODE_DISABLED = 1,
- /// Enabled
- TS_SPARSE_MODE_ENABLED = 8
-} avb_audio_sparse_mode_t;
-
/** Contains detailed information of the audio format.
* \note Interface module has to set during the RX and TX init callbacks:
* - audioRate,
@@ -79,7 +67,6 @@ typedef enum {
* - audioBitDepth,
* - audioEndian,
* - audioChannels,
- * - sparseMode.
* \note The rest of fields mapping module will set these during the RX and TX
* init callbacks. The interface module can use these during the RX and TX
* callbacks.
@@ -95,8 +82,6 @@ typedef struct {
avb_audio_endian_t audioEndian;
/// Number of channels
avb_audio_channels_t audioChannels;
- /// Sparse timestamping mode
- avb_audio_sparse_mode_t sparseMode;
// The mapping module will set these during the RX and TX init callbacks
// The interface module can use these during the RX and TX callbacks.
@@ -121,12 +106,12 @@ typedef struct {
/// synchronization time interval
U32 sytInterval;
- /// CB for interface modules to do translations in place before data is moved into the mediaQ on rx.
+ /// CB for interface modules to do translations in place before data is moved into the mediaQ on rx.
openavb_intf_rx_translate_cb_t intf_rx_translate_cb;
/// Interface Module may set this presentation latency which listener mapping modules will use to adjust the presetnation time
S32 presentationLatencyUSec;
-
+
} media_q_pub_map_uncmp_audio_info_t;
#endif // OPENAVB_MAP_UNCMP_AUDIO_PUB_H
diff --git a/lib/avtp_pipeline/map_uncmp_audio/uncmp_audio_map.md b/lib/avtp_pipeline/map_uncmp_audio/uncmp_audio_map.md
index f826249c..862241b6 100644
--- a/lib/avtp_pipeline/map_uncmp_audio/uncmp_audio_map.md
+++ b/lib/avtp_pipeline/map_uncmp_audio/uncmp_audio_map.md
@@ -41,8 +41,6 @@ audioType |How the data is organized - what is the data type of \
samples @ref avb_audio_type_t
audioBitDepth |What is the bit depth of audio @ref avb_audio_bit_depth_t
audioChannels |How many channels there are @ref avb_audio_channels_t
-sparseMode |Timestamping mode @ref avb_audio_sparse_mode_t \
- (not used in this mapping module)
Below you can find description of how to set up those variables in interfaces
* [wav file interface](@ref wav_file_intf)
diff --git a/lib/avtp_pipeline/mcr/CMakeLists.txt b/lib/avtp_pipeline/mcr/CMakeLists.txt
index 3e3b4110..cffff7f9 100644
--- a/lib/avtp_pipeline/mcr/CMakeLists.txt
+++ b/lib/avtp_pipeline/mcr/CMakeLists.txt
@@ -1 +1,4 @@
-# No common code
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_HAL_DIR}/mcr/openavb_mcr_hal.c
+ PARENT_SCOPE
+)
diff --git a/lib/avtp_pipeline/mcr/openavb_mcr_hal_pub.h b/lib/avtp_pipeline/mcr/openavb_mcr_hal_pub.h
index ac2eca21..d474d084 100644
--- a/lib/avtp_pipeline/mcr/openavb_mcr_hal_pub.h
+++ b/lib/avtp_pipeline/mcr/openavb_mcr_hal_pub.h
@@ -1,65 +1,66 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-/*
-* MODULE : Public interface for media clock recovery
-*/
-
-#ifndef OPENAVB_MCR_HAL_PUB_H
-#define OPENAVB_MCR_HAL_PUB_H
-
-#include "openavb_platform_pub.h"
-#include "openavb_types_base_pub.h"
-
-#define HAL_INIT_MCR_V2(packetRate, pushInterval, timestampInterval, recoveryInterval) halInitMCR(packetRate, pushInterval, timestampInterval, recoveryInterval)
-#define HAL_CLOSE_MCR_V2() halCloseMCR()
-#define HAL_PUSH_MCR_V2() halPushMCR()
-
-// Initialize HAL MCR
-bool halInitMCR(U32 packetRate, U32 pushInterval, U32 timeStampInterval, U32 recoveryInterval);
-
-// Close HAL MCR
-bool halCloseMCR(void);
-
-// Push MCR Event
-bool halPushMCR(void);
-
-// MCR timer adjustment. Negative value speed up the media clock. Positive values slow the media clock.
-// Will take effect during the next clock recovery interval. This is completely indepentant from pure MCR and
-// allows for adjustments based on media buffer levels. The value past in works as credit with each
-// MCR timer cycle bump up and down the clock temporarily.
-void halAdjustMCRNSec(S32 adjNSec);
-
-// The granularity is used to set coarseness of the values that will be passed into halAdjustMCRNSec.
-// This is used to balance if the timestamps or values from halAdjustMCRNSec are used to adjust the clock.
-void halAdjustMCRGranularityNSec(U32 adjGranularityNSec);
-
-
-#endif // OPENAVB_MCR_HAL_PUB_H
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+* MODULE : Public interface for media clock recovery
+*/
+
+#ifndef OPENAVB_MCR_HAL_PUB_H
+#define OPENAVB_MCR_HAL_PUB_H
+
+#include "openavb_platform_pub.h"
+#include "openavb_types_base_pub.h"
+
+#define HAL_INIT_MCR_V2(packetRate, pushInterval, timestampInterval, recoveryInterval) halInitMCR(packetRate, pushInterval, timestampInterval, recoveryInterval)
+#define HAL_CLOSE_MCR_V2() halCloseMCR()
+#define HAL_PUSH_MCR_V2() halPushMCR()
+
+// Initialize HAL MCR
+bool halInitMCR(U32 packetRate, U32 pushInterval, U32 timeStampInterval, U32 recoveryInterval);
+
+// Close HAL MCR
+bool halCloseMCR(void);
+
+// Push MCR Event
+bool halPushMCR(void);
+
+// MCR timer adjustment. Negative value speed up the media clock. Positive values slow the media clock.
+// Will take effect during the next clock recovery interval. This is completely indepentant from pure MCR and
+// allows for adjustments based on media buffer levels. The value past in works as credit with each
+// MCR timer cycle bump up and down the clock temporarily.
+void halAdjustMCRNSec(S32 adjNSec);
+
+// The granularity is used to set coarseness of the values that will be passed into halAdjustMCRNSec.
+// This is used to balance if the timestamps or values from halAdjustMCRNSec are used to adjust the clock.
+void halAdjustMCRGranularityNSec(U32 adjGranularityNSec);
+
+
+#endif // OPENAVB_MCR_HAL_PUB_H
diff --git a/lib/avtp_pipeline/mcs/CMakeLists.txt b/lib/avtp_pipeline/mcs/CMakeLists.txt
new file mode 100644
index 00000000..0f942140
--- /dev/null
+++ b/lib/avtp_pipeline/mcs/CMakeLists.txt
@@ -0,0 +1,5 @@
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/mcs/openavb_mcs.c
+ PARENT_SCOPE
+)
+
diff --git a/lib/avtp_pipeline/mcs/openavb_mcs.c b/lib/avtp_pipeline/mcs/openavb_mcs.c
new file mode 100644
index 00000000..51d7fe9a
--- /dev/null
+++ b/lib/avtp_pipeline/mcs/openavb_mcs.c
@@ -0,0 +1,77 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+* MODULE SUMMARY : Media clock timestamp synthesis for stored or generated media
+*/
+
+#include "openavb_platform_pub.h"
+#include "openavb_types_pub.h"
+#include "openavb_log_pub.h"
+#include "openavb_mcs.h"
+
+void openavbMcsInit(mcs_t *mediaClockSynth, U64 nsPerAdvance, S32 correctionAmount, U32 correctionInterval)
+{
+ mediaClockSynth->firstTimeSet = FALSE;
+ mediaClockSynth->nsPerAdvance = nsPerAdvance;
+ mediaClockSynth->correctionAmount = correctionAmount;
+ mediaClockSynth->correctionInterval = correctionInterval;
+ mediaClockSynth->startTime = 0;
+ mediaClockSynth->tickCount = 0;
+ mediaClockSynth->edgeTime = 0;
+}
+
+void openavbMcsAdvance(mcs_t *mediaClockSynth)
+{
+ if (mediaClockSynth->firstTimeSet == FALSE) {
+ CLOCK_GETTIME64(OPENAVB_CLOCK_WALLTIME, &mediaClockSynth->edgeTime);
+ if (mediaClockSynth->edgeTime) {
+ mediaClockSynth->firstTimeSet = TRUE;
+ mediaClockSynth->startTime = mediaClockSynth->edgeTime;
+ }
+ }
+ else
+ {
+ mediaClockSynth->edgeTime += mediaClockSynth->nsPerAdvance;
+ mediaClockSynth->tickCount++;
+ if (mediaClockSynth->tickCount % mediaClockSynth->correctionInterval == 0) {
+ mediaClockSynth->edgeTime += mediaClockSynth->correctionAmount;
+ }
+#if !IGB_LAUNCHTIME_ENABLED
+ IF_LOG_INTERVAL(8000) {
+ U64 nowNS;
+ CLOCK_GETTIME64(OPENAVB_CLOCK_WALLTIME, &nowNS);
+ S64 fixedRealDelta = mediaClockSynth->edgeTime - nowNS;
+ AVB_LOGF_INFO("Fixed/Real TS Delta: %lld", fixedRealDelta);
+ }
+#endif
+ }
+}
diff --git a/lib/avtp_pipeline/mcs/openavb_mcs.h b/lib/avtp_pipeline/mcs/openavb_mcs.h
new file mode 100644
index 00000000..1ae8f7de
--- /dev/null
+++ b/lib/avtp_pipeline/mcs/openavb_mcs.h
@@ -0,0 +1,52 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+* MODULE SUMMARY : Media clock timestamp synthesis for stored or generated media
+*/
+
+#ifndef OPENAVB_MCS_H
+#define OPENAVB_MCS_H
+
+typedef struct {
+ bool firstTimeSet;
+ U64 nsPerAdvance;
+ U64 startTime;
+ U64 tickCount;
+ S32 correctionAmount;
+ U32 correctionInterval;
+ U64 edgeTime;
+} mcs_t;
+
+void openavbMcsInit(mcs_t *mediaClockSynth, U64 nsPerAdvance, S32 correctionAmount, U32 correctionInterval);
+void openavbMcsAdvance(mcs_t *mediaClockSynth);
+
+#endif
diff --git a/lib/avtp_pipeline/mediaq/openavb_mediaq.c b/lib/avtp_pipeline/mediaq/openavb_mediaq.c
index 463b15c2..eda2c68d 100644
--- a/lib/avtp_pipeline/mediaq/openavb_mediaq.c
+++ b/lib/avtp_pipeline/mediaq/openavb_mediaq.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -40,8 +41,6 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_mediaq.h"
#include "openavb_avtp_time_pub.h"
-#include "openavb_printbuf.h"
-
#define AVB_LOG_COMPONENT "Media Queue"
#include "openavb_log.h"
@@ -49,10 +48,6 @@ static MUTEX_HANDLE(gMediaQMutex);
#define MEDIAQ_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(gMediaQMutex); MUTEX_LOG_ERR("Mutex Lock failure"); }
#define MEDIAQ_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(gMediaQMutex); MUTEX_LOG_ERR("Mutex Unlock failure"); }
-// CORE_TODO : Currently this first future logic for purge the media queue and incoming items
-// may be too aggressive and can result in never catching up. Therefore it is disabled for now
-//#define ENABLE_FIRST_FUTURE 1
-
//#define DUMP_HEAD_PUSH 1
//#define DUMP_TAIL_PULL 1
@@ -85,9 +80,6 @@ typedef struct {
// True is next item to be pulled is locked
bool tailLocked;
- // set if timestamp is ever in the future
- bool firstFuture;
-
// Maximum latency
U32 maxLatencyUsec;
@@ -167,18 +159,6 @@ void x_openavbMediaQPurgeStaleTail(media_q_t *pMediaQ)
{
AVB_TRACE_ENTRY(AVB_TRACE_MEDIAQ_DETAIL);
-#if 0 // debug
- // Debug code to report delta from TS
- static bool init = TRUE;
- static U32 cnt = 0;
- static openavb_printbuf_t printBuf;
- if (init) {
- printBuf = openavbPrintbufNew(2000, 20);
- init = FALSE;
- }
-#endif
-
-
if (pMediaQ) {
if (pMediaQ->pPvtMediaQInfo) {
media_q_info_t *pMediaQInfo = (media_q_info_t *)(pMediaQ->pPvtMediaQInfo);
@@ -196,14 +176,12 @@ void x_openavbMediaQPurgeStaleTail(media_q_t *pMediaQ)
pMediaQInfo->tailLocked = TRUE;
bool bPurge = FALSE;
-#ifdef ENABLE_FIRST_FUTURE
if (bFirst) {
S32 delta = openavbAvtpTimeUsecDelta(pTail->pAvtpTime);
S32 maxStale = (S32)(0 - pMediaQInfo->maxStaleTailUsec);
if (delta < maxStale) {
- IF_LOG_INTERVAL(100) AVB_LOGF_INFO("Purging stale MediaQ items: delta:%dus maxStale%dus", delta, maxStale);
-
+ AVB_LOGF_DEBUG("Purging stale MediaQ items: delta %d us, maxStale %d us", delta, maxStale);
bPurge = TRUE;
}
bFirst = FALSE;
@@ -211,6 +189,7 @@ void x_openavbMediaQPurgeStaleTail(media_q_t *pMediaQ)
else {
// Once we have triggered a stale tail purge everything past presentation time.
if (openavbAvtpTimeIsPast(pTail->pAvtpTime)) {
+ AVB_LOG_DEBUG("Purging stale MediaQ items");
bPurge = TRUE;
}
}
@@ -224,46 +203,6 @@ void x_openavbMediaQPurgeStaleTail(media_q_t *pMediaQ)
pMediaQInfo->tailLocked = FALSE;
pTail = NULL;
}
-#else // ENABLE_FIRST_FUTURE
- if (bFirst) {
- S32 delta = openavbAvtpTimeUsecDelta(pTail->pAvtpTime);
- S32 maxStale = (S32)(0 - pMediaQInfo->maxStaleTailUsec);
- if(delta >= 0) {
- pMediaQInfo->firstFuture = TRUE;
- }
- else if (delta < maxStale) {
- bPurge = TRUE;
- pMediaQInfo->firstFuture = FALSE;
- }
-
- bFirst = FALSE;
- }
- else {
- // Once we have triggered a stale tail purge everything past presentation time.
- if (openavbAvtpTimeIsPast(pTail->pAvtpTime)) {
-#if 0 // debug
- if (!(++cnt % 1)) {
- openavbPrintbufPrintf(printBuf, "Purge More\n");
- }
-#endif
- bPurge = TRUE;
- }
- else {
- pMediaQInfo->firstFuture = TRUE;
- }
- }
-
- if (bPurge || (pMediaQInfo->firstFuture == FALSE)) {
- openavbMediaQTailPull(pMediaQ);
- pTail = NULL;
- bMore = TRUE;
- }
- else {
- pMediaQInfo->tailLocked = FALSE;
- pTail = NULL;
- }
-#endif // ENABLE_FIRST_FUTURE
-
}
}
}
@@ -292,7 +231,6 @@ media_q_t* openavbMediaQCreate()
pMediaQInfo->headLocked = FALSE;
pMediaQInfo->tail = -1;
pMediaQInfo->tailLocked = FALSE;
- pMediaQInfo->firstFuture = TRUE;
pMediaQInfo->maxLatencyUsec = 0;
pMediaQInfo->threadSafeOn = FALSE;
pMediaQInfo->maxStaleTailUsec = MICROSECONDS_PER_SECOND;
@@ -347,7 +285,7 @@ bool openavbMediaQSetSize(media_q_t *pMediaQ, int itemCount, int itemSize)
int i1;
for (i1 = 0; i1 < itemCount; i1++) {
pMediaQInfo->pItems[i1].pAvtpTime = openavbAvtpTimeCreate(pMediaQInfo->maxLatencyUsec);
- pMediaQInfo->pItems[i1].pPubData = calloc(1, itemSize);
+ pMediaQInfo->pItems[i1].pPubData = calloc(1, itemSize + 4 /* Just in case */);
pMediaQInfo->pItems[i1].dataLen = 0;
pMediaQInfo->pItems[i1].itemSize = itemSize;
if (!pMediaQInfo->pItems[i1].pPubData) {
@@ -399,7 +337,7 @@ bool openavbMediaQAllocItemMapData(media_q_t *pMediaQ, int itemPubMapSize, int i
}
}
else {
- AVB_LOG_ERROR("Attemping to reallocate public map data");
+ AVB_LOG_ERROR("Attempting to reallocate public map data");
AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ);
return FALSE;
}
@@ -413,7 +351,7 @@ bool openavbMediaQAllocItemMapData(media_q_t *pMediaQ, int itemPubMapSize, int i
}
}
else {
- AVB_LOG_ERROR("Attemping to reallocate private map data");
+ AVB_LOG_ERROR("Attempting to reallocate private map data");
AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ);
return FALSE;
}
@@ -449,7 +387,7 @@ bool openavbMediaQAllocItemIntfData(media_q_t *pMediaQ, int itemIntfSize)
}
}
else {
- AVB_LOG_ERROR("Attemping to reallocate private interface data");
+ AVB_LOG_ERROR("Attempting to reallocate private interface data");
AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ);
return FALSE;
}
@@ -699,13 +637,14 @@ media_q_item_t* openavbMediaQTailLock(media_q_t *pMediaQ, bool ignoreTimestamp)
if (pMediaQInfo->threadSafeOn) {
MEDIAQ_UNLOCK();
}
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
return NULL;
}
}
pMediaQInfo->tailLocked = TRUE;
- AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
// Mutex (LOCK()) if acquired stays locked
+ AVB_TRACE_EXIT(AVB_TRACE_MEDIAQ_DETAIL);
return pTail;
}
}
diff --git a/lib/avtp_pipeline/mediaq/openavb_mediaq.h b/lib/avtp_pipeline/mediaq/openavb_mediaq.h
index 4a2c031c..ec69a84a 100644
--- a/lib/avtp_pipeline/mediaq/openavb_mediaq.h
+++ b/lib/avtp_pipeline/mediaq/openavb_mediaq.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/mediaq/openavb_mediaq_pub.h b/lib/avtp_pipeline/mediaq/openavb_mediaq_pub.h
index 4e479f9d..16d8c0ac 100644
--- a/lib/avtp_pipeline/mediaq/openavb_mediaq_pub.h
+++ b/lib/avtp_pipeline/mediaq/openavb_mediaq_pub.h
@@ -1,16 +1,17 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
+
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -21,10 +22,10 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -73,7 +74,7 @@ typedef struct {
void *pPubMapData;
/// For use internally by mapping modules. Often may not be used.
- void *pPvtMapData;
+ void *pPvtMapData;
/// For use internally by the interface. Often may not be used.
void *pPvtIntfData;
@@ -125,7 +126,7 @@ media_q_t* openavbMediaQCreate();
/** Enable thread safe access for this media queue.
*
* In the default case a media queue is only accessed from a single thread and
- * therefore multi-threaded synchronication isn't needed. In situations where a
+ * therefore multi-threaded synchronization isn't needed. In situations where a
* media queue can be accessed from multiple threads calling this function will
* enable mutex protection on the head and tail related functions. Once enabled
* for a media queue it can not be disabled.
@@ -238,7 +239,7 @@ media_q_item_t *openavbMediaQHeadLock(media_q_t *pMediaQ);
*
* Unlock a locked media queue item from the head of the queue. The item will
* not become available for use in the queue and the data will not be cleared.
- * Subsequent calls to openavbMediaQHeadLock will return the same item storage
+ * Subsequent calls to openavbMediaQHeadLock will return the same item storage
* with the same data values. An interface module will use this function when
* running as a talker when it must release a previously locked media queue head
* item.
@@ -264,9 +265,9 @@ bool openavbMediaQHeadPush(media_q_t *pMediaQ);
* Lock the next available tail item in the media queue. Available is based on
* the timestamp that is associated with the item when it was a placed into the
* media queue. The interface module running on a listener uses this function
- * to access the data items place into the media queue by the mapping module.
+ * to access the data items placed into the media queue by the mapping module.
* At some point after this function call the item must be unlocked with either
- * openavbMediaQTailUnlockor openavbMediaQTailPull on the same callback or a subsequent
+ * openavbMediaQTailUnlock or openavbMediaQTailPull on the same callback or a subsequent
* callback.
*
* \param pMediaQ A pointer to the media_q_t structure.
@@ -343,7 +344,7 @@ bool openavbMediaQIsAvailableBytes(media_q_t *pMediaQ, U32 bytes, bool ignoreTim
/** Count number of available MediaQ items.
*
- * Count the number of available MediaQ items.
+ * Count the number of available MediaQ items.
*
* \param pMediaQ A pointer to the media_q_t structure.
* \param ignoreTimestamp Ignore timestamp for byte accumulation.
diff --git a/lib/avtp_pipeline/openavb_common/CMakeLists.txt b/lib/avtp_pipeline/openavb_common/CMakeLists.txt
new file mode 100644
index 00000000..e5f7d7f4
--- /dev/null
+++ b/lib/avtp_pipeline/openavb_common/CMakeLists.txt
@@ -0,0 +1,12 @@
+if (AVB_FEATURE_IGB)
+ message("-- common IGB library included")
+ SET (IGB_FILES
+ ${AVB_SRC_DIR}/../common/avb_igb.c
+ )
+endif ()
+SET (SRC_FILES ${SRC_FILES}
+ ${AVB_SRC_DIR}/../common/avb_gptp.c
+ ${AVB_SRC_DIR}/openavb_common/mrp_client.c
+ ${IGB_FILES}
+ PARENT_SCOPE
+)
diff --git a/lib/avtp_pipeline/openavb_common/mrp_client.c b/lib/avtp_pipeline/openavb_common/mrp_client.c
index da1afba8..1a285b5f 100644
--- a/lib/avtp_pipeline/openavb_common/mrp_client.c
+++ b/lib/avtp_pipeline/openavb_common/mrp_client.c
@@ -85,7 +85,6 @@ int send_mrp_msg(char *notify_data, int notify_len)
int process_mrp_msg(char *buf, int buflen)
{
-
/*
* 1st character indicates application
* [MVS] - MAC, VLAN or STREAM
@@ -97,180 +96,63 @@ int process_mrp_msg(char *buf, int buflen)
unsigned int max_interval_frames;
unsigned int priority_and_rank;
unsigned int latency;
- int i, j, k;
+ int i, j;
unsigned int substate;
unsigned char recovered_streamid[8];
unsigned char dest_addr[6];
- k = 0;
- next_line:if (k >= buflen)
- return 0;
- switch (buf[k]) {
- case 'E':
- AVB_LOGF_DEBUG("%s from mrpd", buf);
- mrp_error = 1;
- break;
- case 'O':
- mrp_okay = 1;
- break;
- case 'M':
- case 'V':
- AVB_LOGF_DEBUG("%s unhandled from mrpd", buf);
- /* unhandled for now */
- break;
- case 'L':
-
- /* parse a listener attribute - see if it matches our monitor_stream_id */
- i = k;
- while (buf[i] != 'D')
- i++;
- i += 2; /* skip the ':' */
- sscanf(&(buf[i]), "%d", &substate);
- while (buf[i] != 'S')
- i++;
- i += 2; /* skip the ':' */
- for (j = 0; j < 8; j++) {
- sscanf(&(buf[i + 2 * j]), "%02x", &id);
- recovered_streamid[j] = (unsigned char)id;
- }
- AVB_LOGF_DEBUG
- ("FOUND STREAM ID=%02x%02x%02x%02x%02x%02x%02x%02x ",
- recovered_streamid[0], recovered_streamid[1],
- recovered_streamid[2], recovered_streamid[3],
- recovered_streamid[4], recovered_streamid[5],
- recovered_streamid[6], recovered_streamid[7]);
- switch (substate) {
- case 0:
- AVB_LOG_DEBUG("with state ignore");
- break;
- case 1:
- AVB_LOG_DEBUG("with state askfailed");
- break;
- case 2:
- AVB_LOG_DEBUG("with state ready");
+ int offset = 0;
+
+#if (AVB_LOG_LEVEL_DEBUG <= AVB_LOG_LEVEL)
+ // Display this response in a user-friendly format.
+ static char szMrpData[MAX_MRPD_CMDSZ];
+ int nMrpDataLength = (buflen < MAX_MRPD_CMDSZ - 1 ? buflen : MAX_MRPD_CMDSZ - 1);
+ strncpy(szMrpData, buf, nMrpDataLength);
+ szMrpData[nMrpDataLength] = '\0';
+ while (nMrpDataLength > 0 &&
+ (buf[nMrpDataLength - 1] == '\0' || buf[nMrpDataLength - 1] == '\r' || buf[nMrpDataLength - 1] == '\n')) {
+ // Remove the trailing whitespace.
+ szMrpData[--nMrpDataLength] = '\0';
+ }
+ AVB_LOGF_DEBUG("MRP Response: %s", szMrpData);
+#endif
+
+ while (offset < buflen && buf[offset] != '\0') {
+
+ switch (buf[offset]) {
+ case 'E':
+ mrp_error = 1;
break;
- case 3:
- AVB_LOG_DEBUG("with state readyfail");
+
+ case 'O':
+ mrp_okay = 1;
break;
- default:
- AVB_LOGF_DEBUG("with state UNKNOWN (%d)", substate);
+
+ case 'M':
+ case 'V':
+ /* unhandled for now */
break;
- }
- mrp_attach_cb(recovered_streamid, substate);
- if (substate > MSRP_LISTENER_ASKFAILED) {
- if (memcmp
- (recovered_streamid, monitor_stream_id,
- sizeof(recovered_streamid)) == 0) {
- listeners = 1;
- AVB_LOG_DEBUG("added listener");
- }
- }
- /* try to find a newline ... */
- while ((i < buflen) && (buf[i] != '\n') && (buf[i] != '\0'))
- i++;
- if (i == buflen)
- return 0;
- if (buf[i] == '\0')
- return 0;
- i++;
- k = i;
- goto next_line;
- break;
- case 'D':
- i = k + 4;
-
- /* save the domain attribute */
- sscanf(&(buf[i]), "%d", &id);
- while (buf[i] != 'P')
- i++;
- i += 2; /* skip the ':' */
- sscanf(&(buf[i]), "%d", &priority);
- while (buf[i] != 'V')
- i++;
- i += 2; /* skip the ':' */
- sscanf(&(buf[i]), "%x", &vid);
- if (id == 6) {
- domain_class_a_id = id;
- domain_class_a_priority = priority;
- domain_class_a_vid = vid;
- domain_a_valid = 1;
- } else {
- domain_class_b_id = id;
- domain_class_b_priority = priority;
- domain_class_b_vid = vid;
- domain_b_valid = 1;
- }
- while ((i < buflen) && (buf[i] != '\n') && (buf[i] != '\0'))
- i++;
- if ((i == buflen) || (buf[i] == '\0'))
- return 0;
- i++;
- k = i;
- goto next_line;
- break;
- case 'T':
- i = k;
- while (buf[i] != 'S')
- i++;
- // skip S=
- i += 2;
- for (j = 0; j < 8; j++) {
- sscanf(&(buf[i + 2 * j]), "%02x", &id);
- recovered_streamid[j] = (unsigned char)id;
- }
- while (buf[i] != 'A')
- i++;
- // skip A=
- i += 2;
- for (j = 0; j < 6; j++) {
- sscanf(&(buf[i + 2 * j]), "%02x", &id);
- dest_addr[j] = (unsigned char)id;
- }
- i+= j*2 + 1;
-
- sscanf(&(buf[i]), "V=%d,Z=%d,I=%d,P=%d,L=%d",
- &vid,
- &max_frame_size,
- &max_interval_frames,
- &priority_and_rank,
- &latency);
-
- mrp_register_cb(recovered_streamid, 0, dest_addr, max_frame_size, max_interval_frames, vid, latency);
-
- while ((i < buflen) && (buf[i] != '\n') && (buf[i] != '\0'))
- i++;
-
- if (i == buflen)
- return 0;
- if (buf[i] == '\0')
- return 0;
- i++;
- k = i;
- goto next_line;
- break;
- case 'S':
-
- /* handle the leave/join events */
- switch (buf[k + 4]) {
case 'L':
- i = k + 5;
+
+ /* parse a listener attribute - see if it matches our monitor_stream_id */
+ i = offset;
while (buf[i] != 'D')
i++;
- i += 2; /* skip the ':' */
+ i += 2; /* skip the ':' */
sscanf(&(buf[i]), "%d", &substate);
while (buf[i] != 'S')
i++;
- i += 2; /* skip the ':' */
+ i += 2; /* skip the ':' */
for (j = 0; j < 8; j++) {
sscanf(&(buf[i + 2 * j]), "%02x", &id);
recovered_streamid[j] = (unsigned char)id;
}
AVB_LOGF_DEBUG
- ("EVENT on STREAM ID=%02x%02x%02x%02x%02x%02x%02x%02x ",
- recovered_streamid[0], recovered_streamid[1],
- recovered_streamid[2], recovered_streamid[3],
- recovered_streamid[4], recovered_streamid[5],
- recovered_streamid[6], recovered_streamid[7]);
+ ("FOUND STREAM ID=%02x%02x%02x%02x%02x%02x%02x%02x ",
+ recovered_streamid[0], recovered_streamid[1],
+ recovered_streamid[2], recovered_streamid[3],
+ recovered_streamid[4], recovered_streamid[5],
+ recovered_streamid[6], recovered_streamid[7]);
switch (substate) {
case 0:
AVB_LOG_DEBUG("with state ignore");
@@ -288,34 +170,45 @@ int process_mrp_msg(char *buf, int buflen)
AVB_LOGF_DEBUG("with state UNKNOWN (%d)", substate);
break;
}
- switch (buf[k + 1]) {
- case 'L':
- mrp_attach_cb(recovered_streamid, substate);
- AVB_LOGF_DEBUG("got a leave indication substate %d", substate);
+ mrp_attach_cb(recovered_streamid, substate);
+ if (substate > MSRP_LISTENER_ASKFAILED) {
if (memcmp
- (recovered_streamid, monitor_stream_id,
- sizeof(recovered_streamid)) == 0) {
- listeners = 0;
- AVB_LOG_DEBUG("listener left");
+ (recovered_streamid, monitor_stream_id,
+ sizeof(recovered_streamid)) == 0) {
+ listeners = 1;
+ AVB_LOG_DEBUG("added listener");
}
- break;
- case 'J':
- case 'N':
- AVB_LOGF_DEBUG("got a new/join indication substate %d", substate);
- mrp_attach_cb(recovered_streamid, substate);
- if (substate > MSRP_LISTENER_ASKFAILED) {
- if (memcmp
- (recovered_streamid,
- monitor_stream_id,
- sizeof(recovered_streamid)) == 0)
- listeners = 1;
- }
- break;
+ }
+ break;
+
+ case 'D':
+ i = offset + 4;
+
+ /* save the domain attribute */
+ sscanf(&(buf[i]), "%d", &id);
+ while (buf[i] != 'P')
+ i++;
+ i += 2; /* skip the ':' */
+ sscanf(&(buf[i]), "%d", &priority);
+ while (buf[i] != 'V')
+ i++;
+ i += 2; /* skip the ':' */
+ sscanf(&(buf[i]), "%x", &vid);
+ if (id == 6) {
+ domain_class_a_id = id;
+ domain_class_a_priority = priority;
+ domain_class_a_vid = vid;
+ domain_a_valid = 1;
+ } else {
+ domain_class_b_id = id;
+ domain_class_b_priority = priority;
+ domain_class_b_vid = vid;
+ domain_b_valid = 1;
}
break;
case 'T':
- i = k + 5;
+ i = offset;
while (buf[i] != 'S')
i++;
// skip S=
@@ -335,21 +228,127 @@ int process_mrp_msg(char *buf, int buflen)
i+= j*2 + 1;
sscanf(&(buf[i]), "V=%d,Z=%d,I=%d,P=%d,L=%d",
- &vid,
- &max_frame_size,
- &max_interval_frames,
- &priority_and_rank,
- &latency);
+ &vid,
+ &max_frame_size,
+ &max_interval_frames,
+ &priority_and_rank,
+ &latency);
+
+ mrp_register_cb(recovered_streamid, 0, dest_addr, max_frame_size, max_interval_frames, vid, latency);
+ break;
+
+ case 'S':
+
+ /* handle the leave/join events */
+ switch (buf[offset + 4]) {
+ case 'L':
+ i = offset + 5;
+ while (buf[i] != 'D')
+ i++;
+ i += 2; /* skip the ':' */
+ sscanf(&(buf[i]), "%d", &substate);
+ while (buf[i] != 'S')
+ i++;
+ i += 2; /* skip the ':' */
+ for (j = 0; j < 8; j++) {
+ sscanf(&(buf[i + 2 * j]), "%02x", &id);
+ recovered_streamid[j] = (unsigned char)id;
+ }
+ AVB_LOGF_DEBUG
+ ("EVENT on STREAM ID=%02x%02x%02x%02x%02x%02x%02x%02x ",
+ recovered_streamid[0], recovered_streamid[1],
+ recovered_streamid[2], recovered_streamid[3],
+ recovered_streamid[4], recovered_streamid[5],
+ recovered_streamid[6], recovered_streamid[7]);
+ switch (substate) {
+ case 0:
+ AVB_LOG_DEBUG("with state ignore");
+ break;
+ case 1:
+ AVB_LOG_DEBUG("with state askfailed");
+ break;
+ case 2:
+ AVB_LOG_DEBUG("with state ready");
+ break;
+ case 3:
+ AVB_LOG_DEBUG("with state readyfail");
+ break;
+ default:
+ AVB_LOGF_DEBUG("with state UNKNOWN (%d)", substate);
+ break;
+ }
+ switch (buf[offset + 1]) {
+ case 'L':
+ mrp_attach_cb(recovered_streamid, substate);
+ AVB_LOGF_DEBUG("got a leave indication substate %d", substate);
+ if (memcmp
+ (recovered_streamid, monitor_stream_id,
+ sizeof(recovered_streamid)) == 0) {
+ listeners = 0;
+ AVB_LOG_DEBUG("listener left");
+ }
+ break;
+ case 'J':
+ case 'N':
+ AVB_LOGF_DEBUG("got a new/join indication substate %d", substate);
+ mrp_attach_cb(recovered_streamid, substate);
+ if (substate > MSRP_LISTENER_ASKFAILED) {
+ if (memcmp
+ (recovered_streamid,
+ monitor_stream_id,
+ sizeof(recovered_streamid)) == 0)
+ listeners = 1;
+ }
+ break;
+ }
+ break;
+
+ case 'T':
+ i = offset + 5;
+ while (buf[i] != 'S')
+ i++;
+ // skip S=
+ i += 2;
+ for (j = 0; j < 8; j++) {
+ sscanf(&(buf[i + 2 * j]), "%02x", &id);
+ recovered_streamid[j] = (unsigned char)id;
+ }
+ while (buf[i] != 'A')
+ i++;
+ // skip A=
+ i += 2;
+ for (j = 0; j < 6; j++) {
+ sscanf(&(buf[i + 2 * j]), "%02x", &id);
+ dest_addr[j] = (unsigned char)id;
+ }
+ i+= j*2 + 1;
- mrp_register_cb(recovered_streamid, buf[k+1] == 'J', dest_addr, max_frame_size, max_interval_frames, vid, latency);
+ sscanf(&(buf[i]), "V=%d,Z=%d,I=%d,P=%d,L=%d",
+ &vid,
+ &max_frame_size,
+ &max_interval_frames,
+ &priority_and_rank,
+ &latency);
+
+ mrp_register_cb(recovered_streamid, buf[offset+1] == 'J' || buf[offset+1] == 'N', dest_addr, max_frame_size, max_interval_frames, vid, latency);
+ break;
+
+ default:
+ break;
+ }
break;
- default:
- return 0;
+
+ case '\0':
break;
}
- break;
- case '\0':
- break;
+
+ // Proceed to the next line.
+ while (offset < buflen && buf[offset] != '\n' && buf[offset] != '\0') {
+ offset++;
+ }
+ if (offset < buflen && buf[offset] == '\n') {
+ offset++;
+ }
}
return 0;
}
@@ -434,9 +433,10 @@ int mrp_disconnect(void)
msgbuf = malloc(1500);
if (NULL == msgbuf)
return -1;
- memset(msgbuf, 0, 64);
+ memset(msgbuf, 0, 1500);
sprintf(msgbuf, "BYE");
mrp_okay = 0;
+ AVB_LOGF_DEBUG("MRP Command (Disconnect): %s", msgbuf);
rc = send_mrp_msg(msgbuf, 1500);
free(msgbuf);
@@ -466,6 +466,7 @@ int mrp_register_domain(int *class_id, int *priority, u_int16_t * vid)
sprintf(msgbuf, "S+D:C=%d,P=%d,V=%04x", *class_id, *priority, *vid);
mrp_okay = 0;
+ AVB_LOGF_DEBUG("MRP Command (Register Domain): %s", msgbuf);
rc = send_mrp_msg(msgbuf, 1500);
free(msgbuf);
@@ -502,6 +503,7 @@ mrp_advertise_stream(uint8_t * streamid,
destaddr[3], destaddr[4], destaddr[5], vlan, pktsz,
interval, priority << 5, latency);
mrp_okay = 0;
+ AVB_LOGF_DEBUG("MRP Command (Advertise Stream): %s", msgbuf);
rc = send_mrp_msg(msgbuf, 1500);
free(msgbuf);
@@ -535,6 +537,7 @@ mrp_unadvertise_stream(uint8_t * streamid,
destaddr[3], destaddr[4], destaddr[5], vlan, pktsz,
interval, priority << 5, latency);
mrp_okay = 0;
+ AVB_LOGF_DEBUG("MRP Command (Unadvertise Stream): %s", msgbuf);
rc = send_mrp_msg(msgbuf, 1500);
free(msgbuf);
@@ -556,6 +559,7 @@ int mrp_await_listener(unsigned char *streamid)
return -1;
memset(msgbuf, 0, 1500);
sprintf(msgbuf, "S??");
+ AVB_LOGF_DEBUG("MRP Command (Await Listener): %s", msgbuf);
rc = send_mrp_msg(msgbuf, 1500);
free(msgbuf);
if (rc != 1500)
@@ -587,6 +591,7 @@ int mrp_get_domain(int *class_a_id, int *a_priority, u_int16_t * a_vid,
return -1;
memset(msgbuf, 0, 1500);
sprintf(msgbuf, "S??");
+ AVB_LOGF_DEBUG("MRP Command (Get Domain): %s", msgbuf);
ret = send_mrp_msg(msgbuf, 1500);
free(msgbuf);
if (ret != 1500)
@@ -623,6 +628,7 @@ int mrp_join_vlan()
return -1;
memset(msgbuf, 0, 1500);
sprintf(msgbuf, "V++:I=0002");
+ AVB_LOGF_DEBUG("MRP Command (Join VLAN): %s", msgbuf);
rc = send_mrp_msg(msgbuf, 1500);
free(msgbuf);
@@ -645,6 +651,7 @@ int mrp_join_listener(uint8_t * streamid)
",D=2", streamid[0], streamid[1], streamid[2], streamid[3],
streamid[4], streamid[5], streamid[6], streamid[7]);
mrp_okay = 0;
+ AVB_LOGF_DEBUG("MRP Command (Join Listener): %s", msgbuf);
rc = send_mrp_msg(msgbuf, 1500);
free(msgbuf);
@@ -676,6 +683,7 @@ int mrp_send_ready(uint8_t *stream_id)
stream_id[2], stream_id[3],
stream_id[4], stream_id[5],
stream_id[6], stream_id[7]);
+ AVB_LOGF_DEBUG("MRP Command (Send Ready): %s", databuf);
rc = send_mrp_msg(databuf, 1500);
free(databuf);
@@ -700,6 +708,7 @@ int mrp_send_leave(uint8_t *stream_id)
stream_id[4], stream_id[5],
stream_id[6], stream_id[7]);
+ AVB_LOGF_DEBUG("MRP Command (Send Leave): %s", databuf);
rc = send_mrp_msg(databuf, 1500);
free(databuf);
diff --git a/lib/avtp_pipeline/platform/Linux/CMakeLists.txt b/lib/avtp_pipeline/platform/Linux/CMakeLists.txt
index 585ed769..14f427cc 100644
--- a/lib/avtp_pipeline/platform/Linux/CMakeLists.txt
+++ b/lib/avtp_pipeline/platform/Linux/CMakeLists.txt
@@ -66,6 +66,9 @@ MESSAGE ("-- SDK_INSTALL_SDK_EAVB_DIR : ${SDK_INSTALL_SDK_EAVB_DIR}")
# Turn on all build warnings
set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -Wall" )
+# Turn off strict aliasing
+set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-strict-aliasing" )
+
# Set default visibility of symbols (requires GCC version > 4)
set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden" )
@@ -80,6 +83,17 @@ if ( GSTREAMER_1_0)
set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGSTREAMER_1_0" )
endif ()
+# For AVDECC, disable features we won't need.
+if (DEFINED AVB_FEATURE_AVDECC)
+ if ( AVB_FEATURE_AVDECC )
+ set ( AVB_FEATURE_FQTSS 0 )
+ set ( AVB_FEATURE_GSTREAMER 0 )
+ set ( AVB_FEATURE_ENDPOINT 0 )
+ set ( AVB_FEATURE_IGB 0 )
+ set ( IGB_LAUNCHTIME_ENABLED 0 )
+ endif ()
+endif ()
+
# Default feature flags
if (NOT DEFINED AVB_FEATURE_FQTSS)
set ( AVB_FEATURE_FQTSS 1 )
@@ -92,6 +106,21 @@ endif ()
if (NOT DEFINED AVB_FEATURE_ENDPOINT)
set ( AVB_FEATURE_ENDPOINT 0 )
endif ()
+# Default AVDECC feature
+if (NOT DEFINED AVB_FEATURE_AVDECC)
+ set ( AVB_FEATURE_AVDECC 0 )
+endif ()
+if (NOT DEFINED AVB_FEATURE_IGB)
+ set ( AVB_FEATURE_IGB 1 )
+endif ()
+
+# Default launchtime feature
+if (NOT DEFINED IGB_LAUNCHTIME_ENABLED)
+ set ( IGB_LAUNCHTIME_ENABLED 0 )
+else ()
+ MESSAGE ( "-- IGB launch time enabled" )
+endif ()
+set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DIGB_LAUNCHTIME_ENABLED=${IGB_LAUNCHTIME_ENABLED}" )
# Export feature flags for sub-builds
@@ -104,6 +133,14 @@ endif ()
if (AVB_FEATURE_ENDPOINT)
set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DAVB_FEATURE_ENDPOINT=1" )
endif ()
+if (AVB_FEATURE_AVDECC)
+ set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DAVB_FEATURE_AVDECC=1" )
+endif ()
+if (AVB_FEATURE_IGB)
+ set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DAVB_FEATURE_IGB=1" )
+else ()
+ set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DAVB_FEATURE_IGB=0" )
+endif ()
#Export Platform defines
if ( PLATFORM_DEFINE )
@@ -158,8 +195,8 @@ set ( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PLATFORM_SPECIFIC_LINK
include_directories ( ${PLATFORM_INCLUDE_DIRECTORIES} )
link_directories ( ${PLATFORM_LINK_DIRECTORIES} )
-find_library(TEMP NAMES ${PLATFORM_LINK_LIBRARIES} PATHS ${PLATFORM_LINK_DIRECTORIES} )
-set ( PLATFORM_LINK_LIBRARIES ${TEMP} )
+#find_library(TEMP NAMES ${PLATFORM_LINK_LIBRARIES} PATHS ${PLATFORM_LINK_DIRECTORIES} )
+#set ( PLATFORM_LINK_LIBRARIES ${TEMP} )
# Add our include directories
#
@@ -178,14 +215,19 @@ include_directories(
${AVB_HAL_DIR}/mcr
${AVB_OSAL_DIR}
${AVB_OSAL_DIR}/include
- ${AVB_OSAL_DIR}/fqtss/include
${AVB_SRC_DIR}/include
${AVB_OSAL_DIR}/avtp
${AVB_OSAL_DIR}/tl
${AVB_SRC_DIR}/avtp
+ ${AVB_SRC_DIR}/avdecc
+ ${AVB_SRC_DIR}/acmp
+ ${AVB_SRC_DIR}/adp
+ ${AVB_SRC_DIR}/aecp
+ ${AVB_SRC_DIR}/aem
${AVB_SRC_DIR}/endpoint
${AVB_SRC_DIR}/srp
${AVB_SRC_DIR}/maap
+ ${AVB_SRC_DIR}/shaper
${AVB_SRC_DIR}/inih
${AVB_SRC_DIR}/map_mjpeg
${AVB_SRC_DIR}/map_mpeg2ts
@@ -202,9 +244,12 @@ include_directories(
${AVB_SRC_DIR}/qmgr
${AVB_SRC_DIR}/tl
${AVB_SRC_DIR}/util
+ ${AVB_SRC_DIR}/avdecc_msg
+ ${AVB_OSAL_DIR}/avdecc
${AVB_OSAL_DIR}/endpoint
- ${AVB_OSAL_DIR}/fqtss/qmgr
+ ${AVB_OSAL_DIR}/avdecc_msg
${AVB_SRC_DIR}/../common
+ ${AVB_SRC_DIR}/mcs
)
# Need include and link directories for GLIB
@@ -213,122 +258,136 @@ link_directories(${GLIB_PKG_LIBRARY_DIRS})
# AVB Core Library
SET ( SRC_FILES "" )
-add_subdirectory ( avtp )
-add_subdirectory ( tl )
-add_subdirectory ( util )
-add_subdirectory ( mediaq )
-add_subdirectory ( inih )
-add_subdirectory ( rawsock )
-add_subdirectory ( qmgr )
-if (AVB_FEATURE_ENDPOINT)
- add_subdirectory ( endpoint )
- SET ( SRC_FILES ${SRC_FILES} ${AVB_OSAL_DIR}/openavb_osal_endpoint.c )
-else()
- SET ( SRC_FILES ${SRC_FILES} ${AVB_OSAL_DIR}/openavb_osal.c )
-endif()
-SET ( SRC_FILES ${SRC_FILES} ${AVB_OSAL_DIR}/rawsock/openavb_rawsock.c )
-SET ( SRC_FILES ${SRC_FILES} ${AVB_OSAL_DIR}/rawsock/simple_rawsock.c )
-SET ( SRC_FILES ${SRC_FILES} ${AVB_OSAL_DIR}/rawsock/ring_rawsock.c )
-SET ( SRC_FILES ${SRC_FILES} ${AVB_OSAL_DIR}/rawsock/igb_rawsock.c )
-SET ( SRC_FILES ${SRC_FILES} ${AVB_OSAL_DIR}/openavb_time_osal.c )
-SET ( SRC_FILES ${SRC_FILES} ${AVB_HAL_DIR}/openavb_ether_hal.c )
-SET ( SRC_FILES ${SRC_FILES} ${AVB_HAL_DIR}/openavb_time_hal.c )
-SET ( SRC_FILES ${SRC_FILES} ${AVB_HAL_DIR}/mcr/openavb_mcr_hal.c )
-
-# OpenAVB Common (support) files
-SET ( SRC_FILES ${SRC_FILES} ${AVB_SRC_DIR}/../common/avb.c )
-SET ( SRC_FILES ${SRC_FILES} ${AVB_SRC_DIR}/openavb_common/mrp_client.c )
if ( AVB_FEATURE_PCAP )
find_package ( PCAP REQUIRED )
set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DAVB_FEATURE_PCAP" )
include_directories ( ${PCAP_INCLUDE_DIR} )
- list ( APPEND SRC_FILES ${AVB_OSAL_DIR}/rawsock/pcap_rawsock.c )
+ if ( AVB_FEATURE_IGB )
+ set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DAVB_FEATURE_IGB" )
+ endif ()
endif ()
-add_library ( avbTl ${SRC_FILES} )
-target_link_libraries ( avbTl dl )
+add_subdirectory ( util )
+add_subdirectory ( inih )
+add_subdirectory ( rawsock )
+add_subdirectory ( openavb_common )
-install ( TARGETS avbTl ARCHIVE DESTINATION ${AVB_INSTALL_LIB_DIR} )
+# TODO: Make the above avbBase, then make avbTl and avbAvdecc from below
+
+if (AVB_FEATURE_AVDECC)
+ add_subdirectory ( avdecc )
+ add_subdirectory ( acmp )
+ add_subdirectory ( adp )
+ add_subdirectory ( aecp )
+ add_subdirectory ( aem )
+else ()
+ add_subdirectory ( avtp )
+ add_subdirectory ( mediaq )
+ add_subdirectory ( mcr )
+ add_subdirectory ( mcs )
+ add_subdirectory ( tl )
+ add_subdirectory ( qmgr )
+ if (AVB_FEATURE_ENDPOINT)
+ add_subdirectory ( endpoint )
+ endif ()
+endif ()
+add_library ( avbTl ${SRC_FILES} )
+target_link_libraries ( avbTl dl m )
if ( AVB_FEATURE_PCAP )
target_link_libraries ( avbTl ${PCAP_LIBRARY} )
endif ()
-# avb_host (openavb_host and openavb_harness)
-add_subdirectory ( ${AVB_OSAL_DIR}/avb_host )
-
-# mapping modules
-macro (add_map_mod MAP_NAME)
- SET ( SRC_FILES "" )
- add_subdirectory ( ${MAP_NAME} )
- add_library ( ${MAP_NAME} ${SRC_FILES} )
- install ( TARGETS ${MAP_NAME} ARCHIVE DESTINATION ${AVB_INSTALL_LIB_DIR} )
-endmacro()
-add_map_mod ( "map_ctrl" )
-add_map_mod ( "map_mjpeg" )
-add_map_mod ( "map_mpeg2ts" )
-add_map_mod ( "map_null" )
-add_map_mod ( "map_pipe" )
-add_map_mod ( "map_aaf_audio" )
-add_map_mod ( "map_uncmp_audio" )
-add_map_mod ( "map_h264" )
-
-# Interface modules (common)
-macro (add_intf_mod INTF_NAME)
- SET ( SRC_FILES "" )
- add_subdirectory ( ${INTF_NAME} )
- add_library ( ${INTF_NAME} ${SRC_FILES} )
- install ( TARGETS ${INTF_NAME} ARCHIVE DESTINATION ${AVB_INSTALL_LIB_DIR} )
- install ( DIRECTORY "${AVB_SRC_DIR}/${INTF_NAME}/" DESTINATION ${AVB_INSTALL_BIN_DIR} FILES_MATCHING PATTERN "*.ini" )
-endmacro()
-add_intf_mod ( "intf_ctrl" )
-add_intf_mod ( "intf_echo" )
-add_intf_mod ( "intf_logger" )
-add_intf_mod ( "intf_null" )
-add_intf_mod ( "intf_tonegen" )
-add_intf_mod ( "intf_viewer" )
-
-# Interface modules (platform)
-macro (add_intf_mod_platform INTF_NAME)
- SET ( SRC_FILES "" )
- SET ( INTF_INCLUDE_DIR "")
- SET ( INTF_LIBRARY_DIR "")
- SET ( INTF_LIBRARY "")
- add_subdirectory ( ${AVB_OSAL_DIR}/${INTF_NAME} )
- include_directories ( ${INTF_INCLUDE_DIR} )
- add_library ( ${INTF_NAME} ${SRC_FILES} )
- install ( TARGETS ${INTF_NAME} ARCHIVE DESTINATION ${AVB_INSTALL_LIB_DIR} )
- install ( DIRECTORY "${AVB_OSAL_DIR}/${INTF_NAME}/" DESTINATION ${AVB_INSTALL_BIN_DIR} FILES_MATCHING PATTERN "*.ini" )
-endmacro()
-
-add_intf_mod_platform ( "intf_alsa" )
-if (AVB_FEATURE_GSTREAMER)
- add_intf_mod_platform ( "intf_mpeg2ts_gst" )
- add_intf_mod_platform ( "intf_mjpeg_gst" )
- add_intf_mod_platform ( "intf_h264_gst" )
+install ( TARGETS avbTl ARCHIVE DESTINATION ${AVB_INSTALL_LIB_DIR} )
+
+if (AVB_FEATURE_AVDECC)
+ # avb_avdecc (openavb_avdecc)
+ add_subdirectory ( ${AVB_OSAL_DIR}/avb_avdecc )
+else ()
+ # avb_host (openavb_host and openavb_harness)
+ add_subdirectory ( ${AVB_OSAL_DIR}/avb_host )
+endif ()
+
+if (NOT AVB_FEATURE_AVDECC)
+ # mapping modules
+ macro (add_map_mod MAP_NAME)
+ SET ( SRC_FILES "" )
+ add_subdirectory ( ${MAP_NAME} )
+ add_library ( ${MAP_NAME} ${SRC_FILES} )
+ install ( TARGETS ${MAP_NAME} ARCHIVE DESTINATION ${AVB_INSTALL_LIB_DIR} )
+ endmacro()
+ add_map_mod ( "map_ctrl" )
+ add_map_mod ( "map_mjpeg" )
+ add_map_mod ( "map_mpeg2ts" )
+ add_map_mod ( "map_null" )
+ add_map_mod ( "map_pipe" )
+ add_map_mod ( "map_aaf_audio" )
+ add_map_mod ( "map_uncmp_audio" )
+ add_map_mod ( "map_h264" )
+
+ # Interface modules (common)
+ macro (add_intf_mod INTF_NAME)
+ SET ( SRC_FILES "" )
+ add_subdirectory ( ${INTF_NAME} )
+ add_library ( ${INTF_NAME} ${SRC_FILES} )
+ install ( TARGETS ${INTF_NAME} ARCHIVE DESTINATION ${AVB_INSTALL_LIB_DIR} )
+ install ( DIRECTORY "${AVB_SRC_DIR}/${INTF_NAME}/" DESTINATION ${AVB_INSTALL_BIN_DIR} FILES_MATCHING PATTERN "*.ini" )
+ endmacro()
+ add_intf_mod ( "intf_ctrl" )
+ add_intf_mod ( "intf_echo" )
+ add_intf_mod ( "intf_logger" )
+ add_intf_mod ( "intf_null" )
+ add_intf_mod ( "intf_tonegen" )
+ add_intf_mod ( "intf_viewer" )
+
+ # Interface modules (platform)
+ macro (add_intf_mod_platform INTF_NAME)
+ SET ( SRC_FILES "" )
+ SET ( INTF_INCLUDE_DIR "")
+ SET ( INTF_LIBRARY_DIR "")
+ SET ( INTF_LIBRARY "")
+ add_subdirectory ( ${AVB_OSAL_DIR}/${INTF_NAME} )
+ include_directories ( ${INTF_INCLUDE_DIR} )
+ add_library ( ${INTF_NAME} ${SRC_FILES} )
+ install ( TARGETS ${INTF_NAME} ARCHIVE DESTINATION ${AVB_INSTALL_LIB_DIR} )
+ install ( DIRECTORY "${AVB_OSAL_DIR}/${INTF_NAME}/" DESTINATION ${AVB_INSTALL_BIN_DIR} FILES_MATCHING PATTERN "*.ini" )
+ endmacro()
+
+ add_intf_mod_platform ( "intf_alsa" )
+ if (AVB_FEATURE_GSTREAMER)
+ add_intf_mod_platform ( "intf_mpeg2ts_gst" )
+ add_intf_mod_platform ( "intf_mjpeg_gst" )
+ add_intf_mod_platform ( "intf_h264_gst" )
+ endif ()
+ add_intf_mod_platform ( "intf_mpeg2ts_file" )
+ add_intf_mod_platform ( "intf_wav_file" )
endif ()
-add_intf_mod_platform ( "intf_mpeg2ts_file" )
-add_intf_mod_platform ( "intf_wav_file" )
# API documentation
add_subdirectory ( documents )
-# SDKS
-add_subdirectory ( sdk )
+if (NOT AVB_FEATURE_AVDECC)
+ # SDKS
+ add_subdirectory ( sdk )
-# rawsock_rx
-add_executable (rawsock_rx ${AVB_OSAL_DIR}/rawsock/rawsock_rx.c)
-target_link_libraries (rawsock_rx avbTl ${GLIB_PKG_LIBRARIES} pthread rt pci ${PLATFORM_LINK_LIBRARIES} )
-install ( TARGETS rawsock_rx RUNTIME DESTINATION ${AVB_INSTALL_BIN_DIR} )
+ # rawsock_rx
+ add_executable (rawsock_rx ${AVB_OSAL_DIR}/rawsock/rawsock_rx.c)
+ target_link_libraries (rawsock_rx avbTl ${GLIB_PKG_LIBRARIES} pthread rt ${PLATFORM_LINK_LIBRARIES} )
+ install ( TARGETS rawsock_rx RUNTIME DESTINATION ${AVB_INSTALL_BIN_DIR} )
-# rawsock_tx
-add_executable (rawsock_tx ${AVB_OSAL_DIR}/rawsock/rawsock_tx.c)
-target_link_libraries (rawsock_tx avbTl ${GLIB_PKG_LIBRARIES} pthread rt pci ${PLATFORM_LINK_LIBRARIES} )
-install ( TARGETS rawsock_tx RUNTIME DESTINATION ${AVB_INSTALL_BIN_DIR} )
+ # rawsock_tx
+ add_executable (rawsock_tx ${AVB_OSAL_DIR}/rawsock/rawsock_tx.c)
+ target_link_libraries (rawsock_tx avbTl ${GLIB_PKG_LIBRARIES} pthread rt ${PLATFORM_LINK_LIBRARIES} )
+ install ( TARGETS rawsock_tx RUNTIME DESTINATION ${AVB_INSTALL_BIN_DIR} )
+endif ()
# Copy additional installation files
-install ( FILES ${AVB_SRC_DIR}/endpoint/endpoint.ini DESTINATION ${AVB_INSTALL_BIN_DIR} )
-install ( PROGRAMS ${AVB_SRC_DIR}/endpoint/shutdown_openavb_endpoint.sh DESTINATION ${AVB_INSTALL_BIN_DIR} )
-
-
+if (AVB_FEATURE_ENDPOINT)
+ install ( FILES ${AVB_SRC_DIR}/endpoint/endpoint.ini DESTINATION ${AVB_INSTALL_BIN_DIR} )
+ install ( PROGRAMS ${AVB_SRC_DIR}/endpoint/shutdown_openavb_endpoint.sh DESTINATION ${AVB_INSTALL_BIN_DIR} )
+endif ()
+if (AVB_FEATURE_AVDECC)
+ install ( FILES ${AVB_SRC_DIR}/avdecc/avdecc.ini DESTINATION ${AVB_INSTALL_BIN_DIR} )
+ install ( PROGRAMS ${AVB_SRC_DIR}/avdecc/shutdown_openavb_avdecc.sh DESTINATION ${AVB_INSTALL_BIN_DIR} )
+endif ()
diff --git a/lib/avtp_pipeline/platform/Linux/arm_imx6sx_linux.cmake b/lib/avtp_pipeline/platform/Linux/arm_imx6sx_linux.cmake
new file mode 100644
index 00000000..ee559020
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/arm_imx6sx_linux.cmake
@@ -0,0 +1,26 @@
+set ( GSTREAMER_1_0 0 )
+set ( AVB_FEATURE_PCAP 1 )
+set ( AVB_FEATURE_IGB 0 )
+set ( IGB_LAUNCHTIME_ENABLED 0 )
+
+# and another kernel sources
+#set ( LINUX_KERNEL_DIR "/usr/src/kernel" )
+
+# build configuration
+set ( OPENAVB_HAL "arm_im6sx" )
+set ( OPENAVB_OSAL "Linux" )
+set ( OPENAVB_TCAL "GNU" )
+set ( OPENAVB_PLATFORM "${OPENAVB_HAL}-${OPENAVB_OSAL}" )
+
+# Platform Additions
+set ( PLATFORM_INCLUDE_DIRECTORIES
+ ${CMAKE_SOURCE_DIR}/platform/arm_imx6x/include
+ ${CMAKE_SOURCE_DIR}/openavb_common
+ ${CMAKE_SOURCE_DIR}/../../daemons/common
+ ${CMAKE_SOURCE_DIR}/../../daemons/mrpd
+ ${CMAKE_SOURCE_DIR}/../../daemons/maap/common
+)
+
+# TODO_OPENAVB : need this?
+# Set platform specific define
+#set ( PLATFORM_DEFINE "AVB_DELAY_TWEAK_USEC=15" )
diff --git a/lib/avtp_pipeline/platform/Linux/avb_avdecc/CMakeLists.txt b/lib/avtp_pipeline/platform/Linux/avb_avdecc/CMakeLists.txt
new file mode 100644
index 00000000..12e9e6e2
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avb_avdecc/CMakeLists.txt
@@ -0,0 +1,25 @@
+include_directories(
+ ${AVB_OSAL_DIR}/avdecc
+ ${AVB_SRC_DIR}/util
+ )
+
+# Rules to build the AVB AVDECC
+add_executable ( openavb_avdecc openavb_avdecc.c )
+target_link_libraries( openavb_avdecc
+ avbTl
+ ${PLATFORM_LINK_LIBRARIES}
+ ${ALSA_LIBRARIES}
+ ${GSTRTP_PKG_LIBRARIES}
+ ${GLIB_PKG_LIBRARIES}
+ ${GST_PKG_LIBRARIES}
+ pthread
+ rt
+ dl )
+
+# Install rules
+install ( TARGETS openavb_avdecc RUNTIME DESTINATION ${AVB_INSTALL_BIN_DIR} )
+
+if (AVB_FEATURE_GSTREAMER)
+include_directories( ${GLIB_PKG_INCLUDE_DIRS} ${GST_PKG_INCLUDE_DIRS} )
+target_link_libraries( openavb_avdecc ${GLIB_PKG_LIBRARIES} ${GST_PKG_LIBRARIES} ${PLATFORM_LINK_LIBRARIES} )
+endif ()
diff --git a/lib/avtp_pipeline/platform/Linux/avb_avdecc/openavb_avdecc.c b/lib/avtp_pipeline/platform/Linux/avb_avdecc/openavb_avdecc.c
new file mode 100644
index 00000000..885b06ea
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avb_avdecc/openavb_avdecc.c
@@ -0,0 +1,178 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+* MODULE SUMMARY : AVDECC main implementation.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include "openavb_avdecc_pub.h"
+#include "openavb_plugin.h"
+#include "openavb_trace_pub.h"
+
+#define AVB_LOG_COMPONENT "AVDECC Main"
+#include "openavb_log_pub.h"
+
+bool avdeccRunning = TRUE;
+
+/***********************************************
+ * Signal handler - used to respond to signals.
+ * Allows graceful cleanup.
+ */
+static void openavbAvdeccSigHandler(int signal)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_HOST);
+
+ if (signal == SIGINT || signal == SIGTERM) {
+ if (avdeccRunning) {
+ AVB_LOG_INFO("AVDECC shutting down");
+ avdeccRunning = FALSE;
+ }
+ else {
+ // Force shutdown
+ exit(2);
+ }
+ }
+ else {
+ AVB_LOG_ERROR("Unexpected signal");
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_HOST);
+}
+
+void openavbAvdeccHostUsage(char *programName)
+{
+ printf(
+ "\n"
+ "Usage: %s [options] file...\n"
+ " -I val Use given (val) interface globally, can be overriden by giving the ifname= option to the config line.\n"
+ "\n"
+ "Examples:\n"
+ " %s talker.ini\n"
+ " Control 1 stream with data from the ini file.\n\n"
+ " %s talker1.ini talker2.ini\n"
+ " Control 2 streams with data from the ini files.\n\n"
+ " %s -I eth0 talker1.ini listener2.ini\n"
+ " Control 2 streams with data from the ini files, using the eth0 interface.\n\n"
+ ,
+ programName, programName, programName, programName);
+}
+
+/**********************************************
+ * main
+ */
+int main(int argc, char *argv[])
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_HOST);
+
+ char *programName;
+ char *optIfnameGlobal = NULL;
+
+ programName = strrchr(argv[0], '/');
+ programName = programName ? programName + 1 : argv[0];
+
+ if (argc < 2) {
+ openavbAvdeccHostUsage(programName);
+ exit(-1);
+ }
+
+ // Process command line
+ bool optDone = FALSE;
+ while (!optDone) {
+ int opt = getopt(argc, argv, "hI:");
+ if (opt != EOF) {
+ switch (opt) {
+ case 'I':
+ optIfnameGlobal = strdup(optarg);
+ break;
+ case 'h':
+ default:
+ openavbAvdeccHostUsage(programName);
+ exit(-1);
+ }
+ }
+ else {
+ optDone = TRUE;
+ }
+ }
+
+ int iniIdx = optind;
+ int tlCount = argc - iniIdx;
+
+ if (!osalAvdeccInitialize(optIfnameGlobal, (const char **) (argv + iniIdx), tlCount)) {
+ osalAvdeccFinalize();
+ exit(-1);
+ }
+
+ // Setup signal handler
+ // We catch SIGINT and shutdown cleanly
+ bool err;
+ struct sigaction sa;
+ sa.sa_handler = openavbAvdeccSigHandler;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ err = sigaction(SIGINT, &sa, NULL);
+ if (err)
+ {
+ AVB_LOG_ERROR("Failed to setup SIGINT handler");
+ osalAvdeccFinalize();
+ exit(-1);
+ }
+ err = sigaction(SIGTERM, &sa, NULL);
+ if (err)
+ {
+ AVB_LOG_ERROR("Failed to setup SIGTERM handler");
+ osalAvdeccFinalize();
+ exit(-1);
+ }
+ err = sigaction(SIGUSR1, &sa, NULL);
+ if (err)
+ {
+ AVB_LOG_ERROR("Failed to setup SIGUSR1 handler");
+ osalAvdeccFinalize();
+ exit(-1);
+ }
+
+ // Ignore SIGPIPE signals.
+ signal(SIGPIPE, SIG_IGN);
+
+ while (avdeccRunning) {
+ SLEEP_MSEC(1);
+ }
+
+ osalAvdeccFinalize();
+
+ AVB_TRACE_EXIT(AVB_TRACE_HOST);
+ exit(0);
+}
diff --git a/lib/avtp_pipeline/platform/Linux/avb_host/CMakeLists.txt b/lib/avtp_pipeline/platform/Linux/avb_host/CMakeLists.txt
index 1edf78ab..f11837c4 100644
--- a/lib/avtp_pipeline/platform/Linux/avb_host/CMakeLists.txt
+++ b/lib/avtp_pipeline/platform/Linux/avb_host/CMakeLists.txt
@@ -24,21 +24,15 @@ target_link_libraries( openavb_host
intf_tonegen
intf_viewer
intf_alsa
- intf_mpeg2ts_gst
- intf_mjpeg_gst
intf_mpeg2ts_file
intf_wav_file
- intf_h264_gst
avbTl
${PLATFORM_LINK_LIBRARIES}
${ALSA_LIBRARIES}
- ${GSTRTP_PKG_LIBRARIES}
${GLIB_PKG_LIBRARIES}
- ${GST_PKG_LIBRARIES}
pthread
rt
- dl
- pci )
+ dl )
# Rules to build the AVB harness
@@ -59,21 +53,15 @@ target_link_libraries( openavb_harness
intf_tonegen
intf_viewer
intf_alsa
- intf_mpeg2ts_gst
- intf_mjpeg_gst
intf_mpeg2ts_file
intf_wav_file
- intf_h264_gst
avbTl
${PLATFORM_LINK_LIBRARIES}
${ALSA_LIBRARIES}
- ${GSTRTP_PKG_LIBRARIES}
${GLIB_PKG_LIBRARIES}
- ${GST_PKG_LIBRARIES}
pthread
rt
- dl
- pci )
+ dl )
# Install rules
install ( TARGETS openavb_host RUNTIME DESTINATION ${AVB_INSTALL_BIN_DIR} )
@@ -81,6 +69,6 @@ install ( TARGETS openavb_harness RUNTIME DESTINATION ${AVB_INSTALL_BIN_DIR} )
if (AVB_FEATURE_GSTREAMER)
include_directories( ${GLIB_PKG_INCLUDE_DIRS} ${GST_PKG_INCLUDE_DIRS} )
-target_link_libraries( openavb_host ${GLIB_PKG_LIBRARIES} ${GST_PKG_LIBRARIES} ${PLATFORM_LINK_LIBRARIES} )
-target_link_libraries( openavb_harness ${GLIB_PKG_LIBRARIES} ${GST_PKG_LIBRARIES} ${PLATFORM_LINK_LIBRARIES} )
+target_link_libraries( openavb_host intf_mpeg2ts_gst intf_mjpeg_gst intf_h264_gst ${GST_PKG_LIBRARIES} ${GSTRTP_PKG_LIBRARIES} )
+target_link_libraries( openavb_harness intf_mpeg2ts_gst intf_mjpeg_gst intf_h264_gst ${GST_PKG_LIBRARIES} ${GSTRTP_PKG_LIBRARIES} )
endif ()
diff --git a/lib/avtp_pipeline/platform/Linux/avb_host/openavb_harness.c b/lib/avtp_pipeline/platform/Linux/avb_host/openavb_harness.c
index c999e628..115d553b 100644
--- a/lib/avtp_pipeline/platform/Linux/avb_host/openavb_harness.c
+++ b/lib/avtp_pipeline/platform/Linux/avb_host/openavb_harness.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -53,7 +54,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
bool bRunning = TRUE;
-// Platform indendent mapping modules
+// Platform independent mapping modules
extern bool openavbMapPipeInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec);
extern bool openavbMapAVTPAudioInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec);
extern bool openavbMapCtrlInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec);
@@ -63,7 +64,7 @@ extern bool openavbMapMpeg2tsInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pM
extern bool openavbMapNullInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec);
extern bool openavbMapUncmpAudioInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec);
-// Platform indendent interface modules
+// Platform independent interface modules
extern bool openavbIntfEchoInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
extern bool openavbIntfCtrlInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
extern bool openavbIntfLoggerInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
@@ -73,12 +74,13 @@ extern bool openavbIntfViewerInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *p
// Linux interface modules
extern bool openavbIntfAlsaInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
-extern bool openavbIntfMjpegGstInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
extern bool openavbIntfMpeg2tsFileInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
-extern bool openavbIntfMpeg2tsGstInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
extern bool openavbIntfWavFileInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
+#ifdef AVB_FEATURE_GSTREAMER
+extern bool openavbIntfMpeg2tsGstInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
+extern bool openavbIntfMjpegGstInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
extern bool openavbIntfH264RtpGstInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
-
+#endif
/***********************************************
@@ -89,9 +91,15 @@ static void openavbTLSigHandler(int signal)
{
AVB_TRACE_ENTRY(AVB_TRACE_HOST);
- if (signal == SIGINT) {
- AVB_LOG_INFO("Host shutting down");
- bRunning = FALSE;
+ if (signal == SIGINT || signal == SIGTERM) {
+ if (bRunning) {
+ AVB_LOG_INFO("Host shutting down");
+ bRunning = FALSE;
+ }
+ else {
+ // Force shutdown
+ exit(2);
+ }
}
else if (signal == SIGUSR1) {
AVB_LOG_DEBUG("Waking up streaming thread");
@@ -181,8 +189,12 @@ int main(int argc, char *argv[])
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0; // not SA_RESTART
sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGTERM, &sa, NULL);
sigaction(SIGUSR1, &sa, NULL);
+ // Ignore SIGPIPE signals.
+ signal(SIGPIPE, SIG_IGN);
+
registerStaticMapModule(openavbMapPipeInitialize);
registerStaticMapModule(openavbMapAVTPAudioInitialize);
registerStaticMapModule(openavbMapCtrlInitialize);
@@ -196,15 +208,16 @@ int main(int argc, char *argv[])
registerStaticIntfModule(openavbIntfCtrlInitialize);
registerStaticIntfModule(openavbIntfLoggerInitialize);
registerStaticIntfModule(openavbIntfNullInitialize);
- //registerStaticIntfModule(openavbIntfToneGenInitialize);
+ registerStaticIntfModule(openavbIntfToneGenInitialize);
registerStaticIntfModule(openavbIntfViewerInitialize);
registerStaticIntfModule(openavbIntfAlsaInitialize);
- registerStaticIntfModule(openavbIntfMjpegGstInitialize);
registerStaticIntfModule(openavbIntfMpeg2tsFileInitialize);
- registerStaticIntfModule(openavbIntfMpeg2tsGstInitialize);
registerStaticIntfModule(openavbIntfWavFileInitialize);
+#ifdef AVB_FEATURE_GSTREAMER
+ registerStaticIntfModule(openavbIntfMjpegGstInitialize);
+ registerStaticIntfModule(openavbIntfMpeg2tsGstInitialize);
registerStaticIntfModule(openavbIntfH264RtpGstInitialize);
-
+#endif
// Process command line
programName = strrchr(argv[0], '/');
programName = programName ? programName + 1 : argv[0];
@@ -352,14 +365,16 @@ int main(int argc, char *argv[])
if (!optInteractive) {
// Non-interactive mode
- // Run the streams
+ // Run any streams where the stop initial state was not requested.
for (i1 = 0; i1 < tlCount; i1++) {
- printf("Starting: %s\n", tlIniList[i1]);
- openavbTLRun(tlHandleList[i1]);
+ if (openavbTLGetInitialState(tlHandleList[i1]) != TL_INIT_STATE_STOPPED) {
+ printf("Starting: %s\n", tlIniList[i1]);
+ openavbTLRun(tlHandleList[i1]);
+ }
}
while (bRunning) {
- sleep(1);
+ SLEEP_MSEC(1);
}
for (i1 = 0; i1 < tlCount; i1++) {
@@ -372,6 +387,14 @@ int main(int argc, char *argv[])
else {
// Interactive mode
+ // Run any streams where the running initial state was requested.
+ for (i1 = 0; i1 < tlCount; i1++) {
+ if (openavbTLGetInitialState(tlHandleList[i1]) == TL_INIT_STATE_RUNNING) {
+ printf("Starting: %s\n", tlIniList[i1]);
+ openavbTLRun(tlHandleList[i1]);
+ }
+ }
+
openavbTlHarnessMenu();
while (bRunning) {
char buf[16];
@@ -499,7 +522,7 @@ int main(int argc, char *argv[])
// Close the streams
for (i1 = 0; i1 < tlCount; i1++) {
if (tlHandleList[i1]) {
- printf("Stopping: %s\n", tlIniList[i1]);
+ printf("Closing: %s\n", tlIniList[i1]);
openavbTLClose(tlHandleList[i1]);
diff --git a/lib/avtp_pipeline/platform/Linux/avb_host/openavb_host.c b/lib/avtp_pipeline/platform/Linux/avb_host/openavb_host.c
index e1eec996..324f54d2 100644
--- a/lib/avtp_pipeline/platform/Linux/avb_host/openavb_host.c
+++ b/lib/avtp_pipeline/platform/Linux/avb_host/openavb_host.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -48,7 +49,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
bool bRunning = TRUE;
-// Platform indendent mapping modules
+// Platform independent mapping modules
extern bool openavbMapPipeInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec);
extern bool openavbMapAVTPAudioInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec);
extern bool openavbMapCtrlInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec);
@@ -58,7 +59,7 @@ extern bool openavbMapMpeg2tsInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pM
extern bool openavbMapNullInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec);
extern bool openavbMapUncmpAudioInitialize(media_q_t *pMediaQ, openavb_map_cb_t *pMapCB, U32 inMaxTransitUsec);
-// Platform indendent interface modules
+// Platform independent interface modules
extern bool openavbIntfEchoInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
extern bool openavbIntfCtrlInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
extern bool openavbIntfLoggerInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
@@ -68,11 +69,13 @@ extern bool openavbIntfViewerInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *p
// Linux interface modules
extern bool openavbIntfAlsaInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
-extern bool openavbIntfMjpegGstInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
extern bool openavbIntfMpeg2tsFileInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
-extern bool openavbIntfMpeg2tsGstInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
extern bool openavbIntfWavFileInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
+#ifdef AVB_FEATURE_GSTREAMER
+extern bool openavbIntfMjpegGstInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
+extern bool openavbIntfMpeg2tsGstInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
extern bool openavbIntfH264RtpGstInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB);
+#endif
/***********************************************
* Signal handler - used to respond to signals.
@@ -82,9 +85,15 @@ static void openavbTLSigHandler(int signal)
{
AVB_TRACE_ENTRY(AVB_TRACE_HOST);
- if (signal == SIGINT) {
- AVB_LOG_INFO("Host shutting down");
- bRunning = FALSE;
+ if (signal == SIGINT || signal == SIGTERM) {
+ if (bRunning) {
+ AVB_LOG_INFO("Host shutting down");
+ bRunning = FALSE;
+ }
+ else {
+ // Force shutdown
+ exit(2);
+ }
}
else if (signal == SIGUSR1) {
AVB_LOG_DEBUG("Waking up streaming thread");
@@ -183,6 +192,13 @@ int main(int argc, char *argv[])
osalAVBFinalize();
exit(-1);
}
+ err = sigaction(SIGTERM, &sa, NULL);
+ if (err)
+ {
+ AVB_LOG_ERROR("Failed to setup SIGTERM handler");
+ osalAVBFinalize();
+ exit(-1);
+ }
err = sigaction(SIGUSR1, &sa, NULL);
if (err)
{
@@ -191,6 +207,9 @@ int main(int argc, char *argv[])
exit(-1);
}
+ // Ignore SIGPIPE signals.
+ signal(SIGPIPE, SIG_IGN);
+
registerStaticMapModule(openavbMapPipeInitialize);
registerStaticMapModule(openavbMapAVTPAudioInitialize);
registerStaticMapModule(openavbMapCtrlInitialize);
@@ -204,15 +223,16 @@ int main(int argc, char *argv[])
registerStaticIntfModule(openavbIntfCtrlInitialize);
registerStaticIntfModule(openavbIntfLoggerInitialize);
registerStaticIntfModule(openavbIntfNullInitialize);
- //registerStaticIntfModule(openavbIntfToneGenInitialize);
+ registerStaticIntfModule(openavbIntfToneGenInitialize);
registerStaticIntfModule(openavbIntfViewerInitialize);
registerStaticIntfModule(openavbIntfAlsaInitialize);
- registerStaticIntfModule(openavbIntfMjpegGstInitialize);
registerStaticIntfModule(openavbIntfMpeg2tsFileInitialize);
- registerStaticIntfModule(openavbIntfMpeg2tsGstInitialize);
registerStaticIntfModule(openavbIntfWavFileInitialize);
+#ifdef AVB_FEATURE_GSTREAMER
+ registerStaticIntfModule(openavbIntfMjpegGstInitialize);
+ registerStaticIntfModule(openavbIntfMpeg2tsGstInitialize);
registerStaticIntfModule(openavbIntfH264RtpGstInitialize);
-
+#endif
tlHandleList = calloc(1, sizeof(tl_handle_t) * tlCount);
// Open all streams
@@ -259,12 +279,15 @@ int main(int argc, char *argv[])
gst_init(0, NULL);
#endif
+ // Run any streams where the stop initial state was not requested.
for (i1 = 0; i1 < tlCount; i1++) {
- openavbTLRun(tlHandleList[i1]);
+ if (openavbTLGetInitialState(tlHandleList[i1]) != TL_INIT_STATE_STOPPED) {
+ openavbTLRun(tlHandleList[i1]);
+ }
}
while (bRunning) {
- sleep(1);
+ SLEEP_MSEC(1);
}
for (i1 = 0; i1 < tlCount; i1++) {
diff --git a/lib/avtp_pipeline/platform/Linux/avdecc/CMakeLists.txt b/lib/avtp_pipeline/platform/Linux/avdecc/CMakeLists.txt
new file mode 100644
index 00000000..139597f9
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avdecc/CMakeLists.txt
@@ -0,0 +1,2 @@
+
+
diff --git a/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_cfg.c b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_cfg.c
new file mode 100644
index 00000000..cdf70181
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_cfg.c
@@ -0,0 +1,279 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+* MODULE SUMMARY : Reads the AVDECC .ini file for an endpoint
+*/
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include "openavb_avdecc_cfg.h"
+#include "openavb_trace.h"
+#include "openavb_rawsock.h"
+#include "ini.h"
+
+#define AVB_LOG_COMPONENT "AVDECC Cfg"
+#include "openavb_log.h"
+
+// macro to make matching names easier
+#define MATCH(A, B)(strcasecmp((A), (B)) == 0)
+#define MATCH_FIRST(A, B)(strncasecmp((A), (B), strlen(B)) == 0)
+
+static void cfgValErr(const char *section, const char *name, const char *value)
+{
+ AVB_LOGF_ERROR("Invalid value: section=%s, name=%s, value=%s",
+ section, name, value);
+}
+
+static int cfgCallback(void *user, const char *section, const char *name, const char *value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ if (!user || !section || !name || !value) {
+ AVB_LOG_ERROR("Config: invalid arguments passed to callback");
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return 0;
+ }
+
+ openavb_avdecc_cfg_t *pCfg = (openavb_avdecc_cfg_t*)user;
+
+ AVB_LOGF_DEBUG("name=[%s] value=[%s]", name, value);
+
+ bool valOK = FALSE;
+ char *pEnd;
+
+ if (MATCH(section, "network"))
+ {
+ if (MATCH(name, "ifname"))
+ {
+ if_info_t ifinfo;
+ if (openavbCheckInterface(value, &ifinfo)) {
+ strncpy(pCfg->ifname, value, IFNAMSIZ - 1);
+ memcpy(pCfg->ifmac, &ifinfo.mac, ETH_ALEN);
+ valOK = TRUE;
+ }
+ }
+ }
+ else if (MATCH(section, "vlan"))
+ {
+ if (MATCH(name, "vlanID")) {
+ errno = 0;
+ pCfg->vlanID = strtoul(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0)
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "vlanPCP")) {
+ errno = 0;
+ pCfg->vlanPCP = strtoul(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0)
+ valOK = TRUE;
+ }
+ else {
+ // unmatched item, fail
+ AVB_LOGF_ERROR("Unrecognized configuration item: section=%s, name=%s", section, name);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return 0;
+ }
+ }
+ else if (MATCH(section, "fast_connect"))
+ {
+ if (MATCH(name, "fast_connect")) {
+ errno = 0;
+ pCfg->bFastConnectSupported = (strtoul(value, &pEnd, 10) != 0);
+ if (*pEnd == '\0' && errno == 0)
+ valOK = TRUE;
+ }
+ else {
+ // unmatched item, fail
+ AVB_LOGF_ERROR("Unrecognized configuration item: section=%s, name=%s", section, name);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return 0;
+ }
+ }
+ else if (MATCH(section, "discovery"))
+ {
+ if (MATCH(name, "valid_time")) {
+ errno = 0;
+ pCfg->valid_time = strtoul(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0) {
+ if (pCfg->valid_time < 2 || pCfg->valid_time > 62) {
+ AVB_LOG_ERROR("valid_time must be between 2 and 62 (inclusive)");
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return 0;
+ }
+ if ((pCfg->valid_time & 1) != 0) {
+ AVB_LOGF_WARNING("valid_time converted to an even number (%d to %d)", pCfg->valid_time, pCfg->valid_time - 1);
+ }
+ pCfg->valid_time /= 2; // Convert from seconds to 2-second units.
+ valOK = TRUE;
+ }
+ }
+ else {
+ // unmatched item, fail
+ AVB_LOGF_ERROR("Unrecognized configuration item: section=%s, name=%s", section, name);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return 0;
+ }
+ }
+ else if (MATCH(section, "descriptor_entity"))
+ {
+ if (MATCH(name, "avdeccId")) {
+ errno = 0;
+ pCfg->avdeccId = strtoul(value, &pEnd, 0);
+ if (*pEnd == '\0' && errno == 0)
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "entity_model_id")) {
+ errno = 0;
+ U64 nTemp = strtoull(value, &pEnd, 0);
+ if (*pEnd == '\0' && errno == 0) {
+ valOK = TRUE;
+ int i;
+ for (i = 7; i >= 0; --i) {
+ pCfg->entity_model_id[i] = (U8) (nTemp & 0xFF);
+ nTemp = (nTemp >> 8);
+ }
+ AVB_LOGF_DEBUG("entity_model_id = " ENTITYID_FORMAT, ENTITYID_ARGS(pCfg->entity_model_id));
+ }
+ }
+ else if (MATCH(name, "entity_name"))
+ {
+ strncpy(pCfg->entity_name, value, sizeof(pCfg->entity_name));
+ // String does not need to be 0-terminated.
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "firmware_version"))
+ {
+ strncpy(pCfg->firmware_version, value, sizeof(pCfg->firmware_version));
+ // String does not need to be 0-terminated.
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "group_name"))
+ {
+ strncpy(pCfg->group_name, value, sizeof(pCfg->group_name));
+ // String does not need to be 0-terminated.
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "serial_number"))
+ {
+ strncpy(pCfg->serial_number, value, sizeof(pCfg->serial_number));
+ // String does not need to be 0-terminated.
+ valOK = TRUE;
+ }
+ else {
+ // unmatched item, fail
+ AVB_LOGF_ERROR("Unrecognized configuration item: section=%s, name=%s", section, name);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return 0;
+ }
+ }
+ else if (MATCH(section, "localization"))
+ {
+ if (MATCH(name, "locale_identifier"))
+ {
+ strncpy(pCfg->locale_identifier, value, sizeof(pCfg->locale_identifier));
+ // String does not need to be 0-terminated.
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "vendor_name"))
+ {
+ strncpy(pCfg->vendor_name, value, sizeof(pCfg->vendor_name));
+ // String does not need to be 0-terminated.
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "model_name"))
+ {
+ strncpy(pCfg->model_name, value, sizeof(pCfg->model_name));
+ // String does not need to be 0-terminated.
+ valOK = TRUE;
+ }
+ else {
+ // unmatched item, fail
+ AVB_LOGF_ERROR("Unrecognized configuration item: section=%s, name=%s", section, name);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return 0;
+ }
+ }
+ else {
+ // unmatched item, fail
+ AVB_LOGF_ERROR("Unrecognized configuration item: section=%s, name=%s", section, name);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return 0;
+ }
+
+ if (!valOK) {
+ cfgValErr(section, name, value);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return 1; // OK
+}
+
+// Parse ini file, and create config data
+//
+int openavbReadAvdeccConfig(const char *ini_file, openavb_avdecc_cfg_t *pCfg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ // defaults - most are handled by setting everything to 0
+ memset(pCfg, 0, sizeof(openavb_avdecc_cfg_t));
+ pCfg->valid_time = 31; // See IEEE Std 1722.1-2013 clause 6.2.1.6
+ pCfg->avdeccId = 0xfffe;
+
+ int result = ini_parse(ini_file, cfgCallback, pCfg);
+ if (result < 0) {
+ AVB_LOGF_ERROR("Couldn't parse INI file: %s", ini_file);
+ return -1;
+ }
+ if (result > 0) {
+ AVB_LOGF_ERROR("Error in INI file: %s, line %d", ini_file, result);
+ return -1;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+
+ // Yay, we did it.
+ return 0;
+}
+
+// Clean up any configuration-related stuff
+//
+void openavbAvdeccUnconfigure(openavb_avdecc_cfg_t *pCfg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+}
diff --git a/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_cfg.h b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_cfg.h
new file mode 100644
index 00000000..5de0dab1
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_cfg.h
@@ -0,0 +1,50 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+* HEADER SUMMARY : Declarations used by the endpoint configuration
+*
+* Defines the endpoint configuration data, and the functions
+* to read the configuration data.
+*/
+
+#ifndef AVB_ENDPOINT_AVDECC_CONFIG_H
+#define AVB_ENDPOINT_AVDECC_CONFIG_H
+
+#include "openavb_types.h"
+#include "openavb_avdecc_pub.h"
+
+#define DEFAULT_AVDECC_INI_FILE "avdecc.ini"
+
+int openavbReadAvdeccConfig(const char *inifile, openavb_avdecc_cfg_t *pCfg);
+void openavbAvdeccUnconfigure(openavb_avdecc_cfg_t *pCfg);
+
+#endif // AVB_ENDPOINT_AVDECC_CONFIG_H
diff --git a/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_osal.c b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_osal.c
new file mode 100644
index 00000000..2e097548
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_osal.c
@@ -0,0 +1,203 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include "openavb_platform.h"
+#include "openavb_trace.h"
+#include "openavb_avdecc_cfg.h"
+#include "openavb_avdecc_read_ini_pub.h"
+#include "openavb_avdecc_msg.h"
+#include "openavb_list.h"
+
+#define AVB_LOG_COMPONENT "AVDECC"
+
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+// the following are from openavb_avdecc.c
+extern openavb_avdecc_cfg_t gAvdeccCfg;
+extern openavb_tl_data_cfg_t * streamList;
+extern bool avdeccRunning;
+
+static pthread_t avdeccServerHandle;
+static void* avdeccServerThread(void *arg);
+
+static bool avdeccInitSucceeded;
+
+bool startAvdecc(const char* ifname, const char **inifiles, int numfiles)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+ LOG_EAVB_CORE_VERSION();
+
+ // Ensure that we're running as root
+ // (need to be root to use raw sockets)
+ uid_t euid = geteuid();
+ if (euid != (uid_t)0) {
+ fprintf(stderr, "Error: needs to run as root\n\n");
+ goto error;
+ }
+
+ // Get the AVDECC configuration
+ memset(&gAvdeccCfg, 0, sizeof(openavb_avdecc_cfg_t));
+ openavbReadAvdeccConfig(DEFAULT_AVDECC_INI_FILE, &gAvdeccCfg);
+
+ // Determine which interface to use.
+ if (ifname) {
+ strncpy(gAvdeccCfg.ifname, ifname, sizeof(gAvdeccCfg.ifname));
+ } else if (gAvdeccCfg.ifname[0] == '\0') {
+ AVB_LOG_ERROR("No interface specified. Use the -I flag, or add one to " DEFAULT_AVDECC_INI_FILE ".");
+ goto error;
+ }
+
+ // Read the information from the supplied INI files.
+ openavb_tl_data_cfg_t * prevStream = NULL, * newStream;
+ U32 i1;
+ for (i1 = 0; i1 < numfiles; i1++) {
+
+ char iniFile[1024];
+ snprintf(iniFile, sizeof(iniFile), "%s", inifiles[i1]);
+ // Create a new item with this INI information.
+ newStream = malloc(sizeof(openavb_tl_data_cfg_t));
+ if (!newStream) {
+ AVB_LOG_ERROR("Out of memory");
+ goto error;
+ }
+ memset(newStream, 0, sizeof(openavb_tl_data_cfg_t));
+ if (!openavbReadTlDataIniFile(iniFile, newStream)) {
+ AVB_LOGF_ERROR("Error reading ini file: %s", inifiles[i1]);
+ goto error;
+ }
+ // Append this item to the list of items.
+ if (!prevStream) {
+ // First item.
+ streamList = newStream;
+ } else {
+ // Subsequent item.
+ prevStream->next = newStream;
+ }
+ prevStream = newStream;
+ }
+
+ /* Run AVDECC in its own thread. */
+ avdeccRunning = TRUE;
+ avdeccInitSucceeded = FALSE;
+ int err = pthread_create(&avdeccServerHandle, NULL, avdeccServerThread, NULL);
+ if (err) {
+ AVB_LOGF_ERROR("Failed to start AVDECC thread: %s", strerror(err));
+ goto error;
+ }
+
+ /* Wait a while to see if the thread was able to start AVDECC. */
+ int i;
+ for (i = 0; avdeccRunning && !avdeccInitSucceeded && i < 5000; ++i) {
+ SLEEP_MSEC(1);
+ }
+ if (!avdeccInitSucceeded) {
+ goto error;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return true;
+
+error:
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+}
+
+void stopAvdecc()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ avdeccRunning = FALSE;
+ pthread_join(avdeccServerHandle, NULL);
+
+ AVB_LOG_INFO("Shutting down");
+
+ // Free the INI file items.
+ while (streamList) {
+ openavb_tl_data_cfg_t * del = streamList;
+ streamList = streamList->next;
+ free(del);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+}
+
+static void* avdeccServerThread(void *arg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ while (avdeccRunning) {
+ if (!openavbAvdeccInitialize()) {
+ AVB_LOG_ERROR("Failed to initialize AVDECC");
+ break;
+ }
+
+ AVB_LOG_DEBUG("AVDECC Initialized");
+
+ if (!openavbAvdeccStart()) {
+ AVB_LOG_ERROR("Failed to start AVDECC");
+ openavbAvdeccStop();
+ break;
+ }
+
+ if (!openavbAvdeccMsgServerOpen()) {
+ AVB_LOG_ERROR("Failed to start AVDECC Server");
+ openavbAvdeccStop();
+ break;
+ }
+ else {
+ AVB_LOG_INFO("AVDECC Started");
+ avdeccInitSucceeded = TRUE;
+
+ // Wait until AVDECC is finished.
+ while (avdeccRunning) {
+ openavbAvdeccMsgSrvrService();
+ }
+
+ openavbAvdeccMsgServerClose();
+ }
+
+ // Stop AVDECC
+ AVB_LOG_DEBUG("AVDECC Stopping");
+ openavbAvdeccStop();
+ AVB_LOG_INFO("AVDECC Stopped");
+ }
+
+ // Shutdown AVDECC
+ openavbAvdeccCleanup();
+
+ avdeccRunning = FALSE;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return NULL;
+}
diff --git a/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_osal.h b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_osal.h
new file mode 100644
index 00000000..b52f99b1
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_osal.h
@@ -0,0 +1,45 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#ifndef OSAL_AVDECC_H
+#define OSAL_AVDECC_H
+
+// should only be included from openavb_avdecc.h
+
+#include <linux/un.h>
+#include <net/if.h>
+#include <unistd.h>
+#include <signal.h>
+
+bool startAvdecc(const char* ifname, const char *inifiles[], int numfiles);
+void stopAvdecc();
+
+#endif // OSAL_AVDECC_H
diff --git a/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_pipeline_interaction.c b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_pipeline_interaction.c
new file mode 100644
index 00000000..5e6a5051
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_pipeline_interaction.c
@@ -0,0 +1,513 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#define AVB_LOG_COMPONENT "AVDECC"
+#include "openavb_log.h"
+#include "openavb_trace_pub.h"
+
+#include "openavb_aem_types_pub.h"
+#include "openavb_avdecc_pipeline_interaction_pub.h"
+#include "openavb_avdecc_msg_server.h"
+
+
+bool openavbAVDECCRunListener(openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput, U16 configIdx, openavb_acmp_ListenerStreamInfo_t *pListenerStreamInfo)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ // Sanity tests.
+ if (!pDescriptorStreamInput) {
+ AVB_LOG_ERROR("openavbAVDECCRunListener Invalid descriptor");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pListenerStreamInfo) {
+ AVB_LOG_ERROR("openavbAVDECCRunListener Invalid streaminfo");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pDescriptorStreamInput->stream) {
+ AVB_LOG_ERROR("openavbAVDECCRunListener Invalid StreamInput descriptor stream");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pDescriptorStreamInput->stream->client) {
+ AVB_LOG_ERROR("openavbAVDECCRunListener Invalid stream client pointer");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ // Send the Stream ID to the client.
+ // The client will stop a running Listener if the settings differ from its current values.
+ if (!openavbAvdeccMsgSrvrListenerStreamID(pDescriptorStreamInput->stream->client->avdeccMsgHandle,
+ ((pListenerStreamInfo->flags & OPENAVB_ACMP_FLAG_CLASS_B) != 0 ? SR_CLASS_B : SR_CLASS_A),
+ pListenerStreamInfo->stream_id, /* The first 6 bytes of the steam_id are the source MAC Address */
+ (((U16) pListenerStreamInfo->stream_id[6]) << 8 | (U16) pListenerStreamInfo->stream_id[7]),
+ pListenerStreamInfo->stream_dest_mac,
+ pListenerStreamInfo->stream_vlan_id)) {
+ AVB_LOG_ERROR("Error send Stream ID to Listener");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ // Tell the client to start running.
+ if (!openavbAvdeccMsgSrvrChangeRequest(pDescriptorStreamInput->stream->client->avdeccMsgHandle, OPENAVB_AVDECC_MSG_RUNNING)) {
+ AVB_LOG_ERROR("Error requesting Listener change to Running");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ AVB_LOG_INFO("Listener state change to Running requested");
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return TRUE;
+}
+
+bool openavbAVDECCRunTalker(openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput, U16 configIdx, openavb_acmp_TalkerStreamInfo_t *pTalkerStreamInfo)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ // Sanity tests.
+ if (!pDescriptorStreamOutput) {
+ AVB_LOG_ERROR("openavbAVDECCRunTalker Invalid descriptor");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pTalkerStreamInfo) {
+ AVB_LOG_ERROR("openavbAVDECCRunTalker Invalid streaminfo");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pDescriptorStreamOutput->stream) {
+ AVB_LOG_ERROR("openavbAVDECCRunTalker Invalid StreamInput descriptor stream");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pDescriptorStreamOutput->stream->client) {
+ AVB_LOG_ERROR("openavbAVDECCRunTalker Invalid stream client pointer");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ // Tell the client to start running.
+ // Note that that Talker may already be running; this call ensures that it really is.
+ if (!openavbAvdeccMsgSrvrChangeRequest(pDescriptorStreamOutput->stream->client->avdeccMsgHandle, OPENAVB_AVDECC_MSG_RUNNING)) {
+ AVB_LOG_ERROR("Error requesting Talker change to Running");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ AVB_LOG_INFO("Talker state change to Running requested");
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return TRUE;
+}
+
+bool openavbAVDECCStopListener(openavb_aem_descriptor_stream_io_t *pDescriptorStreamInput, U16 configIdx, openavb_acmp_ListenerStreamInfo_t *pListenerStreamInfo)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ // Sanity tests.
+ if (!pDescriptorStreamInput) {
+ AVB_LOG_ERROR("openavbAVDECCStopListener Invalid descriptor");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pListenerStreamInfo) {
+ AVB_LOG_ERROR("openavbAVDECCStopListener Invalid streaminfo");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pDescriptorStreamInput->stream) {
+ AVB_LOG_ERROR("openavbAVDECCStopListener Invalid StreamInput descriptor stream");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pDescriptorStreamInput->stream->client) {
+ AVB_LOG_ERROR("openavbAVDECCStopListener Invalid stream client pointer");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ // Don't request if already stopped.
+ if (pDescriptorStreamInput->stream->client->lastReportedState == OPENAVB_AVDECC_MSG_STOPPED) {
+ AVB_LOG_INFO("Listener state change to Stopped ignored, as Listener already Stopped");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return TRUE;
+ }
+
+ // Send the request to the client.
+ if (!openavbAvdeccMsgSrvrChangeRequest(pDescriptorStreamInput->stream->client->avdeccMsgHandle, OPENAVB_AVDECC_MSG_STOPPED)) {
+ AVB_LOG_ERROR("Error requesting Listener change to Stopped");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ AVB_LOG_INFO("Listener state change to Stopped requested");
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return TRUE;
+}
+
+bool openavbAVDECCStopTalker(openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput, U16 configIdx, openavb_acmp_TalkerStreamInfo_t *pTalkerStreamInfo)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ // Sanity tests.
+ if (!pDescriptorStreamOutput) {
+ AVB_LOG_ERROR("openavbAVDECCStopTalker Invalid descriptor");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pTalkerStreamInfo) {
+ AVB_LOG_ERROR("openavbAVDECCStopTalker Invalid streaminfo");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pDescriptorStreamOutput->stream) {
+ AVB_LOG_ERROR("openavbAVDECCStopTalker Invalid StreamInput descriptor stream");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pDescriptorStreamOutput->stream->client) {
+ AVB_LOG_ERROR("openavbAVDECCStopTalker Invalid stream client pointer");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ // Don't request if already stopped.
+ if (pDescriptorStreamOutput->stream->client->lastReportedState == OPENAVB_AVDECC_MSG_STOPPED) {
+ AVB_LOG_INFO("Talker state change to Stopped ignored, as Talker already Stopped");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return TRUE;
+ }
+
+ // Send the request to the client.
+ if (!openavbAvdeccMsgSrvrChangeRequest(pDescriptorStreamOutput->stream->client->avdeccMsgHandle, OPENAVB_AVDECC_MSG_STOPPED)) {
+ AVB_LOG_ERROR("Error requesting Talker change to Stopped");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ AVB_LOG_INFO("Talker state change to Stopped requested");
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return TRUE;
+}
+
+bool openavbAVDECCGetTalkerStreamInfo(openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput, U16 configIdx, openavb_acmp_TalkerStreamInfo_t *pTalkerStreamInfo)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ // Sanity tests.
+ if (!pDescriptorStreamOutput) {
+ AVB_LOG_ERROR("openavbAVDECCGetTalkerStreamInfo Invalid descriptor");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pTalkerStreamInfo) {
+ AVB_LOG_ERROR("openavbAVDECCGetTalkerStreamInfo Invalid streaminfo");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pDescriptorStreamOutput->stream) {
+ AVB_LOG_ERROR("openavbAVDECCGetTalkerStreamInfo Invalid StreamInput descriptor stream");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ // Get the destination MAC Address.
+ if (!pDescriptorStreamOutput->stream->dest_addr.mac ||
+ memcmp(pDescriptorStreamOutput->stream->dest_addr.buffer.ether_addr_octet, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0) {
+ AVB_LOG_DEBUG("openavbAVDECCGetTalkerStreamInfo Invalid stream dest_addr");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ memcpy(pTalkerStreamInfo->stream_dest_mac, pDescriptorStreamOutput->stream->dest_addr.mac, ETH_ALEN);
+ AVB_LOGF_DEBUG("Talker stream_dest_mac: " ETH_FORMAT,
+ ETH_OCTETS(pTalkerStreamInfo->stream_dest_mac));
+
+ // Get the Stream ID.
+ if (!pDescriptorStreamOutput->stream->stream_addr.mac ||
+ memcmp(pDescriptorStreamOutput->stream->stream_addr.buffer.ether_addr_octet, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0) {
+ AVB_LOG_ERROR("openavbAVDECCGetTalkerStreamInfo Invalid stream stream_addr");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ memcpy(pTalkerStreamInfo->stream_id, pDescriptorStreamOutput->stream->stream_addr.mac, ETH_ALEN);
+ U8 *pStreamUID = pTalkerStreamInfo->stream_id + 6;
+ *(U16 *)(pStreamUID) = htons(pDescriptorStreamOutput->stream->stream_uid);
+ AVB_LOGF_DEBUG("Talker stream_id: " ETH_FORMAT "/%u",
+ ETH_OCTETS(pTalkerStreamInfo->stream_id),
+ (((U16) pTalkerStreamInfo->stream_id[6]) << 8) | (U16) pTalkerStreamInfo->stream_id[7]);
+
+ // Get the VLAN ID.
+ pTalkerStreamInfo->stream_vlan_id = pDescriptorStreamOutput->stream->vlan_id;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return TRUE;
+}
+
+bool openavbAVDECCSetTalkerStreamInfo(openavb_aem_descriptor_stream_io_t *pDescriptorStreamOutput,
+ U8 sr_class, U8 stream_id_valid, const U8 stream_src_mac[6], U16 stream_uid, U8 stream_dest_valid, const U8 stream_dest_mac[6], U8 stream_vlan_id_valid, U16 stream_vlan_id)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ // Sanity tests.
+ if (!pDescriptorStreamOutput) {
+ AVB_LOG_ERROR("openavbAVDECCSetTalkerStreamInfo Invalid descriptor");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pDescriptorStreamOutput->stream) {
+ AVB_LOG_ERROR("openavbAVDECCSetTalkerStreamInfo Invalid StreamInput descriptor stream");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (!pDescriptorStreamOutput->stream->client) {
+ AVB_LOG_ERROR("openavbAVDECCSetTalkerStreamInfo Invalid stream client pointer");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ // Send the information to the client.
+ if (!openavbAvdeccMsgSrvrTalkerStreamID(pDescriptorStreamOutput->stream->client->avdeccMsgHandle,
+ sr_class, stream_id_valid, stream_src_mac, stream_uid, stream_dest_valid, stream_dest_mac, stream_vlan_id_valid, stream_vlan_id)) {
+ AVB_LOG_ERROR("Error sending stream info updates to Talker");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return TRUE;
+}
+
+openavbAvdeccMsgStateType_t openavbAVDECCGetRequestedState(openavb_aem_descriptor_stream_io_t *pDescriptorStream, U16 configIdx)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ // Sanity tests.
+ if (!pDescriptorStream) {
+ AVB_LOG_ERROR("openavbAVDECCGetRequestedState Invalid descriptor");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return OPENAVB_AVDECC_MSG_UNKNOWN;
+ }
+ if (!pDescriptorStream->stream) {
+ AVB_LOG_ERROR("openavbAVDECCGetRequestedState Invalid descriptor stream");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return OPENAVB_AVDECC_MSG_UNKNOWN;
+ }
+ if (!pDescriptorStream->stream->client) {
+ AVB_LOG_DEBUG("openavbAVDECCGetRequestedState Invalid stream client pointer");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return OPENAVB_AVDECC_MSG_UNKNOWN;
+ }
+
+ // Return the current state.
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return pDescriptorStream->stream->client->lastRequestedState;
+}
+
+openavbAvdeccMsgStateType_t openavbAVDECCGetStreamingState(openavb_aem_descriptor_stream_io_t *pDescriptorStream, U16 configIdx)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ // Sanity tests.
+ if (!pDescriptorStream) {
+ AVB_LOG_ERROR("openavbAVDECCGetStreamingState Invalid descriptor");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return OPENAVB_AVDECC_MSG_UNKNOWN;
+ }
+ if (!pDescriptorStream->stream) {
+ AVB_LOG_ERROR("openavbAVDECCGetStreamingState Invalid descriptor stream");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return OPENAVB_AVDECC_MSG_UNKNOWN;
+ }
+ if (!pDescriptorStream->stream->client) {
+ AVB_LOG_DEBUG("openavbAVDECCGetStreamingState Invalid stream client pointer");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return OPENAVB_AVDECC_MSG_UNKNOWN;
+ }
+
+ // Return the current state.
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return pDescriptorStream->stream->client->lastReportedState;
+}
+
+void openavbAVDECCPauseStream(openavb_aem_descriptor_stream_io_t *pDescriptor, bool bPause)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ // Sanity test.
+ if (!pDescriptor) {
+ AVB_LOG_ERROR("openavbAVDECCPauseStream Invalid descriptor");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return;
+ }
+ if (!pDescriptor->stream) {
+ AVB_LOG_ERROR("openavbAVDECCPauseStream Invalid StreamInput descriptor stream");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return;
+ }
+ if (!pDescriptor->stream->client) {
+ AVB_LOG_ERROR("openavbAVDECCPauseStream Invalid stream client pointer");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return;
+ }
+
+ if (pDescriptor->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT) {
+
+ if (bPause) {
+ // If the client is not running (or already paused), ignore this command.
+ if (pDescriptor->stream->client->lastReportedState != OPENAVB_AVDECC_MSG_RUNNING) {
+ AVB_LOG_DEBUG("Listener state change to pause ignored, as Listener not running");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return;
+ }
+
+ // Send the request to the client.
+ if (!openavbAvdeccMsgSrvrChangeRequest(pDescriptor->stream->client->avdeccMsgHandle, OPENAVB_AVDECC_MSG_PAUSED)) {
+ AVB_LOG_ERROR("Error requesting Listener change to Paused");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return;
+ }
+
+ AVB_LOG_INFO("Listener state change from Running to Paused requested");
+ }
+ else {
+ // If the client is not paused, ignore this command.
+ if (pDescriptor->stream->client->lastReportedState != OPENAVB_AVDECC_MSG_PAUSED) {
+ AVB_LOG_DEBUG("Listener state change to pause ignored, as Listener not paused");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return;
+ }
+
+ // Send the request to the client.
+ if (!openavbAvdeccMsgSrvrChangeRequest(pDescriptor->stream->client->avdeccMsgHandle, OPENAVB_AVDECC_MSG_RUNNING)) {
+ AVB_LOG_ERROR("Error requesting Listener change to Running");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return;
+ }
+
+ AVB_LOG_INFO("Listener state change from Paused to Running requested");
+ }
+ }
+ else if (pDescriptor->descriptor_type == OPENAVB_AEM_DESCRIPTOR_STREAM_OUTPUT) {
+
+ if (bPause) {
+ // If the client is not running (or already paused), ignore this command.
+ if (pDescriptor->stream->client->lastReportedState != OPENAVB_AVDECC_MSG_RUNNING) {
+ AVB_LOG_DEBUG("Talker state change to pause ignored, as Talker not running");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return;
+ }
+
+ // Send the request to the client.
+ if (!openavbAvdeccMsgSrvrChangeRequest(pDescriptor->stream->client->avdeccMsgHandle, OPENAVB_AVDECC_MSG_PAUSED)) {
+ AVB_LOG_ERROR("Error requesting Talker change to Paused");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return;
+ }
+
+ AVB_LOG_INFO("Talker state change from Running to Paused requested");
+ }
+ else {
+ // If the client is not paused, ignore this command.
+ if (pDescriptor->stream->client->lastReportedState != OPENAVB_AVDECC_MSG_PAUSED) {
+ AVB_LOG_DEBUG("Talker state change to pause ignored, as Talker not paused");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return;
+ }
+
+ // Send the request to the client.
+ if (!openavbAvdeccMsgSrvrChangeRequest(pDescriptor->stream->client->avdeccMsgHandle, OPENAVB_AVDECC_MSG_RUNNING)) {
+ AVB_LOG_ERROR("Error requesting Talker change to Running");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return;
+ }
+
+ AVB_LOG_INFO("Talker state change from Paused to Running requested");
+ }
+ }
+ else {
+ AVB_LOG_ERROR("openavbAVDECCPauseStream unsupported descriptor");
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+}
+
+// Get the current counter value in pValue. Returns TRUE if the counter is supported, FALSE otherwise.
+bool openavbAVDECCGetCounterValue(void *pDescriptor, U16 descriptorType, U32 counterFlag, U32 *pValue)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ if (!pDescriptor) {
+ /* Asked for a non-existing descriptor. */
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ switch (descriptorType) {
+ case OPENAVB_AEM_DESCRIPTOR_ENTITY:
+ // The only counters are entity-specific.
+ break;
+
+ case OPENAVB_AEM_DESCRIPTOR_AVB_INTERFACE:
+ // AVDECC_TODO - Get the LINK_UP, LINK_DOWN, FRAMES_TX, FRAMES_RX, RX_CRC_ERROR. and GPTP_GM_CHANGED counts from the gPTP daemon.
+ break;
+
+ case OPENAVB_AEM_DESCRIPTOR_CLOCK_DOMAIN:
+ {
+ switch (counterFlag) {
+ case OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_LOCKED:
+ AVB_LOG_ERROR("OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_LOCKED Not Implemented!");
+ if (pValue) { *pValue = 1; }
+ return TRUE;
+
+ case OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_UNLOCKED:
+ AVB_LOG_ERROR("OPENAVB_AEM_GET_COUNTERS_COMMAND_CLOCK_DOMAIN_COUNTER_UNLOCKED Not Implemented!");
+ if (pValue) { *pValue = 1; }
+ return TRUE;
+
+ default:
+ break;
+ }
+ break;
+ }
+
+ case OPENAVB_AEM_DESCRIPTOR_STREAM_INPUT:
+ // AVDECC_TODO - Get the MEDIA_LOCKED, MEDIA_UNLOCKED, STREAM_RESET, SEQ_NUM_MISMATCH, MEDIA_RESET,
+ // TIMESTAMP_UNCERTAIN, TIMESTAMP_VALID, TIMESTAMP_NOT_VALID, UNSUPPORTED_FORMAT,
+ // LATE_TIMESTAMP, EARLY_TIMESTAMP, FRAMES_RX, and FRAMES_TX counts.
+ break;
+
+ default:
+ break;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+}
diff --git a/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_read_ini.c b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_read_ini.c
new file mode 100644
index 00000000..06c8b280
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_read_ini.c
@@ -0,0 +1,620 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "ini.h"
+
+#include "openavb_platform.h"
+#include "openavb_trace.h"
+#include "openavb_audio_pub.h"
+#include "openavb_avdecc_pub.h"
+#include "openavb_avdecc_read_ini_pub.h"
+#include "openavb_avdecc_save_state.h"
+
+#define AVB_LOG_COMPONENT "TL INI"
+#include "openavb_log.h"
+
+#define MATCH(A, B)(strcasecmp((A), (B)) == 0)
+#define MATCH_LEFT(A, B, C)(strncasecmp((A), (B), (C)) == 0)
+
+extern openavb_avdecc_cfg_t gAvdeccCfg;
+
+static bool parse_mac(const char *str, cfg_mac_t *mac)
+{
+ memset(&mac->buffer, 0, sizeof(struct ether_addr));
+
+ mac->mac = ether_aton_r(str, &mac->buffer);
+ if (mac->mac)
+ return TRUE;
+
+ AVB_LOGF_ERROR("Failed to parse addr: %s", str);
+ return FALSE;
+}
+
+static void openavbIniCfgInit(openavb_tl_data_cfg_t *pCfg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ memset(pCfg, 0, sizeof(openavb_tl_data_cfg_t));
+
+ // Set default values.
+ // (These values should match those set in openavbTLInitCfg().)
+ pCfg->role = AVB_ROLE_UNDEFINED;
+ pCfg->initial_state = TL_INIT_STATE_UNSPECIFIED;
+ pCfg->stream_uid = 0xFFFF;
+ pCfg->max_interval_frames = 1;
+ pCfg->max_frame_size = 1500;
+ pCfg->max_transit_usec = 50000;
+ pCfg->max_transmit_deficit_usec = 50000;
+ pCfg->internal_latency = 0;
+ pCfg->max_stale = MICROSECONDS_PER_SECOND;
+ pCfg->batch_factor = 1;
+ pCfg->report_seconds = 0;
+ pCfg->start_paused = FALSE;
+ pCfg->sr_class = SR_CLASS_B;
+ pCfg->sr_rank = SR_RANK_REGULAR;
+ pCfg->raw_tx_buffers = 8;
+ pCfg->raw_rx_buffers = 100;
+ pCfg->tx_blocking_in_intf = 0;
+ pCfg->rx_signal_mode = 1;
+ pCfg->vlan_id = 0xFFFF;
+ pCfg->fixed_timestamp = 0;
+ pCfg->spin_wait = FALSE;
+ pCfg->thread_rt_priority = 0;
+ pCfg->thread_affinity = 0xFFFFFFFF;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+}
+
+// callback function - called for each name/value pair by ini parsing library
+static int openavbIniCfgCallback(void *user, const char *tlSection, const char *name, const char *value)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ openavb_tl_data_cfg_t *pCfg = (openavb_tl_data_cfg_t *)user;
+
+ AVB_LOGF_DEBUG("name=[%s] value=[%s]", name, value);
+
+ bool valOK = FALSE;
+ char *pEnd;
+
+ if (MATCH(name, "role")) {
+ if (MATCH(value, "talker")) {
+ pCfg->role = AVB_ROLE_TALKER;
+ valOK = TRUE;
+ }
+ else if (MATCH(value, "listener")) {
+ pCfg->role = AVB_ROLE_LISTENER;
+ valOK = TRUE;
+ }
+ }
+ else if (MATCH(name, "initial_state")) {
+ if (MATCH(value, "running")) {
+ pCfg->initial_state = TL_INIT_STATE_RUNNING;
+ valOK = TRUE;
+ }
+ else if (MATCH(value, "stopped")) {
+ pCfg->initial_state = TL_INIT_STATE_STOPPED;
+ valOK = TRUE;
+ }
+ }
+ else if (MATCH(name, "dest_addr")) {
+ valOK = parse_mac(value, &pCfg->dest_addr);
+ }
+ else if (MATCH(name, "stream_addr")) {
+ valOK = parse_mac(value, &pCfg->stream_addr);
+ }
+ else if (MATCH(name, "stream_uid")) {
+ errno = 0;
+ pCfg->stream_uid = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0
+ && pCfg->stream_uid <= UINT16_MAX)
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "max_interval_frames")) {
+ errno = 0;
+ pCfg->max_interval_frames = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0
+ && pCfg->max_interval_frames <= UINT16_MAX)
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "max_frame_size")) {
+ errno = 0;
+ pCfg->max_frame_size = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0
+ && pCfg->max_interval_frames <= UINT16_MAX)
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "sr_class")) {
+ if (strlen(value) == 1) {
+ if (tolower(value[0]) == 'a') {
+ pCfg->sr_class = SR_CLASS_A;
+ valOK = TRUE;
+ }
+ else if (tolower(value[0]) == 'b') {
+ pCfg->sr_class = SR_CLASS_B;
+ valOK = TRUE;
+ }
+ }
+ }
+ else if (MATCH(name, "sr_rank")) {
+ if (strlen(value) == 1) {
+ if (value[0] == '1') {
+ pCfg->sr_rank = SR_RANK_REGULAR;
+ valOK = TRUE;
+ }
+ else if (value[0] == '0') {
+ pCfg->sr_rank = SR_RANK_EMERGENCY;
+ valOK = TRUE;
+ }
+ }
+ }
+ else if (MATCH(name, "max_transit_usec")) {
+ errno = 0;
+ pCfg->max_transit_usec = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0
+ && pCfg->max_transit_usec <= UINT32_MAX)
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "max_transmit_deficit_usec")) {
+ errno = 0;
+ pCfg->max_transmit_deficit_usec = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0
+ && pCfg->max_transmit_deficit_usec <= UINT32_MAX)
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "internal_latency")) {
+ errno = 0;
+ pCfg->internal_latency = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0
+ && pCfg->internal_latency <= UINT32_MAX)
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "batch_factor")) {
+ errno = 0;
+ pCfg->batch_factor = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0
+ && pCfg->batch_factor > 0
+ && pCfg->batch_factor <= INT32_MAX)
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "max_stale")) {
+ errno = 0;
+ pCfg->max_stale = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0
+ && pCfg->max_stale >= 0
+ && pCfg->max_stale <= INT32_MAX)
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "raw_tx_buffers")) {
+ errno = 0;
+ pCfg->raw_tx_buffers = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0
+ && pCfg->raw_tx_buffers <= UINT32_MAX)
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "raw_rx_buffers")) {
+ errno = 0;
+ pCfg->raw_rx_buffers = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0
+ && pCfg->raw_rx_buffers <= UINT32_MAX)
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "report_seconds")) {
+ errno = 0;
+ pCfg->report_seconds = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0
+ && (int)pCfg->report_seconds >= 0
+ && pCfg->report_seconds <= INT32_MAX)
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "start_paused")) {
+ // ignore this item - tl_host doesn't use it because
+ // it pauses before reading any of its streams.
+ errno = 0;
+ long tmp;
+ tmp = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0
+ && tmp >= 0
+ && tmp <= 1) {
+ pCfg->start_paused = (tmp == 1);
+ valOK = TRUE;
+ }
+ }
+ else if (MATCH(name, "vlan_id")) {
+ errno = 0;
+ long tmp;
+ tmp = strtol(value, &pEnd, 0);
+ // vlanID is 12 bit field
+ if (*pEnd == '\0' && errno == 0
+ && tmp >= 0x0
+ && tmp <= 0xFFF) {
+ pCfg->vlan_id = tmp;
+ valOK = TRUE;
+ }
+ }
+ else if (MATCH(name, "fixed_timestamp")) {
+ errno = 0;
+ long tmp;
+ tmp = strtol(value, &pEnd, 0);
+ if (*pEnd == '\0' && errno == 0) {
+ pCfg->fixed_timestamp = tmp;
+ valOK = TRUE;
+ }
+ }
+ else if (MATCH(name, "spin_wait")) {
+ errno = 0;
+ long tmp;
+ tmp = strtol(value, &pEnd, 0);
+ if (*pEnd == '\0' && errno == 0) {
+ pCfg->spin_wait = (tmp == 1);
+ valOK = TRUE;
+ }
+ }
+ else if (MATCH(name, "tx_blocking_in_intf")) {
+ errno = 0;
+ long tmp;
+ tmp = strtol(value, &pEnd, 0);
+ if (*pEnd == '\0' && errno == 0) {
+ pCfg->tx_blocking_in_intf = tmp;
+ valOK = TRUE;
+ }
+ }
+ else if (MATCH(name, "thread_rt_priority")) {
+ errno = 0;
+ long tmp;
+ tmp = strtol(value, &pEnd, 0);
+ if (*pEnd == '\0' && errno == 0) {
+ pCfg->thread_rt_priority = tmp;
+ valOK = TRUE;
+ }
+ }
+ else if (MATCH(name, "thread_affinity")) {
+ errno = 0;
+ unsigned long tmp;
+ tmp = strtoul(value, &pEnd, 0);
+ if (*pEnd == '\0' && errno == 0) {
+ pCfg->thread_affinity = tmp;
+ valOK = TRUE;
+ }
+ }
+
+ else if (MATCH(name, "friendly_name")) {
+ strncpy(pCfg->friendly_name, value, FRIENDLY_NAME_SIZE - 1);
+ valOK = TRUE;
+ }
+
+ else if (MATCH(name, "current_sampling_rate")) {
+ errno = 0;
+ pCfg->current_sampling_rate = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0
+ && pCfg->current_sampling_rate <= UINT32_MAX)
+ valOK = TRUE;
+ }
+ else if (MATCH(name, "sampling_rates")) {
+ errno = 0;
+ memset(pCfg->sampling_rates,0,sizeof(pCfg->sampling_rates));
+ char *rate, *copy;
+ copy = strdup(value);
+ rate = strtok(copy,",");
+ int i = 0,break_flag = 0;
+ while (rate != NULL )
+ {
+ pCfg->sampling_rates[i] = strtol(rate,&pEnd, 10);
+ if (*pEnd != '\0' || errno != 0
+ || pCfg->sampling_rates[i] > UINT32_MAX)
+ {
+ break_flag = 1;
+ break;
+ }
+ rate = strtok(NULL,",");
+ i++;
+ }
+ if (break_flag != 1)
+ {
+ valOK = TRUE;
+ pCfg->sampling_rates_count = i;
+ }
+ }
+ else if (strcmp(name, "intf_nv_audio_rate") == 0) {
+ long int val = strtol(value, &pEnd, 10);
+ if (val >= AVB_AUDIO_RATE_8KHZ && val <= AVB_AUDIO_RATE_192KHZ) {
+ pCfg->audioRate = val;
+ valOK = TRUE;
+ }
+ else {
+ AVB_LOG_ERROR("Invalid audio rate configured for intf_nv_audio_rate.");
+ pCfg->audioRate = AVB_AUDIO_RATE_44_1KHZ;
+ }
+ }
+ else if (strcmp(name, "intf_nv_audio_bit_depth") == 0) {
+ long int val = strtol(value, &pEnd, 10);
+ if (val >= AVB_AUDIO_BIT_DEPTH_1BIT && val <= AVB_AUDIO_BIT_DEPTH_64BIT) {
+ pCfg->audioBitDepth = val;
+ valOK = TRUE;
+ }
+ else {
+ AVB_LOG_ERROR("Invalid audio type configured for intf_nv_audio_bits.");
+ pCfg->audioBitDepth = AVB_AUDIO_BIT_DEPTH_24BIT;
+ }
+ }
+ else if (strcmp(name, "intf_nv_audio_channels") == 0) {
+ long int val = strtol(value, &pEnd, 10);
+ if (val >= AVB_AUDIO_CHANNELS_1 && val <= AVB_AUDIO_CHANNELS_8) {
+ pCfg->audioChannels = val;
+ valOK = TRUE;
+ }
+ else {
+ AVB_LOG_ERROR("Invalid audio channels configured for intf_nv_audio_channels.");
+ pCfg->audioChannels = AVB_AUDIO_CHANNELS_2;
+ }
+ }
+ else if (MATCH(name, "map_fn")) {
+ errno = 0;
+ memset(pCfg->map_fn,0,sizeof(pCfg->map_fn));
+ strncpy(pCfg->map_fn,value,sizeof(pCfg->map_fn)-1);
+ valOK = TRUE;
+ }
+
+ else {
+ // Ignored item.
+ AVB_LOGF_DEBUG("Unhandled configuration item: name=%s, value=%s", name, value);
+
+ // Don't abort for this item.
+ valOK = TRUE;
+ }
+
+ if (!valOK) {
+ // bad value
+ AVB_LOGF_ERROR("Invalid value: name=%s, value=%s", name, value);
+ return 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+
+ return 1; // OK
+}
+
+bool openavbReadTlDataIniFile(const char *fileName, openavb_tl_data_cfg_t *pCfg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ openavbIniCfgInit(pCfg);
+
+ // Use the .INI file name as the default friendly name.
+ strncpy(pCfg->friendly_name, fileName, FRIENDLY_NAME_SIZE - 1);
+ char * pszComma = strchr(pCfg->friendly_name, ',');
+ if (pszComma) {
+ // Get rid of anything following the file name.
+ *pszComma = '\0';
+ }
+ char * pszExtension = strrchr(pCfg->friendly_name, '.');
+ if (pszExtension && strcasecmp(pszExtension, ".ini") == 0) {
+ // Get rid of the .INI file extension.
+ *pszExtension = '\0';
+ }
+
+ int result = ini_parse(fileName, openavbIniCfgCallback, pCfg);
+ if (result < 0) {
+ AVB_LOGF_ERROR("Couldn't parse INI file: %s", fileName);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ if (result > 0) {
+ AVB_LOGF_ERROR("Error in INI file: %s, line %d", fileName, result);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ if (pCfg->current_sampling_rate != 0 && pCfg->audioRate != 0 &&
+ pCfg->current_sampling_rate != pCfg->audioRate)
+ {
+ AVB_LOGF_ERROR("current_sampling_rate(%u) and intf_nv_audio_rate(%u) do not match.", pCfg->current_sampling_rate, pCfg->audioRate);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+
+ if (pCfg->current_sampling_rate == 0)
+ {
+ /* Make sure we have a default sampling rate. */
+ if (pCfg->audioRate != 0) {
+ pCfg->current_sampling_rate = pCfg->audioRate;
+ } else if (pCfg->sampling_rates[0] != 0) {
+ pCfg->current_sampling_rate = pCfg->sampling_rates[0];
+ } else {
+ pCfg->current_sampling_rate = AVB_AUDIO_RATE_48KHZ;
+ }
+ if (pCfg->audioRate == 0) {
+ AVB_LOGF_WARNING("current_sampling_rate not specified in %s. Defaulting to %u", fileName, pCfg->current_sampling_rate);
+ }
+ }
+ if (pCfg->sampling_rates_count == 0)
+ {
+ /* Set the list of sampling rates to the current sampling rate. */
+ pCfg->sampling_rates[0] = pCfg->current_sampling_rate;
+ pCfg->sampling_rates_count = 1;
+ if (pCfg->audioRate == 0) {
+ AVB_LOGF_WARNING("sampling_rates not specified in %s. Defaulting to %u", fileName, pCfg->current_sampling_rate);
+ }
+ } else {
+ /* Make sure the current sampling rate is in the list of sampling rates. */
+ U16 i;
+ for (i = 0; i < pCfg->sampling_rates_count; ++i) {
+ if (pCfg->sampling_rates[i] == pCfg->current_sampling_rate) break;
+ }
+ if (i >= pCfg->sampling_rates_count) {
+ AVB_LOGF_ERROR("current_sampling_rate(%u) not in list of sampling_rates.", pCfg->current_sampling_rate);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return FALSE;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return TRUE;
+}
+
+
+// Save the connection to the saved state
+//
+bool openavbAvdeccSaveState(const openavb_tl_data_cfg_t *pListener, U16 flags, U16 talker_unique_id, const U8 talker_entity_id[8], const U8 controller_entity_id[8])
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ int i;
+
+ // Don't add to the saved state list if fast connect support is not enabled.
+ if (!gAvdeccCfg.bFastConnectSupported) {
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+
+ // If the supplied saved state matches one of the ones already saved, do nothing and return.
+ // If the Talker or Controller has changed, delete the old information.
+ for (i = 0; i < 1000; ++i) {
+ const openavb_saved_state_t * pTest = openavbAvdeccGetSavedState(i);
+ if (!pTest) {
+ break;
+ }
+
+ if (strcmp(pTest->listener_friendly_name, pListener->friendly_name) == 0) {
+ if (pTest->flags == flags &&
+ pTest->talker_unique_id == talker_unique_id &&
+ memcmp(pTest->talker_entity_id, talker_entity_id, 8) == 0 &&
+ memcmp(pTest->controller_entity_id, controller_entity_id, 8) == 0) {
+ // The supplied data is a match for the existing item. Do nothing.
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return true;
+ }
+
+ // Delete this item. We will create a new item with the updated information.
+ openavbAvdeccDeleteSavedState(i);
+ break;
+ }
+ }
+
+ // Add the supplied state to the list of states.
+ openavbAvdeccAddSavedState(pListener->friendly_name, flags, talker_unique_id, talker_entity_id, controller_entity_id);
+
+ AVB_LOGF_DEBUG("New saved state: listener_id=%s, flags=0x%04x, talker_unique_id=0x%04x, talker_entity_id=" ENTITYID_FORMAT ", controller_entity_id=" ENTITYID_FORMAT,
+ pListener->friendly_name,
+ flags,
+ talker_unique_id,
+ ENTITYID_ARGS(talker_entity_id),
+ ENTITYID_ARGS(controller_entity_id));
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return true;
+}
+
+// Delete a connection with saved state
+//
+bool openavbAvdeccClearSavedState(const openavb_tl_data_cfg_t *pListener)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ int i;
+
+ // Delete the saved state matching the supplied one.
+ // If the supplied saved state does not match any of the ones already saved, do nothing and return.
+ for (i = 0; i < 1000; ++i) {
+ const openavb_saved_state_t * pTest = openavbAvdeccGetSavedState(i);
+ if (!pTest) {
+ break;
+ }
+
+ if (strcmp(pTest->listener_friendly_name, pListener->friendly_name) == 0) {
+ // We found the index for the item to delete.
+ // Delete the item and save the updated file.
+ openavbAvdeccDeleteSavedState(i);
+ AVB_LOGF_DEBUG("Cleared saved state: listener_id=\"%s\"", pListener->friendly_name);
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return true;
+ }
+ }
+
+ AVB_LOGF_WARNING("Unable to find saved state to clear: listener_id=\"%s\"", pListener->friendly_name);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+}
+
+// Determine if the connection has a saved state
+//
+bool openavbAvdeccGetSaveStateInfo(const openavb_tl_data_cfg_t *pListener, U16 *p_flags, U16 *p_talker_unique_id, U8 (*p_talker_entity_id)[8], U8 (*p_controller_entity_id)[8])
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ int i;
+
+ // Don't return anything from the saved state list if fast connect support is not enabled.
+ if (!gAvdeccCfg.bFastConnectSupported) {
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+
+ // If the loaded saved state information matches the Listener supplied, return the information for it.
+ for (i = 0; i < 1000; ++i) {
+ const openavb_saved_state_t * pTest = openavbAvdeccGetSavedState(i);
+ if (!pTest) {
+ break;
+ }
+
+ if (strcmp(pTest->listener_friendly_name, pListener->friendly_name) == 0) {
+ AVB_LOGF_DEBUG("Saved state available for listener_id=%s, flags=0x%04x, talker_unique_id=0x%04x, talker_entity_id=" ENTITYID_FORMAT ", controller_entity_id=" ENTITYID_FORMAT,
+ pListener->friendly_name,
+ pTest->flags,
+ pTest->talker_unique_id,
+ ENTITYID_ARGS(pTest->talker_entity_id),
+ ENTITYID_ARGS(pTest->controller_entity_id));
+ if (p_flags) {
+ *p_flags = pTest->flags;
+ }
+ if (p_talker_unique_id) {
+ *p_talker_unique_id = pTest->talker_unique_id;
+ }
+ if (p_talker_entity_id) {
+ memcpy(*p_talker_entity_id, pTest->talker_entity_id, 8);
+ }
+ if (p_controller_entity_id) {
+ memcpy(*p_controller_entity_id, pTest->controller_entity_id, 8);
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return true;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+}
diff --git a/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_save_state.c b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_save_state.c
new file mode 100644
index 00000000..4287449b
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_save_state.c
@@ -0,0 +1,363 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+* MODULE SUMMARY : Support for ACMP saved state
+*/
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include "openavb_avdecc_cfg.h"
+#include "openavb_avdecc_save_state.h"
+#include "openavb_trace.h"
+
+#define AVB_LOG_COMPONENT "AVDECC Cfg"
+#include "openavb_log.h"
+
+#define MAX_SAVED_STATES 4
+static openavb_saved_state_t s_sSavedStateInfo[MAX_SAVED_STATES];
+static int s_nNumSavedStates = -1;
+
+
+static int get_hex_value(char c)
+{
+ if (c >= '0' && c <= '9') return ((int) c - (int) '0');
+ if (c >= 'A' && c <= 'F') return ((int) c - (int) 'A' + 10);
+ if (c >= 'a' && c <= 'f') return ((int) c - (int) 'a' + 10);
+ return -1;
+}
+
+static bool get_entity_id(const char *input, U8 output[8])
+{
+ int i;
+ for (i = 0; i < 8; ++i) {
+ // Get the hexadecimal number
+ int n1 = get_hex_value(*input++);
+ if (n1 < 0) return false;
+ int n2 = get_hex_value(*input++);
+ if (n2 < 0) return false;
+ output[i] = (U8) (n1 << 4 | n2);
+
+ // Verify the colon separator
+ if (i < 7) {
+ if (*input++ != ':') {
+ return false;
+ }
+ }
+ }
+
+ // Make sure anything trailing the Entity ID is not interesting.
+ return (*input == '\0' || isspace(*input));
+}
+
+static bool get_saved_state_info(const char *ini_file)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ FILE* file;
+ char temp_buffer[FRIENDLY_NAME_SIZE + 10];
+ long temp_int;
+ char *pEnd;
+
+ s_nNumSavedStates = -1;
+
+ char *pvtFilename = strdup(ini_file);
+ if (!pvtFilename) {
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+
+ s_nNumSavedStates = 0;
+
+ char *override = strchr(pvtFilename, ',');
+ if (override)
+ *override++ = '\0';
+
+ file = fopen(pvtFilename, "r");
+ if (!file) {
+ // No file to read. Ignore this error.
+ free(pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return true;
+ }
+
+ for (s_nNumSavedStates = 0; s_nNumSavedStates < MAX_SAVED_STATES; ++s_nNumSavedStates) {
+ // Extract the friendly name.
+ while (TRUE) {
+ if (fgets(temp_buffer, sizeof(temp_buffer), file) == NULL) {
+ if (!feof(file)) {
+ AVB_LOGF_ERROR("Error reading from INI file: %s", ini_file);
+ fclose(file);
+ free(pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+ fclose(file);
+ free(pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return true;
+ }
+
+ // Remove any white space from the end of the friendly name.
+ int length = strlen(temp_buffer);
+ while (length > 0 &&
+ (temp_buffer[length - 1] == '\r' ||
+ temp_buffer[length - 1] == '\n')) {
+ temp_buffer[--length] = '\0';
+ }
+ if (length <= 0) {
+ // Empty line. Ignore it.
+ continue;
+ }
+
+ // Successfully extracted the friendly name.
+ strncpy(s_sSavedStateInfo[s_nNumSavedStates].listener_friendly_name, temp_buffer, FRIENDLY_NAME_SIZE);
+ s_sSavedStateInfo[s_nNumSavedStates].listener_friendly_name[FRIENDLY_NAME_SIZE - 1] = '\0';
+ break;
+ }
+
+ // Extract the flags.
+ if (fgets(temp_buffer, sizeof(temp_buffer), file) == NULL) {
+ AVB_LOGF_ERROR("Error reading from INI file: %s", ini_file);
+ fclose(file);
+ free(pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+ errno = 0;
+ temp_int = strtol(temp_buffer, &pEnd, 10);
+ if (*pEnd != '\n' || errno != 0 || temp_int < 0 || temp_int > 0xFFFF) {
+ AVB_LOGF_ERROR("Error getting Flags from INI file: %s", ini_file);
+ fclose(file);
+ free(pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+ s_sSavedStateInfo[s_nNumSavedStates].flags = (U16) temp_int;
+
+ // Extract the talker_unique_id.
+ if (fgets(temp_buffer, sizeof(temp_buffer), file) == NULL) {
+ AVB_LOGF_ERROR("Error reading from INI file: %s", ini_file);
+ fclose(file);
+ free(pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+ errno = 0;
+ temp_int = strtol(temp_buffer, &pEnd, 10);
+ if (*pEnd != '\n' || errno != 0 || temp_int < 0 || temp_int > 0xFFFF) {
+ AVB_LOGF_ERROR("Error getting Talker Unique ID from INI file: %s", ini_file);
+ fclose(file);
+ free(pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+ s_sSavedStateInfo[s_nNumSavedStates].talker_unique_id = (U16) temp_int;
+
+ // Extract the Talker Entity ID.
+ if (fgets(temp_buffer, sizeof(temp_buffer), file) == NULL) {
+ AVB_LOGF_ERROR("Error reading from INI file: %s", ini_file);
+ fclose(file);
+ free(pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+ if (!get_entity_id(temp_buffer, s_sSavedStateInfo[s_nNumSavedStates].talker_entity_id)) {
+ AVB_LOGF_ERROR("Error getting Talker Entity ID from INI file: %s", ini_file);
+ fclose(file);
+ free(pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+
+ // Extract the Controller Entity ID.
+ if (fgets(temp_buffer, sizeof(temp_buffer), file) == NULL) {
+ AVB_LOGF_ERROR("Error reading from INI file: %s", ini_file);
+ fclose(file);
+ free(pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+ if (!get_entity_id(temp_buffer, s_sSavedStateInfo[s_nNumSavedStates].controller_entity_id)) {
+ AVB_LOGF_ERROR("Error getting Talker Entity ID from INI file: %s", ini_file);
+ fclose(file);
+ free(pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+
+ AVB_LOGF_DEBUG("Loaded saved state %d from file: listener_id=%s, talker_entity_id=" ENTITYID_FORMAT ", controller_entity_id=" ENTITYID_FORMAT,
+ s_nNumSavedStates,
+ s_sSavedStateInfo[s_nNumSavedStates].listener_friendly_name,
+ ENTITYID_ARGS(s_sSavedStateInfo[s_nNumSavedStates].talker_entity_id),
+ ENTITYID_ARGS(s_sSavedStateInfo[s_nNumSavedStates].controller_entity_id));
+ }
+
+ fclose(file);
+ free(pvtFilename);
+
+ AVB_LOGF_DEBUG("Extracted %d saved states from INI file: %s", s_nNumSavedStates, ini_file);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+
+ return true;
+}
+
+static bool write_saved_state_info(const char *ini_file)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC);
+
+ FILE* file;
+ int i;
+
+ char *pvtFilename = strdup(ini_file);
+ if (!pvtFilename) {
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+
+ char *override = strchr(pvtFilename, ',');
+ if (override)
+ *override++ = '\0';
+
+ file = fopen(pvtFilename, "w");
+ if (!file) {
+ AVB_LOGF_WARNING("Error saving to INI file: %s", ini_file);
+ free(pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+
+ for (i = 0; i < s_nNumSavedStates; ++i) {
+ if (fprintf(file, "%s\n%u\n%u\n" ENTITYID_FORMAT "\n" ENTITYID_FORMAT "\n\n",
+ s_sSavedStateInfo[i].listener_friendly_name,
+ s_sSavedStateInfo[i].flags,
+ s_sSavedStateInfo[i].talker_unique_id,
+ ENTITYID_ARGS(s_sSavedStateInfo[i].talker_entity_id),
+ ENTITYID_ARGS(s_sSavedStateInfo[i].controller_entity_id)) < 0) {
+ AVB_LOGF_ERROR("Error writing to INI file: %s", ini_file);
+ fclose(file);
+ free(pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+ return false;
+ }
+ }
+
+ fclose(file);
+ free(pvtFilename);
+
+ AVB_LOGF_DEBUG("Saved state to INI file: %s", ini_file);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC);
+
+ return true;
+}
+
+// Returns a pointer to the saved state information for the index supplied.
+// To use, start at index 0 and increment upward.
+// If NULL is returned, then no values for that or any higher indexes.
+const openavb_saved_state_t * openavbAvdeccGetSavedState(int index)
+{
+ // Load the file data, if needed.
+ if (s_nNumSavedStates < 0 && !get_saved_state_info(DEFAULT_AVDECC_SAVE_INI_FILE)) {
+ return NULL;
+ }
+
+ // Can we return a saved state for the requested index?
+ if (s_nNumSavedStates <= 0 || index >= s_nNumSavedStates) {
+ return NULL;
+ }
+
+ // Return the requested index.
+ return &(s_sSavedStateInfo[index]);
+}
+
+// Add a saved state to the list of saved states.
+// Returns the index for the new saved state, or -1 if an error occurred.
+int openavbAvdeccAddSavedState(const char listener_friendly_name[FRIENDLY_NAME_SIZE], U16 flags, U16 talker_unique_id, const U8 talker_entity_id[8], const U8 controller_entity_id[8])
+{
+ // Load the file data, if needed.
+ if (s_nNumSavedStates < 0 && !get_saved_state_info(DEFAULT_AVDECC_SAVE_INI_FILE)) {
+ return -1;
+ }
+
+ // If the list is full, delete the oldest item to make space for it.
+ while (s_nNumSavedStates >= MAX_SAVED_STATES) {
+ openavbAvdeccDeleteSavedState(0);
+ }
+
+ // Append the supplied state to the list of states.
+ strncpy(s_sSavedStateInfo[s_nNumSavedStates].listener_friendly_name, listener_friendly_name, FRIENDLY_NAME_SIZE);
+ s_sSavedStateInfo[s_nNumSavedStates].listener_friendly_name[FRIENDLY_NAME_SIZE - 1] = '\0';
+ s_sSavedStateInfo[s_nNumSavedStates].flags = flags;
+ s_sSavedStateInfo[s_nNumSavedStates].talker_unique_id = talker_unique_id;
+ memcpy(s_sSavedStateInfo[s_nNumSavedStates].talker_entity_id, talker_entity_id, 8);
+ memcpy(s_sSavedStateInfo[s_nNumSavedStates].controller_entity_id, controller_entity_id, 8);
+ s_nNumSavedStates++;
+
+ // Create a new saved state file with all the previous states, and our state.
+ if (!write_saved_state_info(DEFAULT_AVDECC_SAVE_INI_FILE)) {
+ AVB_LOGF_ERROR("Error saving state: listener_id=%s, talker_entity_id=" ENTITYID_FORMAT ", controller_entity_id=" ENTITYID_FORMAT,
+ listener_friendly_name,
+ ENTITYID_ARGS(talker_entity_id),
+ ENTITYID_ARGS(controller_entity_id));
+ return -1;
+ }
+
+ // Return the last index, as that is the one we used.
+ return (s_nNumSavedStates - 1);
+}
+
+// Delete the saved state information at the specified index.
+// Returns TRUE if successfully deleted, FALSE otherwise.
+bool openavbAvdeccDeleteSavedState(int index)
+{
+ // Load the file data, if needed.
+ if (s_nNumSavedStates < 0 && !get_saved_state_info(DEFAULT_AVDECC_SAVE_INI_FILE)) {
+ return false;
+ }
+
+ // Is the index valid?
+ if (s_nNumSavedStates <= 0 || index >= s_nNumSavedStates) {
+ return false;
+ }
+
+ // If the index points to the last item, simply reduce the count.
+ if (index == s_nNumSavedStates - 1) {
+ s_nNumSavedStates--;
+ return (write_saved_state_info(DEFAULT_AVDECC_SAVE_INI_FILE));
+ }
+
+ // Shift the items after the index to where the index is.
+ memcpy(&(s_sSavedStateInfo[index]), &(s_sSavedStateInfo[index + 1]), sizeof(openavb_saved_state_t) * (--s_nNumSavedStates - index));
+ return (write_saved_state_info(DEFAULT_AVDECC_SAVE_INI_FILE));
+}
diff --git a/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_save_state.h b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_save_state.h
new file mode 100644
index 00000000..da715761
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avdecc/openavb_avdecc_save_state.h
@@ -0,0 +1,70 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+* HEADER SUMMARY : Support for ACMP saved state
+*
+* Defines the saved state data, and the functions
+* to read and write the saved state data.
+*/
+
+#ifndef AVB_ENDPOINT_AVDECC_SAVE_STATE_H
+#define AVB_ENDPOINT_AVDECC_SAVE_STATE_H
+
+#include "openavb_types.h"
+#include "openavb_avdecc_pub.h"
+#include "openavb_tl_pub.h"
+
+#define DEFAULT_AVDECC_SAVE_INI_FILE "avdecc_save.ini"
+
+struct openavb_saved_state {
+ char listener_friendly_name[FRIENDLY_NAME_SIZE];
+ U16 flags;
+ U16 talker_unique_id;
+ U8 talker_entity_id[8];
+ U8 controller_entity_id[8];
+};
+typedef struct openavb_saved_state openavb_saved_state_t;
+
+// Returns a pointer to the saved state information for the index supplied.
+// To use, start at index 0 and increment upward.
+// If NULL is returned, then no values for that or any higher indexes.
+const openavb_saved_state_t * openavbAvdeccGetSavedState(int index);
+
+// Add a saved state to the list of saved states.
+// Returns the index for the new saved state, or -1 if an error occurred.
+int openavbAvdeccAddSavedState(const char listener_friendly_name[FRIENDLY_NAME_SIZE], U16 flags, U16 talker_unique_id, const U8 talker_entity_id[8], const U8 controller_entity_id[8]);
+
+// Delete the saved state information at the specified index.
+// Returns TRUE if successfully deleted, FALSE otherwise.
+bool openavbAvdeccDeleteSavedState(int index);
+
+#endif // AVB_ENDPOINT_AVDECC_SAVE_STATE_H
diff --git a/lib/avtp_pipeline/platform/Linux/avdecc_msg/CMakeLists.txt b/lib/avtp_pipeline/platform/Linux/avdecc_msg/CMakeLists.txt
new file mode 100644
index 00000000..139597f9
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avdecc_msg/CMakeLists.txt
@@ -0,0 +1,2 @@
+
+
diff --git a/lib/avtp_pipeline/platform/Linux/avdecc_msg/openavb_avdecc_msg_client_osal.c b/lib/avtp_pipeline/platform/Linux/avdecc_msg/openavb_avdecc_msg_client_osal.c
new file mode 100644
index 00000000..04de29e0
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avdecc_msg/openavb_avdecc_msg_client_osal.c
@@ -0,0 +1,181 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#ifndef OPENAVB_AVDECC_MSG_CLIENT_OSAL_C
+#define OPENAVB_AVDECC_MSG_CLIENT_OSAL_C
+
+static void socketClose(int socketHandle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ if (socketHandle != AVB_AVDECC_MSG_HANDLE_INVALID) {
+ close(socketHandle);
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+}
+
+static bool openavbAvdeccMsgClntSendToServer(int socketHandle, openavbAvdeccMessage_t *msg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ if (!msg || socketHandle == AVB_AVDECC_MSG_HANDLE_INVALID) {
+ AVB_LOG_ERROR("Client send: invalid argument passed");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return FALSE;
+ }
+
+ ssize_t nWrite = write(socketHandle, msg, OPENAVB_AVDECC_MSG_LEN);
+ AVB_LOGF_VERBOSE("Sent message, len=%zu, nWrite=%zu", OPENAVB_AVDECC_MSG_LEN, nWrite);
+
+ if (nWrite < OPENAVB_AVDECC_MSG_LEN) {
+ if (nWrite < 0) {
+ AVB_LOGF_ERROR("Client failed to write socket: %s", strerror(errno));
+ }
+ else if (nWrite == 0) {
+ AVB_LOG_ERROR("Client send: socket closed unexpectedly");
+ }
+ else {
+ AVB_LOG_ERROR("Client send: short write");
+ }
+ socketClose(socketHandle);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return TRUE;
+}
+
+int openavbAvdeccMsgClntOpenSrvrConnection(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ struct sockaddr_un server;
+ server.sun_family = AF_UNIX;
+ snprintf(server.sun_path, UNIX_PATH_MAX, AVB_AVDECC_MSG_UNIX_PATH);
+
+ int h = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (h < 0) {
+ AVB_LOGF_ERROR("Failed to open socket: %s", strerror(errno));
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return AVB_AVDECC_MSG_HANDLE_INVALID;
+ }
+
+ AVB_LOGF_DEBUG("Connecting to %s", server.sun_path);
+ int rslt = connect(h, (struct sockaddr*)&server, sizeof(struct sockaddr_un));
+ if (rslt < 0) {
+ AVB_LOGF_DEBUG("Failed to connect socket: %s", strerror(errno));
+ socketClose(h);
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return AVB_AVDECC_MSG_HANDLE_INVALID;
+ }
+
+ AVB_LOG_DEBUG("Connected to AVDECC Msg");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return h;
+}
+
+void openavbAvdeccMsgClntCloseSrvrConnection(int socketHandle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ socketClose(socketHandle);
+ AVB_LOG_DEBUG("Closed connection to AVDECC Msg");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+}
+
+bool openavbAvdeccMsgClntService(int socketHandle, int timeout)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ bool rc = FALSE;
+
+ if (socketHandle == AVB_AVDECC_MSG_HANDLE_INVALID) {
+ AVB_LOG_ERROR("Client service: invalid socket");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return FALSE;
+ }
+
+ struct pollfd fds[1];
+ memset(fds, 0, sizeof(struct pollfd));
+ fds[0].fd = socketHandle;
+ fds[0].events = POLLIN;
+
+ AVB_LOG_VERBOSE("Waiting for event...");
+ int pRet = poll(fds, 1, timeout);
+
+ if (pRet == 0) {
+ AVB_LOG_VERBOSE("Poll timeout");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return TRUE;
+ }
+ else if (pRet < 0) {
+ if (errno == EINTR) {
+ AVB_LOG_VERBOSE("Poll interrupted");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return TRUE;
+ }
+ else {
+ AVB_LOGF_ERROR("Poll error: %s", strerror(errno));
+ }
+ }
+ else {
+ AVB_LOGF_DEBUG("Poll returned %d events", pRet);
+ // only one fd, so it's readable.
+ openavbAvdeccMessage_t msgBuf;
+ memset(&msgBuf, 0, OPENAVB_AVDECC_MSG_LEN);
+ ssize_t nRead = read(socketHandle, &msgBuf, OPENAVB_AVDECC_MSG_LEN);
+
+ if (nRead < OPENAVB_AVDECC_MSG_LEN) {
+ // sock closed
+ if (nRead == 0) {
+ AVB_LOG_ERROR("Socket closed unexpectedly");
+ }
+ else if (nRead < 0) {
+ AVB_LOGF_ERROR("Socket read error: %s", strerror(errno));
+ }
+ else {
+ AVB_LOG_ERROR("Socket read to short");
+ }
+ socketClose(socketHandle);
+ }
+ else {
+ // got a message
+ if (openavbAvdeccMsgClntReceiveFromServer(socketHandle, &msgBuf)) {
+ rc = TRUE;
+ }
+ else {
+ AVB_LOG_ERROR("Invalid message received");
+ socketClose(socketHandle);
+ }
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return rc;
+}
+
+#endif // OPENAVB_AVDECC_MSG_CLIENT_OSAL_C
diff --git a/lib/avtp_pipeline/platform/Linux/avdecc_msg/openavb_avdecc_msg_osal.h b/lib/avtp_pipeline/platform/Linux/avdecc_msg/openavb_avdecc_msg_osal.h
new file mode 100644
index 00000000..b68ea38d
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avdecc_msg/openavb_avdecc_msg_osal.h
@@ -0,0 +1,64 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#ifndef OSAL_AVDECC_MSG_H
+#define OSAL_AVDECC_MSG_H
+
+// should only be included from openavb_avdecc_msg.h
+
+#include <linux/un.h>
+#include <net/if.h>
+#include <unistd.h>
+#include <signal.h>
+
+typedef struct {
+ openavbAvdeccMsgType_t type;
+ AVBStreamID_t streamID;
+ union {
+ // Client-to-Server messages
+ openavbAvdeccMsgParams_VersionRequest_t versionRequest;
+ openavbAvdeccMsgParams_ClientInitIdentify_t clientInitIdentify;
+ openavbAvdeccMsgParams_C2S_TalkerStreamID_t c2sTalkerStreamID;
+ openavbAvdeccMsgParams_ClientChangeNotification_t clientChangeNotification;
+
+ // Server-to-Client messages
+ openavbAvdeccMsgParams_VersionCallback_t versionCallback;
+ openavbAvdeccMsgParams_ListenerStreamID_t listenerStreamID;
+ openavbAvdeccMsgParams_S2C_TalkerStreamID_t s2cTalkerStreamID;
+ openavbAvdeccMsgParams_ClientChangeRequest_t clientChangeRequest;
+ } params;
+} openavbAvdeccMessage_t;
+
+
+bool startAvdeccMsg(int mode, int ifindex, const char* ifname, unsigned mtu, unsigned link_kbit, unsigned nsr_kbit);
+void stopAvdeccMsg();
+
+#endif // OSAL_AVDECC_MSG_H
diff --git a/lib/avtp_pipeline/platform/Linux/avdecc_msg/openavb_avdecc_msg_server_osal.c b/lib/avtp_pipeline/platform/Linux/avdecc_msg/openavb_avdecc_msg_server_osal.c
new file mode 100644
index 00000000..e73b9701
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/avdecc_msg/openavb_avdecc_msg_server_osal.c
@@ -0,0 +1,271 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#ifndef OPENAVB_AVDECC_MSG_SERVER_OSAL_C
+#define OPENAVB_AVDECC_MSG_SERVER_OSAL_C
+
+#define AVB_AVDECC_LISTEN_FDS 0 // first fds, was last MAX_AVB_STREAMS
+#define SOCK_INVALID (-1)
+#define POLL_FD_COUNT ((MAX_AVB_STREAMS) + 1)
+
+static int lsock = SOCK_INVALID;
+static struct pollfd fds[POLL_FD_COUNT];
+static struct sockaddr_un serverAddr;
+
+static void socketClose(int h)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ if (h < 0 || h >= POLL_FD_COUNT) {
+ AVB_LOG_ERROR("Closing socket; invalid handle");
+ }
+ else {
+ if (h != AVB_AVDECC_LISTEN_FDS) {
+ openavbAvdeccMsgSrvrCloseClientConnection(h);
+ }
+ close(fds[h].fd);
+ fds[h].fd = SOCK_INVALID;
+ fds[h].events = 0;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+}
+
+static bool openavbAvdeccMsgSrvrSendToClient(int h, openavbAvdeccMessage_t *msg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+
+ if (h < 0 || h >= POLL_FD_COUNT) {
+ AVB_LOG_ERROR("Sending message; invalid handle");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return FALSE;
+ }
+ if (!msg) {
+ AVB_LOG_ERROR("Sending message; invalid argument passed");
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return FALSE;
+ }
+
+ int csock = fds[h].fd;
+ if (csock == SOCK_INVALID) {
+ AVB_LOG_ERROR("Socket closed unexpectedly");
+ return FALSE;
+ }
+
+ ssize_t nWrite = write(csock, msg, OPENAVB_AVDECC_MSG_LEN);
+ AVB_LOGF_VERBOSE("Sent message, len=%zu, nWrite=%zu", OPENAVB_AVDECC_MSG_LEN, nWrite);
+ if (nWrite < OPENAVB_AVDECC_MSG_LEN) {
+ if (nWrite < 0) {
+ AVB_LOGF_ERROR("Failed to write socket: %s", strerror(errno));
+ }
+ else if (nWrite == 0) {
+ AVB_LOG_ERROR("Socket closed unexpectedly");
+ }
+ else {
+ AVB_LOG_ERROR("Socket write too short");
+ }
+ socketClose(h);
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return TRUE;
+}
+
+bool openavbAvdeccMsgServerOpen(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ int i;
+
+ // Perform the base initialization.
+ openavbAvdeccMsgInitialize();
+
+ for (i=0; i < POLL_FD_COUNT; i++) {
+ fds[i].fd = SOCK_INVALID;
+ fds[i].events = 0;
+ }
+
+ lsock = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (lsock < 0) {
+ AVB_LOGF_ERROR("Failed to open socket: %s", strerror(errno));
+ goto error;
+ }
+ // serverAddr is file static
+ serverAddr.sun_family = AF_UNIX;
+ snprintf(serverAddr.sun_path, UNIX_PATH_MAX, AVB_AVDECC_MSG_UNIX_PATH);
+
+ // try remove old socket
+ if (unlink(serverAddr.sun_path) == -1 && errno != ENOENT) {
+ AVB_LOGF_ERROR("Failed to remove %s: %s", serverAddr.sun_path, strerror(errno));
+ }
+
+ int rslt = bind(lsock, (struct sockaddr*)&serverAddr, sizeof(struct sockaddr_un));
+ if (rslt != 0) {
+ AVB_LOGF_ERROR("Failed to create %s: %s", serverAddr.sun_path, strerror(errno));
+ AVB_LOG_WARNING("** If AVDECC Msg process crashed, run the cleanup script **");
+ goto error;
+ }
+
+ rslt = listen(lsock, 5);
+ if (rslt != 0) {
+ AVB_LOGF_ERROR("Failed to listen on socket: %s", strerror(errno));
+ goto error;
+ }
+ AVB_LOGF_DEBUG("Listening on socket: %s", serverAddr.sun_path);
+
+ fds[AVB_AVDECC_LISTEN_FDS].fd = lsock;
+ fds[AVB_AVDECC_LISTEN_FDS].events = POLLIN;
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return TRUE;
+
+ error:
+ if (lsock >= 0) {
+ close(lsock);
+ lsock = -1;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+ return FALSE;
+}
+
+void openavbAvdeccMsgSrvrService(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ struct sockaddr_un addrClient;
+ socklen_t lenAddr;
+ int i, j;
+ int csock;
+
+ int nfds = POLL_FD_COUNT;
+ int pRet;
+
+ AVB_LOG_VERBOSE("Waiting for event...");
+ pRet = poll(fds, nfds, 1000);
+
+ if (pRet == 0) {
+ AVB_LOG_VERBOSE("poll timeout");
+ }
+ else if (pRet < 0) {
+ if (errno == EINTR) {
+ AVB_LOG_VERBOSE("Poll interrupted");
+ }
+ else {
+ AVB_LOGF_ERROR("Poll error: %s", strerror(errno));
+ }
+ }
+ else {
+ AVB_LOGF_VERBOSE("Poll returned %d events", pRet);
+ for (i=0; i<nfds; i++) {
+ if (fds[i].revents != 0) {
+ AVB_LOGF_VERBOSE("%d sock=%d, event=0x%x, revent=0x%x", i, fds[i].fd, fds[i].events, fds[i].revents);
+
+ if (i == AVB_AVDECC_LISTEN_FDS) {
+ // listen sock - indicates new connection from client
+ lenAddr = sizeof(addrClient);
+ csock = accept(lsock, (struct sockaddr*)&addrClient, &lenAddr);
+ if (csock < 0) {
+ AVB_LOGF_ERROR("Failed to accept connection: %s", strerror(errno));
+ }
+ else {
+ for (j = 0; j < POLL_FD_COUNT; j++) {
+ if (fds[j].fd == SOCK_INVALID) {
+ fds[j].fd = csock;
+ fds[j].events = POLLIN;
+ break;
+ }
+ }
+ if (j >= POLL_FD_COUNT) {
+ AVB_LOG_ERROR("Too many client connections");
+ close(csock);
+ }
+ }
+
+ AVB_LOG_INFO("New AVDECC Msg client connection detected");
+ }
+ else {
+ csock = fds[i].fd;
+ openavbAvdeccMessage_t msgBuf;
+ memset(&msgBuf, 0, OPENAVB_AVDECC_MSG_LEN);
+ ssize_t nRead = read(csock, &msgBuf, OPENAVB_AVDECC_MSG_LEN);
+ AVB_LOGF_VERBOSE("Socket read h=%d,fd=%d: read=%zu, expect=%zu", i, csock, nRead, OPENAVB_AVDECC_MSG_LEN);
+
+ if (nRead < OPENAVB_AVDECC_MSG_LEN) {
+ // sock closed
+ if (nRead == 0) {
+ AVB_LOGF_DEBUG("Socket closed, h=%d", i);
+ }
+ else if (nRead < 0) {
+ AVB_LOGF_ERROR("Socket read, h=%d: %s", i, strerror(errno));
+ }
+ else {
+ AVB_LOGF_ERROR("Short read, h=%d", i);
+ }
+ socketClose(i);
+ }
+ else {
+ // got a message
+ if (!openavbAvdeccMsgSrvrReceiveFromClient(i, &msgBuf)) {
+ AVB_LOG_ERROR("Failed to handle message");
+ socketClose(i);
+ }
+ }
+ }
+ }
+ }
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+}
+
+void openavbAvdeccMsgServerClose(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_AVDECC_MSG);
+ int i;
+ for (i = 0; i < POLL_FD_COUNT; i++) {
+ if (fds[i].fd != SOCK_INVALID) {
+ socketClose(i);
+ }
+ }
+ if (lsock != SOCK_INVALID) {
+ close(lsock);
+ }
+
+ if (unlink(serverAddr.sun_path) != 0) {
+ AVB_LOGF_ERROR("Failed to unlink %s: %s", serverAddr.sun_path, strerror(errno));
+ }
+
+ // Perform the base cleanup.
+ openavbAvdeccMsgCleanup();
+
+ AVB_TRACE_EXIT(AVB_TRACE_AVDECC_MSG);
+}
+
+#endif // OPENAVB_AVDECC_MSG_SERVER_OSAL_C
diff --git a/lib/avtp_pipeline/platform/Linux/avtp/openavb_avtp_time_osal.c b/lib/avtp_pipeline/platform/Linux/avtp/openavb_avtp_time_osal.c
index 227174c7..6ff72c8b 100644
--- a/lib/avtp_pipeline/platform/Linux/avtp/openavb_avtp_time_osal.c
+++ b/lib/avtp_pipeline/platform/Linux/avtp/openavb_avtp_time_osal.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.c b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.c
index d00e2380..7e0b53c6 100644
--- a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.c
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -29,7 +30,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
/*
-* MODULE SUMMARY : Reads the .ini file for an enpoint and
+* MODULE SUMMARY : Reads the .ini file for an endpoint
*/
#include <unistd.h>
@@ -50,6 +51,16 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#define MATCH(A, B)(strcasecmp((A), (B)) == 0)
#define MATCH_FIRST(A, B)(strncasecmp((A), (B), strlen(B)) == 0)
+static bool parse_mac(const char *str, struct ether_addr *mac)
+{
+ memset(mac, 0, sizeof(struct ether_addr));
+ if (ether_aton_r(str, mac) != NULL)
+ return TRUE;
+
+ AVB_LOGF_ERROR("Failed to parse addr: %s", str);
+ return FALSE;
+}
+
static void cfgValErr(const char *section, const char *name, const char *value)
{
AVB_LOGF_ERROR("Invalid value: section=%s, name=%s, value=%s",
@@ -164,6 +175,60 @@ static int cfgCallback(void *user, const char *section, const char *name, const
return 0;
}
}
+ else if (MATCH(section, "maap"))
+ {
+ if (MATCH(name, "port")) {
+ errno = 0;
+ unsigned temp = strtoul(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0) {
+ if (temp >= 1 && temp <= 65535) {
+ pCfg->maapPort = temp;
+ valOK = TRUE;
+ }
+ }
+ }
+ else {
+ // unmatched item, fail
+ AVB_LOGF_ERROR("Unrecognized configuration item: section=%s, name=%s", section, name);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return 0;
+ }
+ }
+ else if (MATCH(section, "shaper"))
+ {
+ if (MATCH(name, "port")) {
+ errno = 0;
+ unsigned temp = strtoul(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0) {
+ if (temp >= 1 && temp <= 65535) {
+ pCfg->shaperPort = temp;
+ valOK = TRUE;
+ }
+ }
+ }
+ else {
+ // unmatched item, fail
+ AVB_LOGF_ERROR("Unrecognized configuration item: section=%s, name=%s", section, name);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return 0;
+ }
+ }
+
+ // Special section to load saved settings.
+ else if (MATCH(section, "saved"))
+ {
+ if (MATCH(name, "maap_preferred"))
+ {
+ valOK = parse_mac(value, &(pCfg->maap_preferred));
+ }
+ else {
+ // unmatched item, fail
+ AVB_LOGF_ERROR("Unrecognized configuration item: section=%s, name=%s", section, name);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return 0;
+ }
+ }
+
else {
// unmatched item, fail
AVB_LOGF_ERROR("Unrecognized configuration item: section=%s, name=%s", section, name);
@@ -183,7 +248,7 @@ static int cfgCallback(void *user, const char *section, const char *name, const
// Parse ini file, and create config data
//
-int openavbReadConfig(const char *ini_file, openavb_endpoint_cfg_t *pCfg)
+int openavbReadConfig(const char *ini_file, const char *save_ini_file, openavb_endpoint_cfg_t *pCfg)
{
AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
@@ -194,10 +259,19 @@ int openavbReadConfig(const char *ini_file, openavb_endpoint_cfg_t *pCfg)
int result = ini_parse(ini_file, cfgCallback, pCfg);
if (result < 0) {
AVB_LOGF_ERROR("Couldn't parse INI file: %s", ini_file);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return -1;
+ }
+ if (result > 0) {
+ AVB_LOGF_ERROR("Error in INI file: %s, line %d", ini_file, result);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
return -1;
}
+
+ result = ini_parse(save_ini_file, cfgCallback, pCfg);
if (result > 0) {
AVB_LOGF_ERROR("Error in INI file: %s, line %d", ini_file, result);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
return -1;
}
@@ -207,6 +281,57 @@ int openavbReadConfig(const char *ini_file, openavb_endpoint_cfg_t *pCfg)
return 0;
}
+// Create ini file with information to save.
+//
+int openavbSaveConfig(const char *ini_file, const openavb_endpoint_cfg_t *pCfg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ FILE* file;
+
+ char *pvtFilename = strdup(ini_file);
+ if (!pvtFilename) {
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return -1;
+ }
+
+ char *override = strchr(pvtFilename, ',');
+ if (override)
+ *override++ = '\0';
+
+ file = fopen(pvtFilename, "w");
+ if (!file) {
+ AVB_LOGF_WARNING("Error saving to INI file: %s", ini_file);
+ free (pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return -1;
+ }
+
+ if (fputs("[saved]\n", file) < 0) {
+ AVB_LOGF_ERROR("Error writing to INI file: %s", ini_file);
+ fclose(file);
+ free (pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return -1;
+ }
+ if (fprintf(file, "maap_preferred = " ETH_FORMAT "\n", ETH_OCTETS(pCfg->maap_preferred.ether_addr_octet)) < 0) {
+ AVB_LOGF_ERROR("Error writing to INI file: %s", ini_file);
+ fclose(file);
+ free (pvtFilename);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return -1;
+ }
+
+ fclose(file);
+ free (pvtFilename);
+
+ AVB_LOGF_DEBUG("Saved settings to INI file: %s", ini_file);
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+
+ // Yay, we did it.
+ return 0;
+}
+
// Clean up any configuration-related stuff
//
void openavbUnconfigure(openavb_endpoint_cfg_t *pCfg)
diff --git a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.h b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.h
index 8cc989a5..b8249146 100644
--- a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.h
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_cfg.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -43,21 +44,28 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "net/if.h"
#define DEFAULT_INI_FILE "endpoint.ini"
+#define DEFAULT_SAVE_INI_FILE "endpoint_save.ini"
typedef struct {
- char ifname[IFNAMSIZ];
- U8 ifmac[ETH_ALEN];
- char *ptp_start_opts;
- int ifindex;
- unsigned link_kbit;
- unsigned nsr_kbit;
- unsigned mtu;
- unsigned fqtss_mode;
- bool noSrp;
- bool bypassAsCapableCheck;
+ char ifname[IFNAMSIZ + 10]; // Include space for the socket type prefix (e.g. "simple:eth0")
+ U8 ifmac[ETH_ALEN];
+ char *ptp_start_opts;
+ int ifindex;
+ unsigned link_kbit;
+ unsigned nsr_kbit;
+ unsigned mtu;
+ unsigned fqtss_mode;
+ bool noSrp;
+ unsigned maapPort;
+ unsigned shaperPort;
+ bool bypassAsCapableCheck;
+
+ // Information to be saved for future use.
+ struct ether_addr maap_preferred; // Last assigned MAAP address.
} openavb_endpoint_cfg_t;
-int openavbReadConfig(const char *inifile, openavb_endpoint_cfg_t *pCfg);
+int openavbReadConfig(const char *ini_file, const char *save_ini_file, openavb_endpoint_cfg_t *pCfg);
+int openavbSaveConfig(const char *save_ini_file, const openavb_endpoint_cfg_t *pCfg);
void openavbUnconfigure(openavb_endpoint_cfg_t *pCfg);
#endif // AVB_ENDPOINT_CONFIG_H
diff --git a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_client_osal.c b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_client_osal.c
index dcdca3cd..316604bf 100644
--- a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_client_osal.c
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_client_osal.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -95,7 +96,7 @@ int openavbEptClntOpenSrvrConnection(tl_state_t *pTLState)
return AVB_ENDPOINT_HANDLE_INVALID;
}
- AVB_LOG_DEBUG("connected to endpoint");
+ AVB_LOG_DEBUG("Connected to endpoint");
AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
return h;
}
diff --git a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal.c b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal.c
index 7eb3a17d..dfed5863 100644
--- a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal.c
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -30,15 +31,12 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include <stdlib.h>
#include <string.h>
+
#include "openavb_platform.h"
#include "openavb_trace.h"
#include "openavb_endpoint.h"
#include "openavb_endpoint_cfg.h"
-#include "openavb_srp.h"
-#include "openavb_maap.h"
-#include "mrp_client.h"
-#include "openavb_ether_hal.h"
-#include "openavb_list.h"
+#include "openavb_rawsock.h"
#define AVB_LOG_COMPONENT "Endpoint"
//#define AVB_LOG_LEVEL AVB_LOG_LEVEL_DEBUG
@@ -51,37 +49,6 @@ extern bool endpointRunning;
static pthread_t endpointServerHandle;
static void* endpointServerThread(void *arg);
-inline int startPTP(void)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
-
- // make sure ptp, a seperate process, starts and is using the same interface as endpoint
- int retVal = 0;
-// char ptpCmd[80];
-// memset(ptpCmd, 0, 80);
-// snprintf(ptpCmd, 80, "./openavb_gptp %s -i %s &", x_cfg.ptp_start_opts, x_cfg.ifname);
-// AVB_LOGF_INFO("PTP start command: %s", ptpCmd);
-// if (system(ptpCmd) != 0) {
-// AVB_LOG_ERROR("PTP failed to start - Exiting");
-// retVal = -1;
-// }
-
- AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
- return retVal;
-}
-
-inline int stopPTP(void)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
-
- int retVal = 0;
-// if (system("killall -s SIGINT openavb_gptp") != 0) {
-// retVal = -1;
-// }
-
- AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
- return retVal;
-}
bool startEndpoint(int mode, int ifindex, const char* ifname, unsigned mtu, unsigned link_kbit, unsigned nsr_kbit)
{
@@ -100,15 +67,21 @@ bool startEndpoint(int mode, int ifindex, const char* ifname, unsigned mtu, unsi
memset(&x_cfg, 0, sizeof(openavb_endpoint_cfg_t));
x_cfg.fqtss_mode = mode;
x_cfg.ifindex = ifindex;
- if (ifname)
- strncpy(x_cfg.ifname, ifname, sizeof(x_cfg.ifname));
-
- igbGetMacAddr(x_cfg.ifmac);
-
x_cfg.mtu = mtu;
+
x_cfg.link_kbit = link_kbit;
x_cfg.nsr_kbit = nsr_kbit;
+ openavbReadConfig(DEFAULT_INI_FILE, DEFAULT_SAVE_INI_FILE, &x_cfg);
+
+ if_info_t ifinfo;
+ if (ifname && openavbCheckInterface(ifname, &ifinfo)) {
+ strncpy(x_cfg.ifname, ifname, sizeof(x_cfg.ifname));
+ memcpy(x_cfg.ifmac, &ifinfo.mac, ETH_ALEN);
+ x_cfg.ifindex = ifinfo.index;
+ x_cfg.mtu = ifinfo.mtu;
+ }
+
endpointRunning = TRUE;
int err = pthread_create(&endpointServerHandle, NULL, endpointServerThread, NULL);
if (err) {
@@ -153,425 +126,3 @@ static void* endpointServerThread(void *arg)
AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
return NULL;
}
-
-
-/*******************************************************************************
- * SRP proxies
- ******************************************************************************/
-
-static strmAttachCb_t _attachCb = NULL;
-static strmRegCb_t _registerCb = NULL;
-
-typedef struct {
- void* avtpHandle;
- bool talker;
- U8 streamId[8];
- U8 destAddr[6];
- U16 vlanId;
- int maxFrameSize;
- int maxIntervalFrames;
- int priority;
- int latency;
- int subtype;
-} strElem_t;
-
-openavb_list_t strElemList;
-
-#define SID_FORMAT "%02x:%02x:%02x:%02x:%02x:%02x/%d"
-#define SID_OCTETS(a) (a)[0],(a)[1],(a)[2],(a)[3],(a)[4],(a)[5],(a)[6]<<8|(a)[7]
-
-void mrp_attach_cb(unsigned char streamid[8], int subtype)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
-
- AVB_LOGF_DEBUG("mrp_attach_cb "SID_FORMAT" subtype %d", SID_OCTETS(streamid), subtype);
-
- if (_attachCb) {
- openavb_list_node_t node = openavbListIterFirst(strElemList);
- while (node) {
- strElem_t *elem = openavbListData(node);
- if (elem && elem->talker && memcmp(streamid, elem->streamId, sizeof(elem->streamId)) == 0) {
- if (elem->subtype != subtype) {
- _attachCb(elem->avtpHandle, subtype);
- elem->subtype = subtype;
- }
- break;
- }
- node = openavbListIterNext(strElemList);
- }
- if (!node)
- AVB_LOG_DEBUG("attach_cb stream not ours");
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
-}
-
-void mrp_register_cb(unsigned char streamid[8], int join, unsigned char destaddr[6], unsigned int max_frame_size, unsigned int max_interval_frames, uint16_t vid, unsigned int latency)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
-
- AVB_LOGF_DEBUG("mrp_register_cb "SID_FORMAT" "ETH_FORMAT" join %d max_frame_size %d max_interval_frames %d vid %d latency %d",
- SID_OCTETS(streamid), ETH_OCTETS(destaddr), join, max_frame_size, max_interval_frames, vid, latency);
-
- if (_registerCb) {
- openavb_list_node_t node = openavbListIterFirst(strElemList);
- while (node) {
- strElem_t *elem = openavbListData(node);
- if (elem && !elem->talker && memcmp(streamid, elem->streamId, sizeof(elem->streamId)) == 0) {
- if (elem->subtype != join) {
- AVBTSpec_t tSpec;
- tSpec.maxFrameSize = max_frame_size;
- tSpec.maxIntervalFrames = max_interval_frames;
- _registerCb(elem->avtpHandle,
- join ? openavbSrp_AtTyp_TalkerAdvertise : openavbSrp_AtTyp_None,
- destaddr,
- &tSpec,
- 0, // SR_CLASS is ignored anyway
- latency,
- NULL
- );
- elem->subtype = join;
- }
- break;
- }
- node = openavbListIterNext(strElemList);
- }
- if (!node)
- AVB_LOG_DEBUG("register_cb stream not ours");
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
-}
-
-openavbRC openavbSrpInitialize(strmAttachCb_t attachCb, strmRegCb_t registerCb,
- char* ifname, U32 TxRateKbps, bool bypassAsCapableCheck)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
- int err;
-
- strElemList = openavbListNewList();
-
- _attachCb = attachCb;
- _registerCb = registerCb;
-
-
- err = mrp_connect();
- if (err) {
- AVB_LOGF_ERROR("mrp_connect failed: %s", strerror(errno));
- goto error;
- }
- err = mrp_monitor();
- if (err) {
- AVB_LOGF_ERROR("failed creating MRP monitor thread: %s", strerror(errno));
- goto error;
- }
-
- int class_a_id, a_priority;
- u_int16_t a_vid;
- int class_b_id, b_priority;
- u_int16_t b_vid;
-
- err = mrp_get_domain(&class_a_id,&a_priority, &a_vid, &class_b_id, &b_priority, &b_vid);
- if (err) {
- AVB_LOG_DEBUG("mrp_get_domain failed");
- goto error;
- }
-
- AVB_LOGF_INFO("detected domain Class A PRIO=%d VID=%04x...", a_priority, (int)a_vid);
- AVB_LOGF_INFO("detected domain Class B PRIO=%d VID=%04x...", b_priority, (int)b_vid);
-
- err = mrp_register_domain(&domain_class_a_id, &domain_class_a_priority, &domain_class_a_vid);
- if (err) {
- AVB_LOG_DEBUG("mrp_register_domain failed");
- goto error;
- }
-
- err = mrp_register_domain(&domain_class_b_id, &domain_class_b_priority, &domain_class_b_vid);
- if (err) {
- AVB_LOG_DEBUG("mrp_register_domain failed");
- goto error;
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
- return OPENAVB_SRP_SUCCESS;
-
-error:
- AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
- return OPENAVB_SRP_FAILURE;
-}
-
-void openavbSrpShutdown(void)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
- int err = mrp_disconnect();
- if (err) {
- AVB_LOGF_ERROR("mrp_disconnect failed: %s", strerror(errno));
- }
- AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
-}
-
-openavbRC openavbSrpRegisterStream(void* avtpHandle,
- AVBStreamID_t* _streamId,
- U8 DA[],
- AVBTSpec_t* tSpec,
- SRClassIdx_t SRClassIdx,
- bool Rank,
- U32 Latency)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
- int err;
-
- // convert streamId to 8 byte format
- uint8_t streamId[8];
- memcpy(streamId, _streamId->addr, sizeof(_streamId->addr));
- streamId[6] = _streamId->uniqueID >> 8;
- streamId[7] = _streamId->uniqueID & 0xFF;
-
- openavb_list_node_t node = openavbListNew(strElemList, sizeof(strElem_t));
- strElem_t* elem = openavbListData(node);
-
- elem->avtpHandle = avtpHandle;
- elem->talker = true;
- memcpy(elem->streamId, streamId, sizeof(elem->streamId));
- memcpy(elem->destAddr, DA, sizeof(elem->destAddr));
- elem->maxFrameSize = tSpec->maxFrameSize;
- elem->maxIntervalFrames = tSpec->maxIntervalFrames;
- elem->latency = Latency;
- elem->subtype = openavbSrp_LDSt_None;
-
- switch (SRClassIdx) {
- case SR_CLASS_A:
- elem->vlanId = domain_class_a_vid;
- elem->priority = domain_class_a_priority;
-
- err = mrp_advertise_stream(streamId,
- DA,
- domain_class_a_vid,
- tSpec->maxFrameSize,
- tSpec->maxIntervalFrames,
- domain_class_a_priority,
- Latency);
- break;
- case SR_CLASS_B:
- elem->vlanId = domain_class_b_vid;
- elem->priority = domain_class_b_priority;
-
- err = mrp_advertise_stream(streamId,
- DA,
- domain_class_b_vid,
- tSpec->maxFrameSize,
- tSpec->maxIntervalFrames,
- domain_class_b_priority,
- Latency);
- break;
- default:
- AVB_LOGF_ERROR("unknown SRClassIdx %d", (int)SRClassIdx);
- goto error;
- }
-
- if (err) {
- AVB_LOG_ERROR("mrp_advertise_stream failed");
- goto error;
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
- return OPENAVB_SRP_SUCCESS;
-
-error:
- AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
- return OPENAVB_SRP_FAILURE;
-}
-
-openavbRC openavbSrpDeregisterStream(AVBStreamID_t* _streamId)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
-
- // convert streamId to 8 byte format
- uint8_t streamId[8];
- memcpy(streamId, _streamId->addr, sizeof(_streamId->addr));
- streamId[6] = _streamId->uniqueID >> 8;
- streamId[7] = _streamId->uniqueID & 0xFF;
-
- openavb_list_node_t node = openavbListIterFirst(strElemList);
- while (node) {
- strElem_t *elem = openavbListData(node);
- if (elem && memcmp(streamId, elem->streamId, sizeof(elem->streamId)) == 0) {
- int err = mrp_unadvertise_stream(elem->streamId, elem->destAddr, elem->vlanId, elem->maxFrameSize, elem->maxIntervalFrames, elem->priority, elem->latency);
- if (err) {
- AVB_LOG_ERROR("mrp_unadvertise_stream failed");
- }
- openavbListDelete(strElemList, node);
- break;
- }
- node = openavbListIterNext(strElemList);
- }
- if (!node)
- AVB_LOGF_ERROR("%s: unknown stream "SID_FORMAT, __func__, SID_OCTETS(streamId));
- AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
- return OPENAVB_SRP_SUCCESS;
-}
-
-openavbRC openavbSrpAttachStream(void* avtpHandle,
- AVBStreamID_t* _streamId,
- openavbSrpLsnrDeclSubtype_t type)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
-
- // convert streamId to 8 byte format
- uint8_t streamId[8];
- memcpy(streamId, _streamId->addr, sizeof(_streamId->addr));
- streamId[6] = _streamId->uniqueID >> 8;
- streamId[7] = _streamId->uniqueID & 0xFF;
-
- AVB_LOGF_DEBUG("openavbSrpAttachStream "SID_FORMAT, SID_OCTETS(streamId));
-
- openavb_list_node_t node = openavbListIterFirst(strElemList);
- // lets check if this streamId is on our list
- while (node) {
- strElem_t *elem = openavbListData(node);
- if (elem && memcmp(streamId, elem->streamId, sizeof(elem->streamId)) == 0) {
- break;
- }
- node = openavbListIterNext(strElemList);
- }
- if (!node) {
- // not found so add it
- node = openavbListNew(strElemList, sizeof(strElem_t));
- strElem_t* elem = openavbListData(node);
-
- elem->avtpHandle = avtpHandle;
- elem->talker = false;
- memcpy(elem->streamId, streamId, sizeof(elem->streamId));
- elem->subtype = type;
- }
-
- int err = mrp_send_ready(streamId);
- if (err) {
- AVB_LOG_ERROR("mrp_send_ready failed");
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
- return OPENAVB_SRP_SUCCESS;
-}
-
-openavbRC openavbSrpDetachStream(AVBStreamID_t* _streamId)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
-
- // convert streamId to 8 byte format
- uint8_t streamId[8];
- memcpy(streamId, _streamId->addr, sizeof(_streamId->addr));
- streamId[6] = _streamId->uniqueID >> 8;
- streamId[7] = _streamId->uniqueID & 0xFF;
-
- AVB_LOGF_DEBUG("openavbSrpDetachStream "SID_FORMAT, SID_OCTETS(streamId));
-
- openavb_list_node_t node = openavbListIterFirst(strElemList);
- while (node) {
- strElem_t *elem = openavbListData(node);
- if (elem && memcmp(streamId, elem->streamId, sizeof(elem->streamId)) == 0) {
- int err = mrp_send_leave(streamId);
- if (err) {
- AVB_LOG_ERROR("mrp_send_leave failed");
- }
- openavbListDelete(strElemList, node);
- break;
- }
- node = openavbListIterNext(strElemList);
- }
- if (!node)
- AVB_LOGF_ERROR("%s: unknown stream "SID_FORMAT, __func__, SID_OCTETS(streamId));
-
- AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
- return OPENAVB_SRP_SUCCESS;
-}
-
-openavbRC openavbSrpGetClassParams(SRClassIdx_t SRClassIdx, U8* priority, U16* vid, U32* inverseIntervalSec)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
- switch (SRClassIdx) {
- case SR_CLASS_A:
- *priority = domain_class_a_priority;
- *vid = domain_class_a_vid;
- *inverseIntervalSec = 8000;
- break;
- case SR_CLASS_B:
- *priority = domain_class_b_priority;
- *vid = domain_class_b_vid;
- *inverseIntervalSec = 4000;
- break;
- default:
- AVB_LOGF_ERROR("unknown SRClassIdx %d", (int)SRClassIdx);
- AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
- return OPENAVB_SRP_FAILURE;
- }
- AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
- return OPENAVB_SRP_SUCCESS;
-}
-
-
-/*******************************************************************************
- * MAAP proxies
- ******************************************************************************/
-
-// OPENAVB_TODO: Real implementation should be added once OpenAVB's MAAP daemon is finished
-
-typedef struct {
- U8 destAddr[ETH_ALEN];
- bool taken;
-} maapAlloc_t;
-
-maapAlloc_t maapAllocList[MAX_AVB_STREAMS];
-
-bool openavbMaapInitialize(const char *ifname, openavbMaapRestartCb_t* cbfn)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_MAAP);
- int i = 0;
- U8 destAddr[ETH_ALEN] = {0x91, 0xe0, 0xf0, 0x00, 0x0e, 0x80};
- for (i = 0; i < MAX_AVB_STREAMS; i++) {
- memcpy(maapAllocList[i].destAddr, destAddr, ETH_ALEN);
- maapAllocList[i].taken = false;
- destAddr[5] += 1;
- }
- AVB_TRACE_EXIT(AVB_TRACE_MAAP);
- return true;
-}
-
-void openavbMaapFinalize()
-{
- AVB_TRACE_ENTRY(AVB_TRACE_MAAP);
- AVB_TRACE_EXIT(AVB_TRACE_MAAP);
-
-}
-
-void* openavbMaapAllocate(int count, /* out */ struct ether_addr *addr)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_MAAP);
- assert(count == 1);
-
- int i = 0;
- while (i < MAX_AVB_STREAMS && maapAllocList[i].taken) {
- i++;
- }
-
- if (i < MAX_AVB_STREAMS) {
- maapAllocList[i].taken = true;
- memcpy(addr, maapAllocList[i].destAddr, ETH_ALEN);
-
- AVB_TRACE_EXIT(AVB_TRACE_MAAP);
- return &maapAllocList[i];
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_MAAP);
- return NULL;
-}
-
-void openavbMaapRelease(void* handle)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_MAAP);
-
- maapAlloc_t *elem = handle;
- elem->taken = false;
-
- AVB_TRACE_EXIT(AVB_TRACE_MAAP);
-}
diff --git a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal.h b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal.h
index 4f41f8d5..6b5118ae 100644
--- a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal.h
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_maap.c b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_maap.c
new file mode 100644
index 00000000..0f754236
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_maap.c
@@ -0,0 +1,596 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#include "openavb_platform.h"
+#include "openavb_trace.h"
+#include "openavb_maap.h"
+#include "maap_iface.h"
+#include "openavb_list.h"
+#include "openavb_rawsock.h"
+
+// These are used to support saving the MAAP Address
+#include "openavb_endpoint_cfg.h"
+extern openavb_endpoint_cfg_t x_cfg;
+
+#define AVB_LOG_COMPONENT "Endpoint MAAP"
+//#define AVB_LOG_LEVEL AVB_LOG_LEVEL_DEBUG
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+#define MAAP_DYNAMIC_POOL_BASE 0x91E0F0000000LL /**< MAAP dynamic allocation pool base address - Defined in IEEE 1722-2016 Table B.9 */
+#define MAAP_DYNAMIC_POOL_SIZE 0xFE00 /**< MAAP dynamic allocation pool size - Defined in IEEE 1722-2016 Table B.9 */
+
+
+/*******************************************************************************
+ * MAAP proxies
+ ******************************************************************************/
+
+typedef struct {
+ struct ether_addr destAddr;
+ bool taken;
+} maapAlloc_t;
+
+static maapAlloc_t maapAllocList[MAX_AVB_STREAMS];
+static openavbMaapRestartCb_t *maapRestartCallback = NULL;
+static struct ether_addr *maapPreferredAddress = NULL;
+
+static bool maapRunning = FALSE;
+static pthread_t maapThreadHandle;
+static void* maapThread(void *arg);
+
+enum maapState_t {
+ MAAP_STATE_UNKNOWN,
+ MAAP_STATE_INITIALIZING, // Waiting for initialization
+ MAAP_STATE_REQUESTING, // Waiting address block request
+ MAAP_STATE_CONNECTED, // Have block of addresses
+ MAAP_STATE_RELEASING, // Releasing the block of addresses
+ MAAP_STATE_RELEASED, // Released the block of addresses
+ MAAP_STATE_NOT_AVAILABLE, // MAAP not configured, or freed
+ MAAP_STATE_ERROR
+};
+static enum maapState_t maapState = MAAP_STATE_UNKNOWN;
+static int maapReservationId = 0;
+
+static char maapDaemonPort[6] = {0};
+
+static MUTEX_HANDLE(maapMutex);
+#define MAAP_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(maapMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define MAAP_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(maapMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+static unsigned long long MaapMacAddrToLongLong(const struct ether_addr *addr)
+{
+ unsigned long long nAddress = 0ull;
+ int i;
+ for (i = 0; i < ETH_ALEN; ++i) {
+ nAddress = (nAddress << 8) | addr->ether_addr_octet[i];
+ }
+ return nAddress;
+}
+
+static void MaapResultToMacAddr(unsigned long long nAddress, struct ether_addr *destAddr)
+{
+ int i;
+ for (i = ETH_ALEN - 1; i >= 0; --i) {
+ destAddr->ether_addr_octet[i] = (U8)(nAddress & 0xFF);
+ nAddress >>= 8;
+ }
+}
+
+static void process_maap_notify(Maap_Notify *mn, int socketfd)
+{
+ assert(mn);
+
+ switch (mn->result)
+ {
+ case MAAP_NOTIFY_ERROR_NONE:
+ /* No error. Don't display anything. */
+ break;
+ case MAAP_NOTIFY_ERROR_REQUIRES_INITIALIZATION:
+ AVB_LOG_ERROR("MAAP is not initialized, so the command cannot be performed.");
+ break;
+ case MAAP_NOTIFY_ERROR_ALREADY_INITIALIZED:
+ AVB_LOG_ERROR("MAAP is already initialized, so the values cannot be changed.");
+ break;
+ case MAAP_NOTIFY_ERROR_RESERVE_NOT_AVAILABLE:
+ AVB_LOG_ERROR("The MAAP reservation is not available, or yield cannot allocate a replacement block. "
+ "Try again with a smaller address block size.");
+ break;
+ case MAAP_NOTIFY_ERROR_RELEASE_INVALID_ID:
+ AVB_LOG_ERROR("The MAAP reservation ID is not valid, so cannot be released or report its status.");
+ break;
+ case MAAP_NOTIFY_ERROR_OUT_OF_MEMORY:
+ AVB_LOG_ERROR("The MAAP application is out of memory.");
+ break;
+ case MAAP_NOTIFY_ERROR_INTERNAL:
+ AVB_LOG_ERROR("The MAAP application experienced an internal error.");
+ break;
+ default:
+ AVB_LOGF_ERROR("The MAAP application returned an unknown error %d.", mn->result);
+ break;
+ }
+
+ switch (mn->kind)
+ {
+ case MAAP_NOTIFY_INITIALIZED:
+ if (mn->result == MAAP_NOTIFY_ERROR_NONE) {
+ AVB_LOGF_DEBUG("MAAP initialized: 0x%012llx-0x%012llx (Size: %d)",
+ (unsigned long long) mn->start,
+ (unsigned long long) mn->start + mn->count - 1,
+ (unsigned int) mn->count);
+
+ // We successfully initialized. Reserve a block of addresses.
+ Maap_Cmd maapcmd;
+ memset(&maapcmd, 0, sizeof(Maap_Cmd));
+ maapcmd.kind = MAAP_CMD_RESERVE;
+ maapcmd.start = 0; // No preferred address
+ maapcmd.count = MAX_AVB_STREAMS;
+ if (maapPreferredAddress != NULL) {
+ // Suggest the addresses from the previous time this application was run.
+ maapcmd.start = MaapMacAddrToLongLong(maapPreferredAddress);
+ AVB_LOGF_DEBUG("MAAP Preferred Address: 0x%012llx", maapcmd.start);
+ }
+ if (send(socketfd, (char *) &maapcmd, sizeof(Maap_Cmd), 0) < 0)
+ {
+ /* Something went wrong. Abort! */
+ AVB_LOGF_ERROR("MAAP: Error %d writing to network socket (%s)", errno, strerror(errno));
+ maapState = MAAP_STATE_ERROR;
+ } else {
+ maapState = MAAP_STATE_REQUESTING;
+ }
+ } else {
+ AVB_LOGF_ERROR("MAAP previously initialized to 0x%012llx-0x%012llx (Size: %d)",
+ (unsigned long long) mn->start,
+ (unsigned long long) mn->start + mn->count - 1,
+ (unsigned int) mn->count);
+ maapState = MAAP_STATE_ERROR;
+ }
+ break;
+ case MAAP_NOTIFY_ACQUIRING:
+ if (mn->result == MAAP_NOTIFY_ERROR_NONE) {
+ AVB_LOGF_DEBUG("MAAP address range %d querying: 0x%012llx-0x%012llx (Size %d)",
+ mn->id,
+ (unsigned long long) mn->start,
+ (unsigned long long) mn->start + mn->count - 1,
+ mn->count);
+ } else {
+ AVB_LOGF_ERROR("MAAP unknown address range %d acquisition error", mn->id);
+ maapState = MAAP_STATE_ERROR;
+ }
+ break;
+ case MAAP_NOTIFY_ACQUIRED:
+ if (mn->result == MAAP_NOTIFY_ERROR_NONE) {
+ AVB_LOGF_INFO("MAAP address range %d acquired: 0x%012llx-0x%012llx (Size %d)",
+ mn->id,
+ (unsigned long long) mn->start,
+ (unsigned long long) mn->start + mn->count - 1,
+ mn->count);
+
+ // Update the stored addresses.
+ MAAP_LOCK();
+ int i = 0;
+ for (i = 0; i < mn->count && i < MAX_AVB_STREAMS; i++) {
+ MaapResultToMacAddr(mn->start + i, &(maapAllocList[i].destAddr));
+ if (maapAllocList[i].taken && maapRestartCallback) {
+ // Use the callback to notify that a change has occurred.
+ MAAP_UNLOCK();
+ maapRestartCallback(&(maapAllocList[i]), &(maapAllocList[i].destAddr));
+ MAAP_LOCK();
+ }
+ }
+ MAAP_UNLOCK();
+
+ // Save the address so we can request it in the future.
+ if (maapPreferredAddress != NULL) {
+ struct ether_addr assignedAddress;
+ MaapResultToMacAddr((unsigned long long) mn->start, &assignedAddress);
+ if (memcmp(maapPreferredAddress, &assignedAddress, sizeof(struct ether_addr)) != 0) {
+ // Save the updated settings. Done immediately, so they won't get lost on device reboot.
+ memcpy(maapPreferredAddress, &assignedAddress, sizeof(struct ether_addr));
+ openavbSaveConfig(DEFAULT_SAVE_INI_FILE, &x_cfg);
+ }
+ }
+
+ // We now have addresses we can use.
+ maapReservationId = mn->id;
+ maapState = MAAP_STATE_CONNECTED;
+ } else if (mn->id != -1) {
+ AVB_LOGF_ERROR("MAAP address range %d of size %d not acquired",
+ mn->id, mn->count);
+ maapState = MAAP_STATE_ERROR;
+ } else {
+ AVB_LOGF_ERROR("MAAP address range of size %d not acquired",
+ mn->count);
+ maapState = MAAP_STATE_ERROR;
+ }
+ break;
+ case MAAP_NOTIFY_RELEASED:
+ if (mn->result == MAAP_NOTIFY_ERROR_NONE) {
+ AVB_LOGF_DEBUG("MAAP address range %d released: 0x%012llx-0x%012llx (Size %d)",
+ mn->id,
+ (unsigned long long) mn->start,
+ (unsigned long long) mn->start + mn->count - 1,
+ mn->count);
+ maapState = MAAP_STATE_RELEASED;
+ } else {
+ AVB_LOGF_WARNING("MAAP address range %d not released",
+ mn->id);
+ }
+ break;
+ case MAAP_NOTIFY_STATUS:
+ if (mn->result == MAAP_NOTIFY_ERROR_NONE) {
+ AVB_LOGF_DEBUG("MAAP ID %d is address range 0x%012llx-0x%012llx (Size %d)",
+ mn->id,
+ (unsigned long long) mn->start,
+ (unsigned long long) mn->start + mn->count - 1,
+ mn->count);
+ } else {
+ AVB_LOGF_DEBUG("MAAP ID %d is not valid",
+ mn->id);
+ }
+ break;
+ case MAAP_NOTIFY_YIELDED:
+ if (mn->result != MAAP_NOTIFY_ERROR_REQUIRES_INITIALIZATION && mn->result != MAAP_NOTIFY_ERROR_RELEASE_INVALID_ID) {
+ if (mn->result != MAAP_NOTIFY_ERROR_NONE) {
+ AVB_LOGF_ERROR("MAAP Address range %d yielded: 0x%012llx-0x%012llx (Size %d). A new address range will not be allocated.",
+ mn->id,
+ (unsigned long long) mn->start,
+ (unsigned long long) mn->start + mn->count - 1,
+ mn->count);
+ maapState = MAAP_STATE_ERROR;
+ }
+ else {
+ AVB_LOGF_WARNING("MAAP Address range %d yielded: 0x%012llx-0x%012llx (Size %d)",
+ mn->id,
+ (unsigned long long) mn->start,
+ (unsigned long long) mn->start + mn->count - 1,
+ mn->count);
+ }
+ } else {
+ AVB_LOGF_ERROR("ID %d is not valid", mn->id);
+ }
+ break;
+ default:
+ AVB_LOGF_ERROR("MAAP notification type %d not recognized", mn->kind);
+ break;
+ }
+}
+
+
+/* Local function to interact with the MAAP daemon. */
+static void* maapThread(void *arg)
+{
+ int socketfd;
+ struct addrinfo hints, *ai, *p;
+ int ret;
+
+ fd_set master, read_fds;
+ int fdmax;
+
+ char recvbuffer[200];
+ int recvbytes;
+ Maap_Cmd maapcmd;
+
+ AVB_LOG_DEBUG("MAAP Thread Starting");
+
+ /* Create a localhost socket. */
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = 0;
+ if ((ret = getaddrinfo("localhost", maapDaemonPort, &hints, &ai)) != 0) {
+ AVB_LOGF_ERROR("getaddrinfo failure %s", gai_strerror(ret));
+ maapState = MAAP_STATE_ERROR;
+ return NULL;
+ }
+
+ for(p = ai; p != NULL; p = p->ai_next) {
+ socketfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
+ if (socketfd == -1) {
+ continue;
+ }
+ ret = connect(socketfd, p->ai_addr, p->ai_addrlen);
+ if (ret == -1) {
+ close(socketfd);
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ freeaddrinfo(ai);
+
+ if (p == NULL) {
+ AVB_LOGF_ERROR("MAAP: Unable to connect to the daemon, error %d (%s)", errno, strerror(errno));
+ maapState = MAAP_STATE_ERROR;
+ return NULL;
+ }
+
+ if (fcntl(socketfd, F_SETFL, O_NONBLOCK) < 0)
+ {
+ AVB_LOG_ERROR("MAAP: Could not set the socket to non-blocking");
+ close(socketfd);
+ maapState = MAAP_STATE_ERROR;
+ return NULL;
+ }
+
+ FD_ZERO(&read_fds);
+ FD_ZERO(&master);
+ FD_SET(STDIN_FILENO, &master);
+ FD_SET(socketfd, &master);
+ fdmax = socketfd;
+
+ // Initialize the MAAP daemon.
+ // We will request a block of addresses when we get a response to the initialization.
+ maapState = MAAP_STATE_INITIALIZING;
+ memset(&maapcmd, 0, sizeof(Maap_Cmd));
+ maapcmd.kind = MAAP_CMD_INIT;
+ maapcmd.start = MAAP_DYNAMIC_POOL_BASE;
+ maapcmd.count = MAAP_DYNAMIC_POOL_SIZE;
+ if (send(socketfd, (char *) &maapcmd, sizeof(Maap_Cmd), 0) < 0)
+ {
+ /* Something went wrong. Abort! */
+ AVB_LOGF_ERROR("MAAP: Error %d writing to network socket (%s)", errno, strerror(errno));
+ maapState = MAAP_STATE_ERROR;
+ return NULL;
+ }
+
+
+ /*
+ * Main event loop
+ */
+
+ while (maapRunning || maapState <= MAAP_STATE_CONNECTED)
+ {
+ if (!maapRunning && maapState == MAAP_STATE_CONNECTED)
+ {
+ // Tell the MAAP daemon to release the addresses.
+ memset(&maapcmd, 0, sizeof(Maap_Cmd));
+ maapcmd.kind = MAAP_CMD_RELEASE;
+ maapcmd.id = maapReservationId;
+ if (send(socketfd, (char *) &maapcmd, sizeof(Maap_Cmd), 0) > 0)
+ {
+ maapState = MAAP_STATE_RELEASING;
+ // Use the wait below to give the daemon time to respond.
+ }
+ else
+ {
+ maapState = MAAP_STATE_NOT_AVAILABLE;
+ break;
+ }
+ }
+
+ /* Wait for something to happen. */
+ struct timeval tv_timeout = { 1, 0 };
+ read_fds = master;
+ ret = select(fdmax+1, &read_fds, NULL, NULL, &tv_timeout);
+ if (ret < 0)
+ {
+ AVB_LOGF_ERROR("MAAP: select() error %d (%s)", errno, strerror(errno));
+ maapState = MAAP_STATE_ERROR;
+ break;
+ }
+
+ /* Handle any responses received. */
+ if (FD_ISSET(socketfd, &read_fds))
+ {
+ while ((recvbytes = recv(socketfd, recvbuffer, sizeof(Maap_Notify), 0)) > 0)
+ {
+ recvbuffer[recvbytes] = '\0';
+
+ /* Process the response data (will be binary). */
+ if (recvbytes == sizeof(Maap_Notify))
+ {
+ process_maap_notify((Maap_Notify *) recvbuffer, socketfd);
+ }
+ else
+ {
+ AVB_LOGF_WARNING("MAAP: Received unexpected response of size %d", recvbytes);
+ }
+ }
+ if (recvbytes == 0)
+ {
+ /* The MAAP daemon closed the connection. Assume it shut down, and we should too. */
+ // AVDECC_TODO: Should we try to reconnect?
+ AVB_LOG_ERROR("MAAP daemon exited.");
+ maapState = MAAP_STATE_ERROR;
+ break;
+ }
+ if (recvbytes < 0 && errno != EWOULDBLOCK)
+ {
+ /* Something went wrong. Abort! */
+ AVB_LOGF_ERROR("MAAP: Error %d reading from network socket (%s)", errno, strerror(errno));
+ maapState = MAAP_STATE_ERROR;
+ break;
+ }
+ }
+ }
+
+ if (maapState < MAAP_STATE_NOT_AVAILABLE) {
+ maapState = MAAP_STATE_NOT_AVAILABLE;
+ }
+
+ close(socketfd);
+
+ AVB_LOG_DEBUG("MAAP Thread Done");
+ return NULL;
+}
+
+bool openavbMaapInitialize(const char *ifname, unsigned int maapPort, struct ether_addr *maapPrefAddr, openavbMaapRestartCb_t* cbfn)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAAP);
+
+ // Save the supplied callback function.
+ maapRestartCallback = cbfn;
+ maapPreferredAddress = maapPrefAddr;
+
+ MUTEX_ATTR_HANDLE(mta);
+ MUTEX_ATTR_INIT(mta);
+ MUTEX_ATTR_SET_TYPE(mta, MUTEX_ATTR_TYPE_DEFAULT);
+ MUTEX_ATTR_SET_NAME(mta, "maapMutex");
+ MUTEX_CREATE_ERR();
+ MUTEX_CREATE(maapMutex, mta);
+ MUTEX_LOG_ERR("Could not create/initialize 'maapMutex' mutex");
+
+ // Default to using addresses from the MAAP locally administered Pool.
+ int i = 0;
+ U8 destAddr[ETH_ALEN] = {0x91, 0xe0, 0xf0, 0x00, 0xfe, 0x80};
+ for (i = 0; i < MAX_AVB_STREAMS; i++) {
+ memcpy(maapAllocList[i].destAddr.ether_addr_octet, destAddr, ETH_ALEN);
+ maapAllocList[i].taken = false;
+ destAddr[5] += 1;
+ }
+
+ if (maapPort == 0) {
+ maapState = MAAP_STATE_NOT_AVAILABLE;
+ }
+ else {
+ maapState = MAAP_STATE_UNKNOWN;
+ sprintf(maapDaemonPort, "%u", maapPort);
+
+ maapRunning = TRUE;
+ int err = pthread_create(&maapThreadHandle, NULL, maapThread, NULL);
+ if (err) {
+ maapRunning = FALSE;
+ maapState = MAAP_STATE_ERROR;
+ AVB_LOGF_ERROR("Failed to start MAAP thread: %s", strerror(err));
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAAP);
+ return true;
+}
+
+void openavbMaapFinalize()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAAP);
+
+ maapRestartCallback = NULL;
+ maapPreferredAddress = NULL;
+
+ if (maapRunning) {
+ // Stop the MAAP thread.
+ maapRunning = FALSE;
+ pthread_join(maapThreadHandle, NULL);
+ }
+
+ MUTEX_CREATE_ERR();
+ MUTEX_DESTROY(maapMutex);
+ MUTEX_LOG_ERR("Error destroying mutex");
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAAP);
+}
+
+bool openavbMaapDaemonAvailable(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAAP);
+
+ if (!maapRunning) {
+ AVB_TRACE_EXIT(AVB_TRACE_MAAP);
+ return FALSE;
+ }
+
+ // Wait up to 10 seconds for the daemon to give us a block of addresses.
+ int j;
+ for (j = 0; j < 10 * 1000 / 50 && maapState < MAAP_STATE_CONNECTED; ++j) {
+ AVB_LOG_DEBUG("Waiting for MAAP Daemon status");
+ SLEEP_MSEC(50);
+ }
+
+ if (maapState != MAAP_STATE_CONNECTED) {
+ if (maapState != MAAP_STATE_NOT_AVAILABLE) {
+ AVB_LOG_WARNING("MAAP Daemon not available. Fallback multicast address allocation will be used.");
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_MAAP);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAAP);
+ return TRUE;
+}
+
+void* openavbMaapAllocate(int count, /* out */ struct ether_addr *addr)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAAP);
+ assert(count == 1);
+
+ // Wait up to 10 seconds for the daemon to give us a block of addresses.
+ int j;
+ for (j = 0; j < 10 * 1000 / 50 && maapState < MAAP_STATE_CONNECTED; ++j) {
+ AVB_LOG_DEBUG("Waiting for MAAP Daemon status");
+ SLEEP_MSEC(50);
+ }
+
+ MAAP_LOCK();
+
+ // Find the next non-allocated address.
+ int i = 0;
+ while (i < MAX_AVB_STREAMS && maapAllocList[i].taken) {
+ i++;
+ }
+
+ // Allocate an address from the pool.
+ if (i < MAX_AVB_STREAMS) {
+ maapAllocList[i].taken = true;
+ memcpy(addr, maapAllocList[i].destAddr.ether_addr_octet, sizeof(struct ether_addr));
+ AVB_LOGF_INFO("Allocated MAAP address " ETH_FORMAT, ETH_OCTETS(addr->ether_addr_octet));
+
+ MAAP_UNLOCK();
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAAP);
+ return &maapAllocList[i];
+ }
+
+ MAAP_UNLOCK();
+
+ AVB_LOG_ERROR("All MAAP addresses already allocated");
+ AVB_TRACE_EXIT(AVB_TRACE_MAAP);
+ return NULL;
+}
+
+void openavbMaapRelease(void* handle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_MAAP);
+
+ MAAP_LOCK();
+ maapAlloc_t *elem = handle;
+ elem->taken = false;
+ AVB_LOGF_DEBUG("Freed MAAP address " ETH_FORMAT, ETH_OCTETS(elem->destAddr.ether_addr_octet));
+ MAAP_UNLOCK();
+
+ AVB_TRACE_EXIT(AVB_TRACE_MAAP);
+}
diff --git a/lib/avtp_pipeline/platform/x86_i210/openavb_time_hal.c b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_ptp.c
index 1a07a4bb..e74e7ac3 100644
--- a/lib/avtp_pipeline/platform/x86_i210/openavb_time_hal.c
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_ptp.c
@@ -1,72 +1,75 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-#include "openavb_platform.h"
-#include "openavb_time_hal.h"
-#include "openavb_ether_hal.h"
-
-#include "openavb_trace.h"
-
-#define AVB_LOG_COMPONENT "halTime"
-#include "openavb_pub.h"
-#include "openavb_log.h"
-
-static device_t *igb_dev = NULL;
-
-bool halTimeInitialize(void)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TIME);
- igb_dev = igbAcquireDevice();
- AVB_TRACE_EXIT(AVB_TRACE_TIME);
- return TRUE;
-}
-
-bool halTimeFinalize(void)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TIME);
- igbReleaseDevice(igb_dev);
- AVB_TRACE_EXIT(AVB_TRACE_TIME);
- return TRUE;
-}
-
-bool halTimeGetLocaltime(U64 *localTime64)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TIME);
-
- if (igb_get_wallclock(igb_dev, localTime64, NULL ) > 0) {
- IF_LOG_INTERVAL(1000) AVB_LOG_ERROR("Failed to get wallclock time");
- AVB_TRACE_EXIT(AVB_TRACE_TIME);
- return FALSE;
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_TIME);
- return TRUE;
-}
-
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "openavb_platform.h"
+#include "openavb_trace.h"
+#include "openavb_endpoint.h"
+
+#define AVB_LOG_COMPONENT "Endpoint PTP"
+//#define AVB_LOG_LEVEL AVB_LOG_LEVEL_DEBUG
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+
+inline int startPTP(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ // make sure ptp, a separate process, starts and is using the same interface as endpoint
+ int retVal = 0;
+// char ptpCmd[80];
+// memset(ptpCmd, 0, 80);
+// snprintf(ptpCmd, 80, "./openavb_gptp %s -i %s &", x_cfg.ptp_start_opts, x_cfg.ifname);
+// AVB_LOGF_INFO("PTP start command: %s", ptpCmd);
+// if (system(ptpCmd) != 0) {
+// AVB_LOG_ERROR("PTP failed to start - Exiting");
+// retVal = -1;
+// }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return retVal;
+}
+
+inline int stopPTP(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_ENDPOINT);
+
+ int retVal = 0;
+// if (system("killall -s SIGINT openavb_gptp") != 0) {
+// retVal = -1;
+// }
+
+ AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
+ return retVal;
+}
diff --git a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_shaper.c b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_shaper.c
new file mode 100644
index 00000000..f8d2c3b0
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_shaper.c
@@ -0,0 +1,426 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#include "openavb_platform.h"
+#include "openavb_trace.h"
+#include "openavb_shaper.h"
+#include "openavb_list.h"
+#include "openavb_rawsock.h"
+
+#define AVB_LOG_COMPONENT "Endpoint Shaper"
+//#define AVB_LOG_LEVEL AVB_LOG_LEVEL_DEBUG
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+
+/*******************************************************************************
+ * Shaper proxies
+ ******************************************************************************/
+
+#define STREAMDA_LENGTH 18
+
+#ifndef IFNAMSIZ
+#define IFNAMSIZ 16
+#endif
+#ifndef ETH_ALEN
+#define ETH_ALEN 6
+#endif
+
+typedef struct shaper_reservation
+{
+ int in_use;
+ SRClassIdx_t sr_class;
+ int measurement_interval; // microseconds
+ int max_frame_size; // bytes
+ int max_frames_per_interval; // number of frames per measurement_interval
+ unsigned char stream_da[ETH_ALEN];
+} shaper_reservation;
+
+#define MAX_SHAPER_RESERVATIONS 4
+static shaper_reservation shaperReservationList[MAX_SHAPER_RESERVATIONS];
+
+static bool shaperRunning = FALSE;
+static pthread_t shaperThreadHandle;
+static void* shaperThread(void *arg);
+
+enum shaperState_t {
+ SHAPER_STATE_UNKNOWN,
+ SHAPER_STATE_CONNECTED, // Connected, but shaping not enabled.
+ SHAPER_STATE_ENABLED, // Shaping enabled by the daemon
+ SHAPER_STATE_NOT_AVAILABLE, // Daemon not found or not connected.
+ SHAPER_STATE_ERROR
+};
+static enum shaperState_t shaperState = SHAPER_STATE_UNKNOWN;
+
+static int socketfd = -1;
+static char interfaceOnly[IFNAMSIZ];
+static char shaperDaemonPort[6] = {0};
+
+static MUTEX_HANDLE(shaperMutex);
+#define SHAPER_LOCK() { MUTEX_CREATE_ERR(); MUTEX_LOCK(shaperMutex); MUTEX_LOG_ERR("Mutex lock failure"); }
+#define SHAPER_UNLOCK() { MUTEX_CREATE_ERR(); MUTEX_UNLOCK(shaperMutex); MUTEX_LOG_ERR("Mutex unlock failure"); }
+
+
+/* Local function to interact with the SHAPER daemon. */
+static void* shaperThread(void *arg)
+{
+ struct addrinfo hints, *ai, *p;
+ int ret;
+
+ fd_set master, read_fds;
+ int fdmax;
+
+ char recvbuffer[200];
+ int recvbytes;
+
+ AVB_LOG_DEBUG("Shaper Thread Starting");
+
+ /* Create a localhost socket. */
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = 0;
+ if ((ret = getaddrinfo("localhost", shaperDaemonPort, &hints, &ai)) != 0) {
+ AVB_LOGF_ERROR("getaddrinfo failure %s", gai_strerror(ret));
+ shaperState = SHAPER_STATE_ERROR;
+ return NULL;
+ }
+
+ for(p = ai; p != NULL; p = p->ai_next) {
+ socketfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
+ if (socketfd == -1) {
+ continue;
+ }
+ ret = connect(socketfd, p->ai_addr, p->ai_addrlen);
+ if (ret == -1) {
+ close(socketfd);
+ socketfd = -1;
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ freeaddrinfo(ai);
+
+ if (p == NULL) {
+ AVB_LOGF_ERROR("Shaper: Unable to connect to the daemon, error %d (%s)", errno, strerror(errno));
+ shaperState = SHAPER_STATE_ERROR;
+ return NULL;
+ }
+
+ if (fcntl(socketfd, F_SETFL, O_NONBLOCK) < 0)
+ {
+ AVB_LOG_ERROR("Shaper: Could not set the socket to non-blocking");
+ close(socketfd);
+ socketfd = -1;
+ shaperState = SHAPER_STATE_ERROR;
+ return NULL;
+ }
+
+ FD_ZERO(&read_fds);
+ FD_ZERO(&master);
+ FD_SET(STDIN_FILENO, &master);
+ FD_SET(socketfd, &master);
+ fdmax = socketfd;
+
+
+ /*
+ * Main event loop
+ */
+
+ shaperState = SHAPER_STATE_CONNECTED;
+ AVB_LOG_INFO("Shaper daemon available");
+
+ while (shaperRunning || shaperState == SHAPER_STATE_ENABLED)
+ {
+ if (!shaperRunning && shaperState == SHAPER_STATE_ENABLED)
+ {
+ // TODO: Tell the SHAPER daemon to stop shaping.
+ break;
+ }
+
+ /* Wait for something to happen. */
+ struct timeval tv_timeout = { 1, 0 };
+ read_fds = master;
+ ret = select(fdmax+1, &read_fds, NULL, NULL, &tv_timeout);
+ if (ret < 0)
+ {
+ AVB_LOGF_ERROR("Shaper: select() error %d (%s)", errno, strerror(errno));
+ shaperState = SHAPER_STATE_ERROR;
+ break;
+ }
+
+ /* Handle any responses received. */
+ if (FD_ISSET(socketfd, &read_fds))
+ {
+ while ((recvbytes = recv(socketfd, recvbuffer, sizeof(recvbuffer) - 1, 0)) > 0)
+ {
+ /* Log the response data */
+ recvbuffer[recvbytes] = '\0';
+ if (strncmp(recvbuffer, "ERROR:", 6) == 0) {
+ AVB_LOGF_ERROR("Shaper Response: %s", recvbuffer + 7);
+ }
+ else if (strncmp(recvbuffer, "WARNING:", 8) == 0) {
+ AVB_LOGF_WARNING("Shaper Response: %s", recvbuffer + 9);
+ }
+ else if (strncmp(recvbuffer, "DEBUG:", 6) == 0) {
+ AVB_LOGF_DEBUG("Shaper Response: %s", recvbuffer + 7);
+ }
+ else {
+ AVB_LOGF_DEBUG("Shaper Response: %s", recvbuffer);
+ }
+ }
+ if (recvbytes == 0)
+ {
+ /* The SHAPER daemon closed the connection. Assume it shut down, and we should too. */
+ // AVDECC_TODO: Should we try to reconnect?
+ AVB_LOG_ERROR("Shaper daemon exited.");
+ shaperState = SHAPER_STATE_ERROR;
+ break;
+ }
+ if (recvbytes < 0 && errno != EWOULDBLOCK)
+ {
+ /* Something went wrong. Abort! */
+ AVB_LOGF_ERROR("Shaper: Error %d reading from network socket (%s)", errno, strerror(errno));
+ shaperState = SHAPER_STATE_ERROR;
+ break;
+ }
+ }
+ }
+
+ if (shaperState < SHAPER_STATE_NOT_AVAILABLE) {
+ shaperState = SHAPER_STATE_NOT_AVAILABLE;
+ }
+
+ close(socketfd);
+ socketfd = -1;
+
+ AVB_LOG_DEBUG("Shaper Thread Done");
+ return NULL;
+}
+
+bool openavbShaperInitialize(const char *ifname, unsigned int shaperPort)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_SHAPER);
+
+ MUTEX_ATTR_HANDLE(mta);
+ MUTEX_ATTR_INIT(mta);
+ MUTEX_ATTR_SET_TYPE(mta, MUTEX_ATTR_TYPE_DEFAULT);
+ MUTEX_ATTR_SET_NAME(mta, "shaperMutex");
+ MUTEX_CREATE_ERR();
+ MUTEX_CREATE(shaperMutex, mta);
+ MUTEX_LOG_ERR("Could not create/initialize 'shaperMutex' mutex");
+
+ memset(shaperReservationList, 0, sizeof(shaperReservationList));
+
+ if (shaperPort == 0) {
+ shaperState = SHAPER_STATE_NOT_AVAILABLE;
+ }
+ else {
+ shaperState = SHAPER_STATE_UNKNOWN;
+ sprintf(shaperDaemonPort, "%u", shaperPort);
+
+ // Save the interface-only name to pass to the daemon later.
+ const char *ifonly = strchr(ifname, ':');
+ if (ifonly) {
+ ifonly++; // Go past the colon
+ } else {
+ ifonly = ifname; // No colon in interface name
+ }
+ strncpy(interfaceOnly, ifonly, sizeof(interfaceOnly));
+ interfaceOnly[sizeof(interfaceOnly) - 1] = '\0';
+
+ shaperRunning = TRUE;
+ int err = pthread_create(&shaperThreadHandle, NULL, shaperThread, NULL);
+ if (err) {
+ shaperRunning = FALSE;
+ shaperState = SHAPER_STATE_ERROR;
+ AVB_LOGF_ERROR("Failed to start SHAPER thread: %s", strerror(err));
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_SHAPER);
+ return true;
+}
+
+void openavbShaperFinalize()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_SHAPER);
+
+ if (shaperRunning) {
+ // Stop the SHAPER thread.
+ shaperRunning = FALSE;
+ pthread_join(shaperThreadHandle, NULL);
+ }
+
+ MUTEX_CREATE_ERR();
+ MUTEX_DESTROY(shaperMutex);
+ MUTEX_LOG_ERR("Error destroying mutex");
+
+ AVB_TRACE_EXIT(AVB_TRACE_SHAPER);
+}
+
+bool openavbShaperDaemonAvailable(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_SHAPER);
+
+ if (!shaperRunning) {
+ AVB_TRACE_EXIT(AVB_TRACE_SHAPER);
+ return FALSE;
+ }
+
+ // Wait for the daemon to connect.
+ if (shaperState == SHAPER_STATE_UNKNOWN) {
+ SLEEP_MSEC(50);
+ }
+
+ if (shaperState > SHAPER_STATE_UNKNOWN && shaperState < SHAPER_STATE_NOT_AVAILABLE) {
+ AVB_TRACE_EXIT(AVB_TRACE_SHAPER);
+ return TRUE;
+ }
+
+ if (shaperState != SHAPER_STATE_NOT_AVAILABLE) {
+ AVB_LOG_WARNING("Shaper Daemon not available.");
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_SHAPER);
+ return FALSE;
+}
+
+void* openavbShaperHandle(SRClassIdx_t sr_class, int measurement_interval_usec, int max_frame_size_bytes, int max_frames_per_interval, const unsigned char * stream_da)
+{
+ // If the daemon is not available, abort!
+ if (socketfd == -1 || !openavbShaperDaemonAvailable())
+ {
+ AVB_LOG_ERROR("Shaper reservation attempted with no daemon available");
+ return NULL;
+ }
+
+ // Find the first available index.
+ int i;
+ for (i = 0; i < MAX_SHAPER_RESERVATIONS; ++i)
+ {
+ if (!(shaperReservationList[i].in_use))
+ {
+ break;
+ }
+ }
+ if (i >= MAX_SHAPER_RESERVATIONS)
+ {
+ AVB_LOG_ERROR("No Shaper reservations are available");
+ return NULL;
+ }
+
+ // Fill in the information.
+ shaperReservationList[i].in_use = TRUE;
+ shaperReservationList[i].sr_class = sr_class;
+ shaperReservationList[i].measurement_interval = measurement_interval_usec;
+ shaperReservationList[i].max_frame_size = max_frame_size_bytes;
+ shaperReservationList[i].max_frames_per_interval = max_frames_per_interval;
+ memcpy(shaperReservationList[i].stream_da, stream_da, ETH_ALEN);
+
+ // Send the information to the Shaper daemon.
+ // Reserving Bandwidth Example: -ri eth2 -c A -s 125 -b 74 -f 1 -a ff:ff:ff:ff:ff:11\n
+ char szCommand[200];
+ sprintf(szCommand, "-ri %s -c %c -s %u -b %u -f %u -a %02x:%02x:%02x:%02x:%02x:%02x",
+ interfaceOnly,
+ ( shaperReservationList[i].sr_class == SR_CLASS_A ? 'A' : 'B' ),
+ shaperReservationList[i].measurement_interval,
+ shaperReservationList[i].max_frame_size,
+ shaperReservationList[i].max_frames_per_interval,
+ shaperReservationList[i].stream_da[0],
+ shaperReservationList[i].stream_da[1],
+ shaperReservationList[i].stream_da[2],
+ shaperReservationList[i].stream_da[3],
+ shaperReservationList[i].stream_da[4],
+ shaperReservationList[i].stream_da[5]);
+ AVB_LOGF_DEBUG("Sending Shaper command: %s", szCommand);
+ strcat(szCommand, "\n");
+ if (send(socketfd, szCommand, strlen(szCommand), 0) < 0)
+ {
+ /* Something went wrong. Abort! */
+ AVB_LOGF_ERROR("Shaper: Error %d writing to network socket (%s)", errno, strerror(errno));
+ shaperState = SHAPER_STATE_ERROR;
+ return NULL;
+ }
+
+ shaperState = SHAPER_STATE_ENABLED;
+
+ // TODO: Verify that the command was successful.
+
+ return (void *)(&(shaperReservationList[i]));
+}
+
+void openavbShaperRelease(void* handle)
+{
+ int i;
+ for (i = 0; i < MAX_SHAPER_RESERVATIONS; ++i)
+ {
+ if (handle == (void *)(&(shaperReservationList[i])))
+ {
+ if (shaperReservationList[i].in_use)
+ {
+ // Send the information to the Shaper daemon.
+ // Unreserving Bandwidth Example: -ua ff:ff:ff:ff:ff:11\n
+ char szCommand[200];
+ sprintf(szCommand, "-ua %02x:%02x:%02x:%02x:%02x:%02x",
+ shaperReservationList[i].stream_da[0],
+ shaperReservationList[i].stream_da[1],
+ shaperReservationList[i].stream_da[2],
+ shaperReservationList[i].stream_da[3],
+ shaperReservationList[i].stream_da[4],
+ shaperReservationList[i].stream_da[5]);
+
+ shaperReservationList[i].in_use = FALSE;
+
+ AVB_LOGF_DEBUG("Sending Shaper command: %s", szCommand);
+ strcat(szCommand, "\n");
+ if (send(socketfd, szCommand, strlen(szCommand), 0) < 0)
+ {
+ /* Something went wrong. */
+ AVB_LOGF_ERROR("Shaper: Error %d writing to network socket (%s)", errno, strerror(errno));
+ shaperState = SHAPER_STATE_ERROR;
+ }
+ else {
+ // TODO: Verify that the command was successful.
+ }
+ }
+ break;
+ }
+ }
+}
diff --git a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_srp.c b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_srp.c
new file mode 100644
index 00000000..9a7d2b33
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_osal_srp.c
@@ -0,0 +1,412 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "openavb_platform.h"
+#include "openavb_trace.h"
+#include "openavb_endpoint.h"
+#include "openavb_srp.h"
+#include "mrp_client.h"
+#include "openavb_list.h"
+
+#define AVB_LOG_COMPONENT "Endpoint SRP"
+//#define AVB_LOG_LEVEL AVB_LOG_LEVEL_DEBUG
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+
+/*******************************************************************************
+ * SRP proxies
+ ******************************************************************************/
+
+static strmAttachCb_t _attachCb = NULL;
+static strmRegCb_t _registerCb = NULL;
+
+typedef struct {
+ void* avtpHandle;
+ bool talker;
+ U8 streamId[8];
+ U8 destAddr[6];
+ U16 vlanId;
+ int maxFrameSize;
+ int maxIntervalFrames;
+ int priority;
+ int latency;
+ int subtype;
+} strElem_t;
+
+openavb_list_t strElemList;
+
+#define SID_FORMAT "%02x:%02x:%02x:%02x:%02x:%02x/%u"
+#define SID_OCTETS(a) (a)[0],(a)[1],(a)[2],(a)[3],(a)[4],(a)[5],(a)[6]<<8|(a)[7]
+
+// Callback for SRP to notify AVTP Talker that a Listener Declaration has been
+// registered (or de-registered)
+void mrp_attach_cb(unsigned char streamid[8], int subtype)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
+
+ AVB_LOGF_DEBUG("mrp_attach_cb "SID_FORMAT" subtype %d", SID_OCTETS(streamid), subtype);
+
+ if (_attachCb) {
+ openavb_list_node_t node = openavbListIterFirst(strElemList);
+ while (node) {
+ strElem_t *elem = openavbListData(node);
+ if (elem && elem->talker && memcmp(streamid, elem->streamId, sizeof(elem->streamId)) == 0) {
+ _attachCb(elem->avtpHandle, subtype);
+ elem->subtype = subtype;
+ AVB_LOGF_DEBUG("mrp_attach_cb subtype changed to %d", elem->subtype);
+ break;
+ }
+ else if (elem) {
+ AVB_LOGF_DEBUG("mrp_attach_cb skipping elem " SID_FORMAT ", talker %d",
+ SID_OCTETS(elem->streamId), elem->talker ? 1 : 0);
+ }
+ node = openavbListIterNext(strElemList);
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
+}
+
+// Callback for SRP to notify AVTP Listener that a Talker Declaration has been
+// registered (or de-registered)
+void mrp_register_cb(unsigned char streamid[8], int join, unsigned char destaddr[6], unsigned int max_frame_size, unsigned int max_interval_frames, uint16_t vid, unsigned int latency)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
+
+ AVB_LOGF_DEBUG("mrp_register_cb "SID_FORMAT" "ETH_FORMAT" join %d max_frame_size %d max_interval_frames %d vid %d latency %d",
+ SID_OCTETS(streamid), ETH_OCTETS(destaddr), join, max_frame_size, max_interval_frames, vid, latency);
+
+ if (_registerCb) {
+ openavb_list_node_t node = openavbListIterFirst(strElemList);
+ while (node) {
+ strElem_t *elem = openavbListData(node);
+ if (elem && !elem->talker && memcmp(streamid, elem->streamId, sizeof(elem->streamId)) == 0) {
+ AVBTSpec_t tSpec;
+ tSpec.maxFrameSize = max_frame_size;
+ tSpec.maxIntervalFrames = max_interval_frames;
+ _registerCb(elem->avtpHandle,
+ join ? openavbSrp_AtTyp_TalkerAdvertise : openavbSrp_AtTyp_None,
+ destaddr,
+ &tSpec,
+ 0, // SR_CLASS is ignored anyway
+ latency,
+ NULL
+ );
+ elem->subtype = join;
+ AVB_LOGF_DEBUG("mrp_register_cb subtype changed to %d", elem->subtype);
+ break;
+ }
+ else if (elem) {
+ AVB_LOGF_DEBUG("mrp_register_cb skipping elem " SID_FORMAT ", talker %d",
+ SID_OCTETS(elem->streamId), elem->talker ? 1 : 0);
+ }
+ node = openavbListIterNext(strElemList);
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
+}
+
+openavbRC openavbSrpInitialize(strmAttachCb_t attachCb, strmRegCb_t registerCb,
+ char* ifname, U32 TxRateKbps, bool bypassAsCapableCheck)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
+ int err;
+
+ strElemList = openavbListNewList();
+
+ _attachCb = attachCb;
+ _registerCb = registerCb;
+
+
+ err = mrp_connect();
+ if (err) {
+ AVB_LOGF_ERROR("mrp_connect failed: %s", strerror(errno));
+ goto error;
+ }
+ err = mrp_monitor();
+ if (err) {
+ AVB_LOGF_ERROR("failed creating MRP monitor thread: %s", strerror(errno));
+ goto error;
+ }
+
+ int class_a_id, a_priority;
+ u_int16_t a_vid;
+ int class_b_id, b_priority;
+ u_int16_t b_vid;
+
+ err = mrp_get_domain(&class_a_id,&a_priority, &a_vid, &class_b_id, &b_priority, &b_vid);
+ if (err) {
+ AVB_LOG_DEBUG("mrp_get_domain failed");
+ goto error;
+ }
+
+ AVB_LOGF_INFO("detected domain Class A PRIO=%d VID=%04x...", a_priority, (int)a_vid);
+ AVB_LOGF_INFO("detected domain Class B PRIO=%d VID=%04x...", b_priority, (int)b_vid);
+
+ err = mrp_register_domain(&domain_class_a_id, &domain_class_a_priority, &domain_class_a_vid);
+ if (err) {
+ AVB_LOG_DEBUG("mrp_register_domain failed");
+ goto error;
+ }
+
+ err = mrp_register_domain(&domain_class_b_id, &domain_class_b_priority, &domain_class_b_vid);
+ if (err) {
+ AVB_LOG_DEBUG("mrp_register_domain failed");
+ goto error;
+ }
+
+ err = mrp_join_vlan();
+ if (err) {
+ AVB_LOG_DEBUG("mrp_join_vlan failed");
+ goto error;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
+ return OPENAVB_SRP_SUCCESS;
+
+error:
+ AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
+ return OPENAVB_SRP_FAILURE;
+}
+
+void openavbSrpShutdown(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
+ int err = mrp_disconnect();
+ if (err) {
+ AVB_LOGF_ERROR("mrp_disconnect failed: %s", strerror(errno));
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
+}
+
+openavbRC openavbSrpRegisterStream(void* avtpHandle,
+ AVBStreamID_t* _streamId,
+ U8 DA[],
+ AVBTSpec_t* tSpec,
+ SRClassIdx_t SRClassIdx,
+ bool Rank,
+ U32 Latency)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
+ int err;
+
+ // convert streamId to 8 byte format
+ uint8_t streamId[8];
+ memcpy(streamId, _streamId->addr, sizeof(_streamId->addr));
+ streamId[6] = _streamId->uniqueID >> 8;
+ streamId[7] = _streamId->uniqueID & 0xFF;
+
+ openavb_list_node_t node = openavbListNew(strElemList, sizeof(strElem_t));
+ strElem_t* elem = openavbListData(node);
+
+ elem->avtpHandle = avtpHandle;
+ elem->talker = true;
+ memcpy(elem->streamId, streamId, sizeof(elem->streamId));
+ memcpy(elem->destAddr, DA, sizeof(elem->destAddr));
+ elem->maxFrameSize = tSpec->maxFrameSize;
+ elem->maxIntervalFrames = tSpec->maxIntervalFrames;
+ elem->latency = Latency;
+ elem->subtype = openavbSrp_LDSt_None;
+
+ switch (SRClassIdx) {
+ case SR_CLASS_A:
+ elem->vlanId = domain_class_a_vid;
+ elem->priority = domain_class_a_priority;
+
+ err = mrp_advertise_stream(streamId,
+ DA,
+ domain_class_a_vid,
+ tSpec->maxFrameSize,
+ tSpec->maxIntervalFrames,
+ domain_class_a_priority,
+ Latency);
+ break;
+ case SR_CLASS_B:
+ elem->vlanId = domain_class_b_vid;
+ elem->priority = domain_class_b_priority;
+
+ err = mrp_advertise_stream(streamId,
+ DA,
+ domain_class_b_vid,
+ tSpec->maxFrameSize,
+ tSpec->maxIntervalFrames,
+ domain_class_b_priority,
+ Latency);
+ break;
+ default:
+ AVB_LOGF_ERROR("unknown SRClassIdx %d", (int)SRClassIdx);
+ goto error;
+ }
+
+ if (err) {
+ AVB_LOG_ERROR("mrp_advertise_stream failed");
+ goto error;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
+ return OPENAVB_SRP_SUCCESS;
+
+error:
+ AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
+ return OPENAVB_SRP_FAILURE;
+}
+
+openavbRC openavbSrpDeregisterStream(AVBStreamID_t* _streamId)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
+
+ // convert streamId to 8 byte format
+ uint8_t streamId[8];
+ memcpy(streamId, _streamId->addr, sizeof(_streamId->addr));
+ streamId[6] = _streamId->uniqueID >> 8;
+ streamId[7] = _streamId->uniqueID & 0xFF;
+
+ openavb_list_node_t node = openavbListIterFirst(strElemList);
+ while (node) {
+ strElem_t *elem = openavbListData(node);
+ if (elem && memcmp(streamId, elem->streamId, sizeof(elem->streamId)) == 0) {
+ int err = mrp_unadvertise_stream(elem->streamId, elem->destAddr, elem->vlanId, elem->maxFrameSize, elem->maxIntervalFrames, elem->priority, elem->latency);
+ if (err) {
+ AVB_LOG_ERROR("mrp_unadvertise_stream failed");
+ }
+ openavbListDelete(strElemList, node);
+ break;
+ }
+ node = openavbListIterNext(strElemList);
+ }
+ if (!node)
+ AVB_LOGF_ERROR("%s: unknown stream "SID_FORMAT, __func__, SID_OCTETS(streamId));
+ AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
+ return OPENAVB_SRP_SUCCESS;
+}
+
+openavbRC openavbSrpAttachStream(void* avtpHandle,
+ AVBStreamID_t* _streamId,
+ openavbSrpLsnrDeclSubtype_t type)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
+
+ // convert streamId to 8 byte format
+ uint8_t streamId[8];
+ memcpy(streamId, _streamId->addr, sizeof(_streamId->addr));
+ streamId[6] = _streamId->uniqueID >> 8;
+ streamId[7] = _streamId->uniqueID & 0xFF;
+
+ AVB_LOGF_DEBUG("openavbSrpAttachStream "SID_FORMAT, SID_OCTETS(streamId));
+
+ openavb_list_node_t node = openavbListIterFirst(strElemList);
+ // lets check if this streamId is on our list
+ while (node) {
+ strElem_t *elem = openavbListData(node);
+ if (elem && memcmp(streamId, elem->streamId, sizeof(elem->streamId)) == 0) {
+ break;
+ }
+ node = openavbListIterNext(strElemList);
+ }
+ if (!node) {
+ // not found so add it
+ node = openavbListNew(strElemList, sizeof(strElem_t));
+ strElem_t* elem = openavbListData(node);
+
+ elem->avtpHandle = avtpHandle;
+ elem->talker = false;
+ memcpy(elem->streamId, streamId, sizeof(elem->streamId));
+ elem->subtype = type;
+ }
+
+ int err = mrp_send_ready(streamId);
+ if (err) {
+ AVB_LOG_ERROR("mrp_send_ready failed");
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
+ return OPENAVB_SRP_SUCCESS;
+}
+
+openavbRC openavbSrpDetachStream(AVBStreamID_t* _streamId)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
+
+ // convert streamId to 8 byte format
+ uint8_t streamId[8];
+ memcpy(streamId, _streamId->addr, sizeof(_streamId->addr));
+ streamId[6] = _streamId->uniqueID >> 8;
+ streamId[7] = _streamId->uniqueID & 0xFF;
+
+ AVB_LOGF_DEBUG("openavbSrpDetachStream "SID_FORMAT, SID_OCTETS(streamId));
+
+ openavb_list_node_t node = openavbListIterFirst(strElemList);
+ while (node) {
+ strElem_t *elem = openavbListData(node);
+ if (elem && memcmp(streamId, elem->streamId, sizeof(elem->streamId)) == 0) {
+ int err = mrp_send_leave(streamId);
+ if (err) {
+ AVB_LOG_ERROR("mrp_send_leave failed");
+ }
+ openavbListDelete(strElemList, node);
+ break;
+ }
+ node = openavbListIterNext(strElemList);
+ }
+ if (!node)
+ AVB_LOGF_ERROR("%s: unknown stream "SID_FORMAT, __func__, SID_OCTETS(streamId));
+
+ AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
+ return OPENAVB_SRP_SUCCESS;
+}
+
+openavbRC openavbSrpGetClassParams(SRClassIdx_t SRClassIdx, U8* priority, U16* vid, U32* inverseIntervalSec)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_SRP_PUBLIC);
+ switch (SRClassIdx) {
+ case SR_CLASS_A:
+ *priority = domain_class_a_priority;
+ *vid = domain_class_a_vid;
+ *inverseIntervalSec = 8000;
+ break;
+ case SR_CLASS_B:
+ *priority = domain_class_b_priority;
+ *vid = domain_class_b_vid;
+ *inverseIntervalSec = 4000;
+ break;
+ default:
+ AVB_LOGF_ERROR("unknown SRClassIdx %d", (int)SRClassIdx);
+ AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
+ return OPENAVB_SRP_FAILURE;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_SRP_PUBLIC);
+ return OPENAVB_SRP_SUCCESS;
+}
diff --git a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_server_osal.c b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_server_osal.c
index c921d358..3454270f 100644
--- a/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_server_osal.c
+++ b/lib/avtp_pipeline/platform/Linux/endpoint/openavb_endpoint_server_osal.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -117,6 +118,11 @@ bool openavbEndpointServerOpen(void)
serverAddr.sun_family = AF_UNIX;
snprintf(serverAddr.sun_path, UNIX_PATH_MAX, AVB_ENDPOINT_UNIX_PATH);
+ // try remove old socket
+ if (unlink(serverAddr.sun_path) < 0 && errno != ENOENT) {
+ AVB_LOGF_ERROR("Failed to remove %s: %s", serverAddr.sun_path, strerror(errno));
+ }
+
int rslt = bind(lsock, (struct sockaddr*)&serverAddr, sizeof(struct sockaddr_un));
if (rslt != 0) {
AVB_LOGF_ERROR("Failed to create %s: %s", serverAddr.sun_path, strerror(errno));
@@ -140,7 +146,7 @@ bool openavbEndpointServerOpen(void)
error:
if (lsock >= 0) {
close(lsock);
- lsock = -1;
+ lsock = SOCK_INVALID;
}
AVB_TRACE_EXIT(AVB_TRACE_ENDPOINT);
return FALSE;
@@ -239,10 +245,12 @@ void openavbEndpointServerClose(void)
for (i = 0; i < POLL_FD_COUNT; i++) {
if (fds[i].fd != SOCK_INVALID) {
close(fds[i].fd);
+ fds[i].fd = SOCK_INVALID;
}
}
if (lsock != SOCK_INVALID) {
close(lsock);
+ lsock = SOCK_INVALID;
}
if (unlink(serverAddr.sun_path) != 0) {
diff --git a/lib/avtp_pipeline/platform/Linux/generic.cmake b/lib/avtp_pipeline/platform/Linux/generic.cmake
index a81a99ef..abe9fef8 100644
--- a/lib/avtp_pipeline/platform/Linux/generic.cmake
+++ b/lib/avtp_pipeline/platform/Linux/generic.cmake
@@ -1,17 +1,25 @@
# generic build settings
# just builds linux version of stack on host machine
+set ( AVB_FEATURE_IGB 0 )
+set ( IGB_LAUNCHTIME_ENABLED 0 )
+set ( AVB_FEATURE_PCAP 1 )
+
# Label for messages / build configuration
set ( OPENAVB_HAL "generic" )
set ( OPENAVB_OSAL "Linux" )
set ( OPENAVB_TCAL "GNU" )
set ( OPENAVB_PLATFORM "${OPENAVB_HAL}-${OPENAVB_OSAL}" )
-# point to our "proxy" linux/ptp_clock.h include file
-# which includes /usr/include/linux/ptp_clock.h
-# and adding missing defines just to make everything compile
+set ( PLATFORM_INCLUDE_DIRECTORIES
+ ${CMAKE_SOURCE_DIR}/openavb_common
+ ${CMAKE_SOURCE_DIR}/../../daemons/common
+ ${CMAKE_SOURCE_DIR}/../../daemons/mrpd
+ ${CMAKE_SOURCE_DIR}/../../daemons/maap/common
+)
+
include_directories ( platform/generic/include )
-set ( PLATFORM_DEFINE "AVB_DELAY_TWEAK_USEC=45" )
+#set ( PLATFORM_DEFINE "AVB_DELAY_TWEAK_USEC=45" )
set ( GSTREAMER_1_0 1 )
diff --git a/lib/avtp_pipeline/platform/Linux/gst_al/gst_al.h b/lib/avtp_pipeline/platform/Linux/gst_al/gst_al.h
index d55284ae..dbdb5b09 100644
--- a/lib/avtp_pipeline/platform/Linux/gst_al/gst_al.h
+++ b/lib/avtp_pipeline/platform/Linux/gst_al/gst_al.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/platform/Linux/gst_al/gst_al_01.c b/lib/avtp_pipeline/platform/Linux/gst_al/gst_al_01.c
index 86d7d475..9eedb4e8 100644
--- a/lib/avtp_pipeline/platform/Linux/gst_al/gst_al_01.c
+++ b/lib/avtp_pipeline/platform/Linux/gst_al/gst_al_01.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/platform/Linux/gst_al/gst_al_10.c b/lib/avtp_pipeline/platform/Linux/gst_al/gst_al_10.c
index a3fa8a47..0d1898c5 100644
--- a/lib/avtp_pipeline/platform/Linux/gst_al/gst_al_10.c
+++ b/lib/avtp_pipeline/platform/Linux/gst_al/gst_al_10.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_file_talker.ini b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_file_talker.ini
index 0eddb28f..210ae966 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_file_talker.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_file_talker.ini
@@ -5,6 +5,12 @@
# talker or listener
role = talker
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
#stream_addr = 00:25:64:48:ca:a8
@@ -121,3 +127,7 @@ intf_fn = openavbIntfWavFileInitialize
# intf_nv_file_name: The fully qualified file name.
intf_nv_file_name = test.wav
+
+# AAF is defined to be big-endian.
+intf_nv_audio_endian = big
+
diff --git a/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener.ini b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener.ini
index b04ca608..c7c799de 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener.ini
@@ -9,6 +9,12 @@
# talker or listener
role = listener
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
stream_addr = 84:7e:40:2b:63:f4
@@ -53,6 +59,10 @@ max_transit_usec = 50000
# Ethernet Interface Name. Only needed on some platforms when stack is built with no endpoint functionality
# ifname = eth0
+current_sampling_rate = 48000
+
+sampling_rates = 44100,48000,96000
+
#####################################################################
# Mapping module configuration
#####################################################################
@@ -105,15 +115,14 @@ intf_fn = openavbIntfAlsaInitialize
intf_nv_device_name = default
# intf_nv_audio_rate: Valid values that are supported by AAF are:
-# 8000, 16000, 32000, 44100, 48000, 88200, 96000, 176400 and 192000
+# 8000, 16000, 24000, 32000, 44100, 48000, 88200, 96000, 176400 and 192000
intf_nv_audio_rate = 48000
# intf_nv_audio_bit_depth: Valid values that are supported by AAF are:
-# 8, 16, 32
+# 16, 24, 32
intf_nv_audio_bit_depth = 32
-# intf_nv_audio_channels: Valid values that are supported by AAF are:
-# 1 - 8
+# intf_nv_audio_channels
intf_nv_audio_channels = 2
# intf_nv_allow_resampling: 0 = disable software resampling. 1 = allow software resampling. Default is disable.
@@ -127,3 +136,7 @@ intf_nv_start_threshold_periods = 3
# This influence ALSA's period_time and period_size parameters and the result value should be the nearest possible.
# Initial playback latency is equal intf_nv_start_threshold_periods * intf_nv_period_time. If not set internal defaults are used.
# intf_nv_period_time = 31250
+
+# AAF is defined to be big-endian.
+intf_nv_audio_endian = big
+
diff --git a/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener_auto.ini b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener_auto.ini
index 481dac65..d3d064b1 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener_auto.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_listener_auto.ini
@@ -9,6 +9,12 @@
# talker or listener
role = listener
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
stream_addr = ba:bc:1a:ba:bc:1a
@@ -105,15 +111,14 @@ intf_fn = openavbIntfAlsaInitialize
intf_nv_device_name = default
# intf_nv_audio_rate: Valid values that are supported by AAF are:
-# 8000, 16000, 32000, 44100, 48000, 88200, 96000, 176400 and 192000
+# 8000, 16000, 24000, 32000, 44100, 48000, 88200, 96000, 176400 and 192000
intf_nv_audio_rate = 48000
# intf_nv_audio_bit_depth: Valid values that are supported by AAF are:
-# 8, 16, 32
+# 16, 24, 32
intf_nv_audio_bit_depth = 16
-# intf_nv_audio_channels: Valid values that are supported by AAF are:
-# 1 - 8
+# intf_nv_audio_channels
intf_nv_audio_channels = 2
# intf_nv_allow_resampling: 0 = disable software resampling. 1 = allow software resampling. Default is disable.
@@ -127,3 +132,7 @@ intf_nv_start_threshold_periods = 3
# This influence ALSA's period_time and period_size parameters and the result value should be the nearest possible.
# Initial playback latency is equal intf_nv_start_threshold_periods * intf_nv_period_time. If not set internal defaults are used.
# intf_nv_period_time = 31250
+
+# AAF is defined to be big-endian.
+intf_nv_audio_endian = big
+
diff --git a/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_talker.ini b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_talker.ini
index f98ba668..a6a85071 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_talker.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/aaf_talker.ini
@@ -5,6 +5,12 @@
# talker or listener
role = talker
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
#stream_addr = 00:25:64:48:ca:a8
@@ -92,6 +98,10 @@ max_transmit_deficit_usec = 50000
# vlan_id: VLAN Identifier (1-4094). Used in "no endpoint" builds. Defaults to 2.
# vlan_id = 2
+current_sampling_rate = 48000
+
+sampling_rates = 44100,48000,96000
+
#####################################################################
# Mapping module configuration
#####################################################################
@@ -142,17 +152,19 @@ intf_fn = openavbIntfAlsaInitialize
intf_nv_device_name = default
# intf_nv_audio_rate: Valid values that are supported by AAF are:
-# 8000, 16000, 32000, 44100, 48000, 88200, 96000, 176400 and 192000
+# 8000, 16000, 24000, 32000, 44100, 48000, 88200, 96000, 176400 and 192000
intf_nv_audio_rate = 48000
# intf_nv_audio_bit_depth: Valid values that are supported by AAF are:
-# 8, 16, 32
+# 16, 24, 32
intf_nv_audio_bit_depth = 32
-# intf_nv_audio_channels: Valid values that are supported by AAF are:
-# 1 - 8
+# intf_nv_audio_channels
intf_nv_audio_channels = 2
# intf_nv_allow_resampling: 0 = disable software resampling. 1 = allow software resampling. Default is disable.
intf_nv_allow_resampling = 1
+# AAF is defined to be big-endian.
+intf_nv_audio_endian = big
+
diff --git a/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_intf.md b/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_intf.md
index cd97cf1a..123c4366 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_intf.md
+++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_intf.md
@@ -10,26 +10,17 @@ ALSA interface module. An interface to connect AVTP streams to ALSA either as an
Name | Description
--------------------------|---------------------------
-intf_nv_ignore_timestamp | If set to 1 timestamps will be ignored during \
- processing of frames. This also means stale (old) \
- Media Queue items will not be purged.
-intf_nv_device_name |ALSA device name. Commonly "default" or "plug:dmix"
-intf_nv_audio_rate |Audio rate, numberic values defined by \
- @ref avb_audio_rate_t
-intf_nv_audio_bit_depth |Bit depth of audio, numeric values defined by \
- @ref avb_audio_bit_depth_t
-intf_nv_audio_type |Type of data samples, possible values <ul><li>float \
- </li><li>sign</li><li>unsign</li><li>int</li><li> \
- uint</li></ul>
-intf_nv_audio_endian |Data endianess possible values <ul><li>big</li><li> \
- little</li></ul>
-intf_nv_audio_channels |Number of audio channels, numeric values should be \
- within range of values in @ref avb_audio_channels_t
-intf_nv_allow_resampling |If 1 software resampling allowed, disallowed \
- otherwise (by default allowed)
-intf_nv_start_threshold_periods|Playback start threshold measured in ALSA \
- periods (2 by default)
-intf_nv_period_time |Approximate ALSA period duration in microseconds
+intf_nv_ignore_timestamp | If set to 1 timestamps will be ignored during processing of frames. This also means stale (old) Media Queue items will not be purged.
+intf_nv_device_name | ALSA device name. Commonly "default" or "plug:dmix"
+intf_nv_audio_rate | Audio rate, numberic values defined by @ref avb_audio_rate_t
+intf_nv_audio_bit_depth | Bit depth of audio, numeric values defined by @ref avb_audio_bit_depth_t
+intf_nv_audio_type | Type of data samples, possible values <ul><li>float</li><li>sign</li><li>unsign</li><li>int</li><li>uint</li></ul>
+intf_nv_audio_endian | Data endianess possible values <ul><li>big</li><li>little</li></ul>
+intf_nv_audio_channels | Number of audio channels, numeric values should be within range of values in @ref avb_audio_channels_t
+intf_nv_allow_resampling | If 1 software resampling allowed, disallowed otherwise (by default allowed)
+intf_nv_start_threshold_periods | Playback start threshold measured in ALSA periods (2 by default)
+intf_nv_period_time | Approximate ALSA period duration in microseconds
+intf_nv_clock_skew_ppb | Estimate of media clock skew in Parts Per Billion (nanoseconds per second)
<br>
# Notes
diff --git a/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_listener.ini b/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_listener.ini
index 944616d1..545d8943 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_listener.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_listener.ini
@@ -9,6 +9,12 @@
# talker or listener
role = listener
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
#stream_addr = 08:00:28:31:E6:6E
diff --git a/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_talker.ini b/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_talker.ini
index e5908906..fc94f7f2 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_talker.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/alsa_talker.ini
@@ -9,6 +9,12 @@
# talker or listener
role = talker
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
#stream_addr = 00:25:64:48:ca:a8
diff --git a/lib/avtp_pipeline/platform/Linux/intf_alsa/openavb_intf_alsa.c b/lib/avtp_pipeline/platform/Linux/intf_alsa/openavb_intf_alsa.c
index 7685db93..37d29140 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_alsa/openavb_intf_alsa.c
+++ b/lib/avtp_pipeline/platform/Linux/intf_alsa/openavb_intf_alsa.c
@@ -1,16 +1,17 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
+
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -21,10 +22,10 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -42,11 +43,12 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_map_uncmp_audio_pub.h"
#include "openavb_map_aaf_audio_pub.h"
#include "openavb_intf_pub.h"
+#include "openavb_mcs.h"
#define AVB_LOG_COMPONENT "ALSA Interface"
#include "openavb_log_pub.h"
-// The asoundlib.h header needs to appear after openavb_trace_pub.h otherwise an incompatibtily version of time.h gets pulled in.
+// The asoundlib.h header needs to appear after openavb_trace_pub.h otherwise an incompatible version of time.h gets pulled in.
#include <alsa/asoundlib.h>
#define PCM_DEVICE_NAME_DEFAULT "default"
@@ -95,6 +97,15 @@ typedef struct {
// ALSA read/write interval
U32 intervalCounter;
+
+ // Media clock synthesis for precise timestamps
+ mcs_t mcs;
+
+ // Estimate of media clock skew in Parts Per Billion (ns per second)
+ S32 clockSkewPPB;
+
+ // Use Media Clock Synth module instead of timestamps taken during Tx callback
+ bool fixedTimestampEnabled;
} pvt_data_t;
@@ -217,7 +228,7 @@ static snd_pcm_format_t x_AVBAudioFormatToAlsaFormat(avb_audio_type_t type,
// Each configuration name value pair for this mapping will result in this callback being called.
-void openavbIntfAlsaCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
+void openavbIntfAlsaCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
{
AVB_TRACE_ENTRY(AVB_TRACE_INTF);
if (pMediaQ) {
@@ -279,7 +290,7 @@ void openavbIntfAlsaCfgCB(media_q_t *pMediaQ, const char *name, const char *valu
// TODO: Should check for specific values
if (val >= AVB_AUDIO_BIT_DEPTH_1BIT && val <= AVB_AUDIO_BIT_DEPTH_64BIT) {
pPvtData->audioBitDepth = val;
- }
+ }
else {
AVB_LOG_ERROR("Invalid audio type configured for intf_nv_audio_bits.");
pPvtData->audioBitDepth = AVB_AUDIO_BIT_DEPTH_24BIT;
@@ -380,12 +391,16 @@ void openavbIntfAlsaCfgCB(media_q_t *pMediaQ, const char *name, const char *valu
pPvtData->periodTimeUsec = strtol(value, &pEnd, 10);
}
+ else if (strcmp(name, "intf_nv_clock_skew_ppb") == 0) {
+ pPvtData->clockSkewPPB = strtol(value, &pEnd, 10);
+ }
+
}
AVB_TRACE_EXIT(AVB_TRACE_INTF);
}
-void openavbIntfAlsaGenInitCB(media_q_t *pMediaQ)
+void openavbIntfAlsaGenInitCB(media_q_t *pMediaQ)
{
AVB_TRACE_ENTRY(AVB_TRACE_INTF);
AVB_TRACE_EXIT(AVB_TRACE_INTF);
@@ -393,7 +408,7 @@ void openavbIntfAlsaGenInitCB(media_q_t *pMediaQ)
// A call to this callback indicates that this interface module will be
// a talker. Any talker initialization can be done in this function.
-void openavbIntfAlsaTxInitCB(media_q_t *pMediaQ)
+void openavbIntfAlsaTxInitCB(media_q_t *pMediaQ)
{
AVB_TRACE_ENTRY(AVB_TRACE_INTF);
@@ -427,7 +442,7 @@ void openavbIntfAlsaTxInitCB(media_q_t *pMediaQ)
return;
}
- // Initialize the hardware paramneters
+ // Initialize the hardware parameters
rslt = snd_pcm_hw_params_any(pPvtData->pcmHandle, hwParams);
if (rslt < 0) {
AVB_LOGF_ERROR("snd_pcm_hw_params_any() error: %s", snd_strerror(rslt));
@@ -466,7 +481,7 @@ void openavbIntfAlsaTxInitCB(media_q_t *pMediaQ)
// Set the sample format
int fmt = x_AVBAudioFormatToAlsaFormat(pPvtData->audioType,
pPvtData->audioBitDepth,
- pPvtData->audioEndian,
+ pPvtData->audioEndian,
pMediaQ->pMediaQDataFormat);
rslt = snd_pcm_hw_params_set_format(pPvtData->pcmHandle, hwParams, fmt);
if (rslt < 0) {
@@ -537,14 +552,23 @@ void openavbIntfAlsaTxInitCB(media_q_t *pMediaQ)
snd_output_t* out;
snd_output_stdio_attach(&out, stderr, 0);
snd_pcm_dump(pPvtData->pcmHandle, out);
- }
+ snd_output_close(out);
+ // Start capture
+ snd_pcm_start(pPvtData->pcmHandle);
+ {
+ media_q_pub_map_uncmp_audio_info_t *pPubMapUncmpAudioInfo = pMediaQ->pPubMapInfo;
+
+ AVB_LOGF_INFO("Finished ALSA Setup: packingFactor %d", pPubMapUncmpAudioInfo->packingFactor);
+ }
+ }
AVB_TRACE_EXIT(AVB_TRACE_INTF);
}
-// This callback will be called for each AVB transmit interval.
+// This callback will be called for each AVB transmit interval.
bool openavbIntfAlsaTxCB(media_q_t *pMediaQ)
{
+ bool moreItems = TRUE;
AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
S32 rslt;
@@ -555,72 +579,77 @@ bool openavbIntfAlsaTxCB(media_q_t *pMediaQ)
media_q_item_t *pMediaQItem = NULL;
if (!pPvtData) {
AVB_LOG_ERROR("Private interface module data not allocated.");
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
return FALSE;
}
- //put current wall time into tail item used by AAF mapping module
- if ((pPubMapUncmpAudioInfo->sparseMode != TS_SPARSE_MODE_UNSPEC)) {
- pMediaQItem = openavbMediaQTailLock(pMediaQ, TRUE);
- if ((pMediaQItem) && (pPvtData->intervalCounter % pPubMapUncmpAudioInfo->sparseMode == 0)) {
- openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
- }
- openavbMediaQTailUnlock(pMediaQ);
- pMediaQItem = NULL;
- }
- if (pPvtData->intervalCounter++ % pPubMapUncmpAudioInfo->packingFactor != 0)
+ if (pPvtData->intervalCounter++ % pPubMapUncmpAudioInfo->packingFactor != 0) {
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
return TRUE;
+ }
- pMediaQItem = openavbMediaQHeadLock(pMediaQ);
- if (pMediaQItem) {
- if (pMediaQItem->itemSize < pPubMapUncmpAudioInfo->itemSize) {
- AVB_LOG_ERROR("Media queue item not large enough for samples");
- }
+ while (moreItems) {
+ pMediaQItem = openavbMediaQHeadLock(pMediaQ);
+ if (pMediaQItem) {
+ if (pMediaQItem->itemSize < pPubMapUncmpAudioInfo->itemSize) {
+ AVB_LOG_ERROR("Media queue item not large enough for samples");
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
+ return FALSE;
+ }
- rslt = snd_pcm_readi(pPvtData->pcmHandle, pMediaQItem->pPubData + pMediaQItem->dataLen, pPubMapUncmpAudioInfo->framesPerItem - (pMediaQItem->dataLen / pPubMapUncmpAudioInfo->itemFrameSizeBytes));
+ rslt = snd_pcm_readi(pPvtData->pcmHandle, pMediaQItem->pPubData + pMediaQItem->dataLen, pPubMapUncmpAudioInfo->framesPerItem - (pMediaQItem->dataLen / pPubMapUncmpAudioInfo->itemFrameSizeBytes));
- if (rslt == -EPIPE) {
- AVB_LOGF_ERROR("snd_pcm_readi() error: %s", snd_strerror(rslt));
- rslt = snd_pcm_recover(pPvtData->pcmHandle, rslt, 0);
if (rslt < 0) {
- AVB_LOGF_ERROR("snd_pcm_recover: %s", snd_strerror(rslt));
+ switch(rslt) {
+ case -EPIPE:
+ AVB_LOGF_ERROR("snd_pcm_readi() error: %s", snd_strerror(rslt));
+ rslt = snd_pcm_recover(pPvtData->pcmHandle, rslt, 0);
+ if (rslt < 0) {
+ AVB_LOGF_ERROR("snd_pcm_recover: %s", snd_strerror(rslt));
+ }
+ break;
+ case -EAGAIN:
+ { IF_LOG_INTERVAL(1000) AVB_LOG_DEBUG("snd_pcm_readi() had no data available"); }
+ break;
+ default:
+ AVB_LOGF_ERROR("Unhandled snd_pcm_readi() error: %s", snd_strerror(rslt));
+ break;
+ }
+
+ if (rslt < 0) {
+ openavbMediaQHeadUnlock(pMediaQ);
+ break;
+ }
}
- openavbMediaQHeadUnlock(pMediaQ);
- AVB_TRACE_EXIT(AVB_TRACE_INTF);
- return FALSE;
- }
- if (rslt < 0) {
- openavbMediaQHeadUnlock(pMediaQ);
- AVB_TRACE_EXIT(AVB_TRACE_INTF);
- return FALSE;
- }
- pMediaQItem->dataLen += rslt * pPubMapUncmpAudioInfo->itemFrameSizeBytes;
- if (pMediaQItem->dataLen != pPubMapUncmpAudioInfo->itemSize) {
- openavbMediaQHeadUnlock(pMediaQ);
- AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
- return TRUE;
+ pMediaQItem->dataLen += rslt * pPubMapUncmpAudioInfo->itemFrameSizeBytes;
+ if (pMediaQItem->dataLen != pPubMapUncmpAudioInfo->itemSize) {
+ openavbMediaQHeadUnlock(pMediaQ);
+ }
+ else {
+ // Always get the timestamp. Protocols such as AAF can choose to ignore them if not needed.
+ if (!pPvtData->fixedTimestampEnabled) {
+ openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
+ } else {
+ openavbMcsAdvance(&pPvtData->mcs);
+ openavbAvtpTimeSetToTimestampNS(pMediaQItem->pAvtpTime, pPvtData->mcs.edgeTime);
+ }
+ openavbMediaQHeadPush(pMediaQ);
+ }
}
else {
- openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
- openavbMediaQHeadPush(pMediaQ);
-
- AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
- return TRUE;
+ moreItems = FALSE;
}
}
- else {
- AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
- return FALSE; // Media queue full
- }
}
AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
- return FALSE;
+ return !moreItems;
}
// A call to this callback indicates that this interface module will be
// a listener. Any listener initialization can be done in this function.
-void openavbIntfAlsaRxInitCB(media_q_t *pMediaQ)
+void openavbIntfAlsaRxInitCB(media_q_t *pMediaQ)
{
AVB_TRACE_ENTRY(AVB_TRACE_INTF);
@@ -656,7 +685,7 @@ void openavbIntfAlsaRxInitCB(media_q_t *pMediaQ)
return;
}
- // Initialize the hardware paramneters
+ // Initialize the hardware parameters
rslt = snd_pcm_hw_params_any(pPvtData->pcmHandle, hwParams);
if (rslt < 0) {
AVB_LOGF_ERROR("snd_pcm_hw_params_any() error: %s", snd_strerror(rslt));
@@ -695,7 +724,7 @@ void openavbIntfAlsaRxInitCB(media_q_t *pMediaQ)
// Set the sample format
int fmt = x_AVBAudioFormatToAlsaFormat(pPvtData->audioType,
pPvtData->audioBitDepth,
- pPvtData->audioEndian,
+ pPvtData->audioEndian,
pMediaQ->pMediaQDataFormat);
rslt = snd_pcm_hw_params_set_format(pPvtData->pcmHandle, hwParams, fmt);
if (rslt < 0) {
@@ -764,7 +793,7 @@ void openavbIntfAlsaRxInitCB(media_q_t *pMediaQ)
buffer_time = (max / usec_round) * usec_round;
}
- // Check for maximum perioid time and adjust ours down if necessary
+ // Check for maximum period time and adjust ours down if necessary
rslt = snd_pcm_hw_params_get_period_time_max(hwParams, &max, &dir);
if (rslt < 0) {
AVB_LOGF_ERROR("snd_pcm_hw_params_get_period_time_max() error: %s", snd_strerror(rslt));
@@ -849,6 +878,8 @@ void openavbIntfAlsaRxInitCB(media_q_t *pMediaQ)
AVB_LOGF_ERROR("snd_pcm_sw_params_malloc error(): %s", snd_strerror(rslt));
snd_pcm_close(pPvtData->pcmHandle);
pPvtData->pcmHandle = NULL;
+ snd_pcm_sw_params_free(swParams);
+ swParams = NULL;
AVB_TRACE_EXIT(AVB_TRACE_INTF);
return;
}
@@ -858,6 +889,8 @@ void openavbIntfAlsaRxInitCB(media_q_t *pMediaQ)
AVB_LOGF_ERROR("snd_pcm_sw_params_current error(): %s", snd_strerror(rslt));
snd_pcm_close(pPvtData->pcmHandle);
pPvtData->pcmHandle = NULL;
+ snd_pcm_sw_params_free(swParams);
+ swParams = NULL;
AVB_TRACE_EXIT(AVB_TRACE_INTF);
return;
}
@@ -867,6 +900,8 @@ void openavbIntfAlsaRxInitCB(media_q_t *pMediaQ)
AVB_LOGF_ERROR("snd_pcm_sw_params_set_start_threshold error(): %s", snd_strerror(rslt));
snd_pcm_close(pPvtData->pcmHandle);
pPvtData->pcmHandle = NULL;
+ snd_pcm_sw_params_free(swParams);
+ swParams = NULL;
AVB_TRACE_EXIT(AVB_TRACE_INTF);
return;
}
@@ -876,6 +911,8 @@ void openavbIntfAlsaRxInitCB(media_q_t *pMediaQ)
AVB_LOGF_ERROR("snd_pcm_sw_params_set_avail_min error(): %s", snd_strerror(rslt));
snd_pcm_close(pPvtData->pcmHandle);
pPvtData->pcmHandle = NULL;
+ snd_pcm_sw_params_free(swParams);
+ swParams = NULL;
AVB_TRACE_EXIT(AVB_TRACE_INTF);
return;
}
@@ -885,6 +922,8 @@ void openavbIntfAlsaRxInitCB(media_q_t *pMediaQ)
AVB_LOGF_ERROR("snd_pcm_sw_params_set_period_event error(): %s", snd_strerror(rslt));
snd_pcm_close(pPvtData->pcmHandle);
pPvtData->pcmHandle = NULL;
+ snd_pcm_sw_params_free(swParams);
+ swParams = NULL;
AVB_TRACE_EXIT(AVB_TRACE_INTF);
return;
}
@@ -894,6 +933,8 @@ void openavbIntfAlsaRxInitCB(media_q_t *pMediaQ)
AVB_LOGF_ERROR("snd_pcm_sw_params error(): %s", snd_strerror(rslt));
snd_pcm_close(pPvtData->pcmHandle);
pPvtData->pcmHandle = NULL;
+ snd_pcm_sw_params_free(swParams);
+ swParams = NULL;
AVB_TRACE_EXIT(AVB_TRACE_INTF);
return;
}
@@ -917,13 +958,14 @@ void openavbIntfAlsaRxInitCB(media_q_t *pMediaQ)
snd_output_t* out;
snd_output_stdio_attach(&out, stderr, 0);
snd_pcm_dump(pPvtData->pcmHandle, out);
+ snd_output_close(out);
}
AVB_TRACE_EXIT(AVB_TRACE_INTF);
}
// This callback is called when acting as a listener.
-bool openavbIntfAlsaRxCB(media_q_t *pMediaQ)
+bool openavbIntfAlsaRxCB(media_q_t *pMediaQ)
{
AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
@@ -932,6 +974,7 @@ bool openavbIntfAlsaRxCB(media_q_t *pMediaQ)
pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
if (!pPvtData) {
AVB_LOG_ERROR("Private interface module data not allocated.");
+ AVB_TRACE_EXIT(AVB_TRACE_INTF_DETAIL);
return FALSE;
}
@@ -975,9 +1018,9 @@ bool openavbIntfAlsaRxCB(media_q_t *pMediaQ)
return TRUE;
}
-// This callback will be called when the interface needs to be closed. All shutdown should
+// This callback will be called when the interface needs to be closed. All shutdown should
// occur in this function.
-void openavbIntfAlsaEndCB(media_q_t *pMediaQ)
+void openavbIntfAlsaEndCB(media_q_t *pMediaQ)
{
AVB_TRACE_ENTRY(AVB_TRACE_INTF);
@@ -991,18 +1034,56 @@ void openavbIntfAlsaEndCB(media_q_t *pMediaQ)
if (pPvtData->pcmHandle) {
snd_pcm_close(pPvtData->pcmHandle);
pPvtData->pcmHandle = NULL;
+
+#if 0
+ // Optional call when using Valgrind to stop reports of memory leaks.
+ snd_config_update_free_global();
+#endif
}
}
AVB_TRACE_EXIT(AVB_TRACE_INTF);
}
-void openavbIntfAlsaGenEndCB(media_q_t *pMediaQ)
+void openavbIntfAlsaGenEndCB(media_q_t *pMediaQ)
{
AVB_TRACE_ENTRY(AVB_TRACE_INTF);
AVB_TRACE_EXIT(AVB_TRACE_INTF);
}
+void openavbIntfAlsaEnableFixedTimestamp(media_q_t *pMediaQ, bool enabled, U32 transmitInterval, U32 batchFactor)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ if (pMediaQ && pMediaQ->pPvtIntfInfo && pMediaQ->pPubMapInfo) {
+ media_q_pub_map_uncmp_audio_info_t *pPubMapUncmpAudioInfo = pMediaQ->pPubMapInfo;
+ pvt_data_t *pPvtData = (pvt_data_t *)pMediaQ->pPvtIntfInfo;
+
+ pPvtData->fixedTimestampEnabled = enabled;
+ if (pPvtData->fixedTimestampEnabled) {
+ U32 per, rate, rem;
+ S32 skewEst = pPvtData->clockSkewPPB;
+ /* Ignore passed in transmit interval and use framesPerItem and audioRate so
+ we work with both AAF and 61883-6 */
+ /* Carefully scale values to avoid U32 overflow or loss of precision */
+ per = MICROSECONDS_PER_SECOND * pPubMapUncmpAudioInfo->framesPerItem * 10;
+ per += (skewEst/10);
+ rate = pPvtData->audioRate/100;
+ transmitInterval = per/rate;
+ rem = per % rate;
+ if (rem != 0) {
+ rem *= 10;
+ rem /= rate;
+ }
+ openavbMcsInit(&pPvtData->mcs, transmitInterval, rem, 10);
+ AVB_LOGF_INFO("Fixed timestamping enabled: %d %d/%d", transmitInterval, rem, 10);
+ }
+
+ }
+
+
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
// Main initialization entry point into the interface module
extern DLL_EXPORT bool openavbIntfAlsaInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB)
{
@@ -1026,6 +1107,7 @@ extern DLL_EXPORT bool openavbIntfAlsaInitialize(media_q_t *pMediaQ, openavb_int
pIntfCB->intf_rx_cb = openavbIntfAlsaRxCB;
pIntfCB->intf_end_cb = openavbIntfAlsaEndCB;
pIntfCB->intf_gen_end_cb = openavbIntfAlsaGenEndCB;
+ pIntfCB->intf_enable_fixed_timestamp = openavbIntfAlsaEnableFixedTimestamp;
pPvtData->ignoreTimestamp = FALSE;
pPvtData->pDeviceName = strdup(PCM_DEVICE_NAME_DEFAULT);
@@ -1034,6 +1116,8 @@ extern DLL_EXPORT bool openavbIntfAlsaInitialize(media_q_t *pMediaQ, openavb_int
pPvtData->startThresholdPeriods = 2; // Default to 2 periods of frames as the start threshold
pPvtData->periodTimeUsec = 100000;
+ pPvtData->fixedTimestampEnabled = FALSE;
+ pPvtData->clockSkewPPB = 0;
}
AVB_TRACE_EXIT(AVB_TRACE_INTF);
diff --git a/lib/avtp_pipeline/platform/Linux/intf_h264_gst/h264_gst_listener.ini b/lib/avtp_pipeline/platform/Linux/intf_h264_gst/h264_gst_listener.ini
index 9817900c..6de30dc5 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_h264_gst/h264_gst_listener.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_h264_gst/h264_gst_listener.ini
@@ -5,6 +5,12 @@
# talker or listener
role = listener
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
stream_addr = ba:bc:1a:ba:bc:1a
diff --git a/lib/avtp_pipeline/platform/Linux/intf_h264_gst/h264_gst_talker.ini b/lib/avtp_pipeline/platform/Linux/intf_h264_gst/h264_gst_talker.ini
index 87569675..e69bf5bf 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_h264_gst/h264_gst_talker.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_h264_gst/h264_gst_talker.ini
@@ -5,6 +5,12 @@
# talker or listener
role = talker
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
stream_addr = ba:bc:1a:ba:bc:1a
diff --git a/lib/avtp_pipeline/platform/Linux/intf_h264_gst/openavb_intf_h264_gst.c b/lib/avtp_pipeline/platform/Linux/intf_h264_gst/openavb_intf_h264_gst.c
index 35af240f..1be182d1 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_h264_gst/openavb_intf_h264_gst.c
+++ b/lib/avtp_pipeline/platform/Linux/intf_h264_gst/openavb_intf_h264_gst.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -70,6 +71,8 @@ typedef struct pvt_data_t
bool blockingRx;
gint nWaiting;
+ bool firstSample;
+ U16 stream_uid;
} pvt_data_t;
// Each configuration name value pair for this mapping will result in this callback being called.
@@ -144,6 +147,11 @@ static GstFlowReturn sinkNewBufferSample(GstAppSink *sink, gpointer pv)
media_q_t *pMediaQ = (media_q_t *)pv;
pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (pPvtData->firstSample) {
+ AVB_LOGF_WARNING("UID: %d: First sample to send", pPvtData->stream_uid);
+ pPvtData->firstSample = false;
+ }
+
g_atomic_int_add(&pPvtData->nWaiting, 1);
return GST_FLOW_OK;
@@ -252,6 +260,8 @@ void openavbIntfH264RtpGstTxInitCB(media_q_t *pMediaQ)
return;
}
+ pPvtData->firstSample = true;
+
createTxPipeline(pMediaQ);
AVB_TRACE_EXIT(AVB_TRACE_INTF);
@@ -430,6 +440,8 @@ void openavbIntfH264RtpGstRxInitCB(media_q_t *pMediaQ)
return;
}
+ pPvtData->firstSample = true;
+
GError *error = NULL;
pPvtData->pipe = gst_parse_launch(pPvtData->pPipelineStr, &error);
if (error)
@@ -504,6 +516,12 @@ bool openavbIntfH264RtpGstRxCB(media_q_t *pMediaQ)
openavbMediaQTailPull(pMediaQ);
continue;
}
+
+ if (pPvtData->firstSample) {
+ AVB_LOGF_WARNING("UID: %d: First packet RX", pPvtData->stream_uid);
+ pPvtData->firstSample = false;
+ }
+
if (pPvtData->asyncRx)
{
U32 bufwr = pPvtData->bufwr;
@@ -587,6 +605,19 @@ void openavbIntfH264RtpGstGenEndCB(media_q_t *pMediaQ)
AVB_TRACE_EXIT(AVB_TRACE_INTF);
}
+void openavbIntfH264RtpGstSetStreamUidCB(media_q_t *pMediaQ, U16 stream_uid)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_INTF);
+ pvt_data_t *pPvtData = pMediaQ->pPvtIntfInfo;
+ if (!pPvtData)
+ {
+ AVB_LOG_ERROR("Private interface module data not allocated.");
+ return;
+ }
+ pPvtData->stream_uid = stream_uid;
+ AVB_TRACE_EXIT(AVB_TRACE_INTF);
+}
+
// Main initialization entry point into the interface module
extern DLL_EXPORT bool openavbIntfH264RtpGstInitialize(media_q_t *pMediaQ, openavb_intf_cb_t *pIntfCB)
{
@@ -611,6 +642,7 @@ extern DLL_EXPORT bool openavbIntfH264RtpGstInitialize(media_q_t *pMediaQ, opena
pIntfCB->intf_rx_cb = openavbIntfH264RtpGstRxCB;
pIntfCB->intf_end_cb = openavbIntfH264RtpGstEndCB;
pIntfCB->intf_gen_end_cb = openavbIntfH264RtpGstGenEndCB;
+ pIntfCB->intf_set_stream_uid_cb = openavbIntfH264RtpGstSetStreamUidCB;
pPvtData->ignoreTimestamp = FALSE;
diff --git a/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_gst_listener.ini b/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_gst_listener.ini
index 80b742ca..07ebc7fb 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_gst_listener.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_gst_listener.ini
@@ -5,6 +5,12 @@
# talker or listener
role = listener
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
stream_addr = 00:50:56:c0:00:08
diff --git a/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_gst_talker.ini b/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_gst_talker.ini
index 7e906a76..2fb8810d 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_gst_talker.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/mjpeg_gst_talker.ini
@@ -5,6 +5,12 @@
# talker or listener
role = talker
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
#stream_addr = 00:25:64:48:ca:a8
diff --git a/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/openavb_intf_mjpeg_gst.c b/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/openavb_intf_mjpeg_gst.c
index db2aafa6..9c190579 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/openavb_intf_mjpeg_gst.c
+++ b/lib/avtp_pipeline/platform/Linux/intf_mjpeg_gst/openavb_intf_mjpeg_gst.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/mpeg2ts_file_listener.ini b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/mpeg2ts_file_listener.ini
index eb76cb7d..691b8bb1 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/mpeg2ts_file_listener.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/mpeg2ts_file_listener.ini
@@ -5,6 +5,12 @@
# talker or listener
role = listener
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
stream_addr = 00:0c:29:f8:3e:c6
diff --git a/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/mpeg2ts_file_talker.ini b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/mpeg2ts_file_talker.ini
index b5bf26d0..8756dbea 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/mpeg2ts_file_talker.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/mpeg2ts_file_talker.ini
@@ -5,6 +5,12 @@
# talker or listener
role = talker
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
#stream_addr = 00:25:64:48:ca:a8
diff --git a/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/openavb_intf_mpeg2ts_file.c b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/openavb_intf_mpeg2ts_file.c
index 311ec767..5ab9f5b9 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/openavb_intf_mpeg2ts_file.c
+++ b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_file/openavb_intf_mpeg2ts_file.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/mpeg2ts_gst_listener.ini b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/mpeg2ts_gst_listener.ini
index bf7ef6b7..9c40b574 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/mpeg2ts_gst_listener.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/mpeg2ts_gst_listener.ini
@@ -5,6 +5,12 @@
# talker or listener
role = listener
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
stream_addr = 84:7E:40:2B:73:D6
diff --git a/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/mpeg2ts_gst_talker.ini b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/mpeg2ts_gst_talker.ini
index 0cc3299b..63a7d5da 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/mpeg2ts_gst_talker.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/mpeg2ts_gst_talker.ini
@@ -5,6 +5,12 @@
# talker or listener
role = talker
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
#stream_addr = 00:25:64:48:ca:a8
diff --git a/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/openavb_intf_mpeg2ts_gst.c b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/openavb_intf_mpeg2ts_gst.c
index 0c12af20..6c06b574 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/openavb_intf_mpeg2ts_gst.c
+++ b/lib/avtp_pipeline/platform/Linux/intf_mpeg2ts_gst/openavb_intf_mpeg2ts_gst.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/platform/Linux/intf_wav_file/openavb_intf_wav_file.c b/lib/avtp_pipeline/platform/Linux/intf_wav_file/openavb_intf_wav_file.c
index c038c95c..e598bb94 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_wav_file/openavb_intf_wav_file.c
+++ b/lib/avtp_pipeline/platform/Linux/intf_wav_file/openavb_intf_wav_file.c
@@ -1,16 +1,17 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
+
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -21,19 +22,19 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
/*
* MODULE SUMMARY : wav File interface module. Talker only.
-*
+*
* This interface module is narrowly focused to read a common wav file format
* and send the data samples to mapping modules.
-*
+*
*/
#include <stdlib.h>
@@ -48,7 +49,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_intf_pub.h"
#define AVB_LOG_COMPONENT "Wav File Interface"
-#include "openavb_log_pub.h"
+#include "openavb_log_pub.h"
typedef struct {
// RIFF Chunk descriptor
@@ -103,6 +104,12 @@ typedef struct {
// intf_nv_number_of_data_bytes
U32 numberOfDataBytes;
+ //total number of data bytes stored in file so far
+ U32 numOfStoredDataBytes;
+
+ //set when writing to file is finished
+ bool fileReady;
+
} pvt_data_t;
// fread that (mostly) ignores return value - to silence compiler warnings
@@ -251,7 +258,7 @@ static void passParamToMapModule(media_q_t *pMediaQ)
}
}
-// CORE_TODO : this version of convertEndianess is in the commit process but didn't appear to work as expected.
+// CORE_TODO : this version of convertEndianess is in the commit process but didn't appear to work as expected.
// As part of a separate merge the function below this one was pulled in which does work as expected.
#if 0
// little <-> big endian conversion: copy bytes of each
@@ -299,7 +306,7 @@ static void convertEndianness(uint8_t *pData, U32 dataLen, U32 sampleSize)
}
// Each configuration name value pair for this mapping will result in this callback being called.
-void openavbIntfWavFileCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
+void openavbIntfWavFileCfgCB(media_q_t *pMediaQ, const char *name, const char *value)
{
AVB_TRACE_ENTRY(AVB_TRACE_INTF);
@@ -375,7 +382,7 @@ void openavbIntfWavFileCfgCB(media_q_t *pMediaQ, const char *name, const char *v
AVB_TRACE_EXIT(AVB_TRACE_INTF);
}
-void openavbIntfWavFileGenInitCB(media_q_t *pMediaQ)
+void openavbIntfWavFileGenInitCB(media_q_t *pMediaQ)
{
AVB_TRACE_ENTRY(AVB_TRACE_INTF);
@@ -400,7 +407,7 @@ void openavbIntfWavFileGenInitCB(media_q_t *pMediaQ)
// A call to this callback indicates that this interface module will be
// a talker. Any talker initialization can be done in this function.
-void openavbIntfWavFileTxInitCB(media_q_t *pMediaQ)
+void openavbIntfWavFileTxInitCB(media_q_t *pMediaQ)
{
AVB_TRACE_ENTRY(AVB_TRACE_INTF);
@@ -443,16 +450,6 @@ bool openavbIntfWavFileTxCB(media_q_t *pMediaQ)
return FALSE;
}
- //put current wall time into tail item used by AAF maping module
- if ((pPubMapUncmpAudioInfo->sparseMode != TS_SPARSE_MODE_UNSPEC)) {
- pMediaQItem = openavbMediaQTailLock(pMediaQ, TRUE);
- if ((pMediaQItem) && (pPvtData->intervalCounter % pPubMapUncmpAudioInfo->sparseMode == 0)) {
- openavbAvtpTimeSetToWallTime(pMediaQItem->pAvtpTime);
- }
- openavbMediaQTailUnlock(pMediaQ);
- pMediaQItem = NULL;
- }
-
if (pPvtData->intervalCounter++ % pPubMapUncmpAudioInfo->packingFactor != 0)
return TRUE;
@@ -502,7 +499,7 @@ bool openavbIntfWavFileTxCB(media_q_t *pMediaQ)
// A call to this callback indicates that this interface module will be
// a listener. Any listener initialization can be done in this function.
-void openavbIntfWavFileRxInitCB(media_q_t *pMediaQ)
+void openavbIntfWavFileRxInitCB(media_q_t *pMediaQ)
{
AVB_TRACE_ENTRY(AVB_TRACE_INTF);
@@ -565,7 +562,7 @@ void openavbIntfWavFileRxInitCB(media_q_t *pMediaQ)
}
// This callback is called when acting as a listener.
-bool openavbIntfWavFileRxCB(media_q_t *pMediaQ)
+bool openavbIntfWavFileRxCB(media_q_t *pMediaQ)
{
AVB_TRACE_ENTRY(AVB_TRACE_INTF_DETAIL);
@@ -580,17 +577,15 @@ bool openavbIntfWavFileRxCB(media_q_t *pMediaQ)
bool moreData = TRUE;
size_t written;
- static U32 numOfStoredDataBytes = 0; //total number of data bytes stored in file so far
- static bool fileReady = FALSE; //set when writing to file is finished
bool expectedNumberOfDataReceived = FALSE; //set when expected number of data bytes has been received
while (moreData) {
media_q_item_t *pMediaQItem = openavbMediaQTailLock(pMediaQ, TRUE);
- if ((pMediaQItem) && (fileReady == FALSE)) {
+ if ((pMediaQItem) && (pPvtData->fileReady == FALSE)) {
if (pPvtData->pFile && pMediaQItem->dataLen > 0) {
if (expectedNumberOfDataReceived == FALSE) {
- if ((numOfStoredDataBytes + pMediaQItem->dataLen ) > pPvtData->numberOfDataBytes) {
- pMediaQItem->dataLen = pPvtData->numberOfDataBytes - numOfStoredDataBytes;
+ if ((pPvtData->numOfStoredDataBytes + pMediaQItem->dataLen ) > pPvtData->numberOfDataBytes) {
+ pMediaQItem->dataLen = pPvtData->numberOfDataBytes - pPvtData->numOfStoredDataBytes;
expectedNumberOfDataReceived = TRUE;
}
}
@@ -606,9 +601,9 @@ bool openavbIntfWavFileRxCB(media_q_t *pMediaQ)
}
else {
pMediaQItem->dataLen = 0;
- numOfStoredDataBytes += written;
+ pPvtData->numOfStoredDataBytes += written;
if (expectedNumberOfDataReceived == TRUE) {
- fileReady = TRUE;
+ pPvtData->fileReady = TRUE;
AVB_LOG_INFO("Wav file ready.");
}
}
@@ -624,9 +619,9 @@ bool openavbIntfWavFileRxCB(media_q_t *pMediaQ)
return TRUE;
}
-// This callback will be called when the interface needs to be closed. All shutdown should
+// This callback will be called when the interface needs to be closed. All shutdown should
// occur in this function.
-void openavbIntfWavFileEndCB(media_q_t *pMediaQ)
+void openavbIntfWavFileEndCB(media_q_t *pMediaQ)
{
AVB_TRACE_ENTRY(AVB_TRACE_INTF);
@@ -646,7 +641,7 @@ void openavbIntfWavFileEndCB(media_q_t *pMediaQ)
AVB_TRACE_EXIT(AVB_TRACE_INTF);
}
-void openavbIntfWavFileGenEndCB(media_q_t *pMediaQ)
+void openavbIntfWavFileGenEndCB(media_q_t *pMediaQ)
{
AVB_TRACE_ENTRY(AVB_TRACE_INTF);
@@ -691,6 +686,8 @@ extern DLL_EXPORT bool openavbIntfWavFileInitialize(media_q_t *pMediaQ, openavb_
pPvtData->audioEndian = AVB_AUDIO_ENDIAN_LITTLE; //wave file default
pPvtData->intervalCounter = 0;
+ pPvtData->numOfStoredDataBytes = 0;
+ pPvtData->fileReady = FALSE;
}
AVB_TRACE_EXIT(AVB_TRACE_INTF);
diff --git a/lib/avtp_pipeline/platform/Linux/intf_wav_file/wav_file_listener.ini b/lib/avtp_pipeline/platform/Linux/intf_wav_file/wav_file_listener.ini
index f1b6d595..afd32636 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_wav_file/wav_file_listener.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_wav_file/wav_file_listener.ini
@@ -5,6 +5,12 @@
# talker or listener
role = listener
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
stream_addr = 84:7E:40:2C:1b:3a
diff --git a/lib/avtp_pipeline/platform/Linux/intf_wav_file/wav_file_talker.ini b/lib/avtp_pipeline/platform/Linux/intf_wav_file/wav_file_talker.ini
index 9abe8167..4e10cdd8 100644
--- a/lib/avtp_pipeline/platform/Linux/intf_wav_file/wav_file_talker.ini
+++ b/lib/avtp_pipeline/platform/Linux/intf_wav_file/wav_file_talker.ini
@@ -5,6 +5,12 @@
# talker or listener
role = talker
+# initial_state: Specify whether the talker or listener should be
+# running or stopped on startup. Valid values are running or stopped.
+# If not specified, the default will depend on how the talker or
+# listener is launched.
+#initial_state = stopped
+
# stream_addr: Used on the listener and should be set to the
# mac address of the talker.
#stream_addr = 00:25:64:48:ca:a8
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_grandmaster_osal.c b/lib/avtp_pipeline/platform/Linux/openavb_grandmaster_osal.c
new file mode 100644
index 00000000..7acbf76d
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_grandmaster_osal.c
@@ -0,0 +1,152 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#include <inttypes.h>
+#include <linux/ptp_clock.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include "avb_gptp.h"
+
+#include "openavb_platform.h"
+#include "openavb_grandmaster_osal.h"
+#include "openavb_trace.h"
+
+#define AVB_LOG_COMPONENT "osalGrandmaster"
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+static pthread_mutex_t gOSALGrandmasterInitMutex = PTHREAD_MUTEX_INITIALIZER;
+#define LOCK() pthread_mutex_lock(&gOSALGrandmasterInitMutex)
+#define UNLOCK() pthread_mutex_unlock(&gOSALGrandmasterInitMutex)
+
+static bool bInitialized = FALSE;
+static int gShmFd = -1;
+static char *gMmap = NULL;
+gPtpTimeData gPtpTD;
+
+static bool x_grandmasterInit(void) {
+ AVB_TRACE_ENTRY(AVB_TRACE_GRANDMASTER);
+
+ if (gptpinit(&gShmFd, &gMmap) < 0) {
+ AVB_LOG_ERROR("Grandmaster init failed");
+ AVB_TRACE_EXIT(AVB_TRACE_GRANDMASTER);
+ return FALSE;
+ }
+
+ if (gptpgetdata(gMmap, &gPtpTD) < 0) {
+ AVB_LOG_ERROR("Grandmaster data fetch failed");
+ AVB_TRACE_EXIT(AVB_TRACE_GRANDMASTER);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_GRANDMASTER);
+ return TRUE;
+}
+
+bool osalAVBGrandmasterInit(void) {
+ AVB_TRACE_ENTRY(AVB_TRACE_GRANDMASTER);
+
+ LOCK();
+ if (!bInitialized) {
+ if (x_grandmasterInit())
+ bInitialized = TRUE;
+ }
+ UNLOCK();
+
+ AVB_TRACE_EXIT(AVB_TRACE_GRANDMASTER);
+ return bInitialized;
+}
+
+bool osalAVBGrandmasterClose(void) {
+ AVB_TRACE_ENTRY(AVB_TRACE_GRANDMASTER);
+
+ gptpdeinit(&gShmFd, &gMmap);
+
+ AVB_TRACE_EXIT(AVB_TRACE_GRANDMASTER);
+ return TRUE;
+}
+
+bool osalAVBGrandmasterGetCurrent(
+ uint8_t gptp_grandmaster_id[],
+ uint8_t * gptp_domain_number )
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_GRANDMASTER);
+
+ if (gptpgetdata(gMmap, &gPtpTD) < 0) {
+ AVB_LOG_ERROR("Grandmaster data fetch failed");
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return FALSE;
+ }
+
+ if (gptp_grandmaster_id != NULL) { memcpy(gptp_grandmaster_id, gPtpTD.gptp_grandmaster_id, 8); }
+ if (gptp_domain_number != NULL) { *gptp_domain_number = gPtpTD.gptp_domain_number; }
+
+ AVB_TRACE_EXIT(AVB_TRACE_GRANDMASTER);
+ return TRUE;
+}
+
+bool osalClockGrandmasterGetInterface(
+ uint8_t clock_identity[],
+ uint8_t * priority1,
+ uint8_t * clock_class,
+ int16_t * offset_scaled_log_variance,
+ uint8_t * clock_accuracy,
+ uint8_t * priority2,
+ uint8_t * domain_number,
+ int8_t * log_sync_interval,
+ int8_t * log_announce_interval,
+ int8_t * log_pdelay_interval,
+ uint16_t * port_number)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_GRANDMASTER);
+
+ if (gptpgetdata(gMmap, &gPtpTD) < 0) {
+ AVB_LOG_ERROR("Grandmaster data fetch failed");
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return FALSE;
+ }
+
+ if (clock_identity != NULL) { memcpy(clock_identity, gPtpTD.clock_identity, 8); }
+ if (priority1 != NULL) { *priority1 = gPtpTD.priority1; }
+ if (clock_class != NULL) { *clock_class = gPtpTD.clock_class; }
+ if (offset_scaled_log_variance != NULL) { *offset_scaled_log_variance = gPtpTD.offset_scaled_log_variance; }
+ if (clock_accuracy != NULL) { *clock_accuracy = gPtpTD.clock_accuracy; }
+ if (priority2 != NULL) { *priority2 = gPtpTD.priority2; }
+ if (domain_number != NULL) { *domain_number = gPtpTD.domain_number; }
+ if (log_sync_interval != NULL) { *log_sync_interval = gPtpTD.log_sync_interval; }
+ if (log_announce_interval != NULL) { *log_announce_interval = gPtpTD.log_announce_interval; }
+ if (log_pdelay_interval != NULL) { *log_pdelay_interval = gPtpTD.log_pdelay_interval; }
+ if (port_number != NULL) { *port_number = gPtpTD.port_number; }
+
+ AVB_TRACE_EXIT(AVB_TRACE_GRANDMASTER);
+ return TRUE;
+}
diff --git a/lib/avtp_pipeline/platform/x86_i210/openavb_time_hal.h b/lib/avtp_pipeline/platform/Linux/openavb_grandmaster_osal.h
index 9bd04048..cdd01b7a 100644
--- a/lib/avtp_pipeline/platform/x86_i210/openavb_time_hal.h
+++ b/lib/avtp_pipeline/platform/Linux/openavb_grandmaster_osal.h
@@ -1,38 +1,37 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-#ifndef _OPENAVB_TIME_HAL_H
-#define _OPENAVB_TIME_HAL_H
-
-bool halTimeInitialize(void);
-bool halTimeFinalize(void);
-bool halTimeGetLocaltime(U64 *localTime64);
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
-#endif // _OPENAVB_TIME_HAL_H
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#ifndef _OPENAVB_GRANDMASTER_OSAL_H
+#define _OPENAVB_GRANDMASTER_OSAL_H
+
+#include "openavb_grandmaster_osal_pub.h"
+
+#endif // _OPENAVB_GRANDMASTER_OSAL_H
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_grandmaster_osal_pub.h b/lib/avtp_pipeline/platform/Linux/openavb_grandmaster_osal_pub.h
new file mode 100644
index 00000000..795ad8a7
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_grandmaster_osal_pub.h
@@ -0,0 +1,62 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#ifndef _OPENAVB_GRANDMASTER_OSAL_PUB_H
+#define _OPENAVB_GRANDMASTER_OSAL_PUB_H
+
+// Initialize the AVB Grandmaster system for client usage
+bool osalAVBGrandmasterInit(void);
+
+// Close the AVB Grandmaster system for client usage
+bool osalAVBGrandmasterClose(void);
+
+/* Get the current grandmaster information */
+/* Referenced by the IEEE Std 1722.1-2013 AVDECC Discovery Protocol Data Unit (ADPDU) */
+bool osalAVBGrandmasterGetCurrent(
+ uint8_t gptp_grandmaster_id[],
+ uint8_t * gptp_domain_number );
+
+/* Get the grandmaster support for the network interface */
+/* Referenced by the IEEE Std 1722.1-2013 AVDECC AVB_INTERFACE descriptor */
+bool osalClockGrandmasterGetInterface(
+ uint8_t clock_identity[],
+ uint8_t * priority1,
+ uint8_t * clock_class,
+ int16_t * offset_scaled_log_variance,
+ uint8_t * clock_accuracy,
+ uint8_t * priority2,
+ uint8_t * domain_number,
+ int8_t * log_sync_interval,
+ int8_t * log_announce_interval,
+ int8_t * log_pdelay_interval,
+ uint16_t * port_number);
+
+#endif // _OPENAVB_GRANDMASTER_OSAL_PUB_H
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_os_services_osal.h b/lib/avtp_pipeline/platform/Linux/openavb_os_services_osal.h
index e3833f0d..a0d399d0 100644
--- a/lib/avtp_pipeline/platform/Linux/openavb_os_services_osal.h
+++ b/lib/avtp_pipeline/platform/Linux/openavb_os_services_osal.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -64,7 +65,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#define SLEEP(sec) sleep(sec)
#define SLEEP_MSEC(mSec) usleep(mSec * 1000)
-#define SLEEP_NSEC(nSec) usleep(nSec)
+#define SLEEP_NSEC(nSec) usleep(nSec / 1000)
#define SLEEP_UNTIL_NSEC(nSec) xSleepUntilNSec(nSec)
inline static void xSleepUntilNSec(U64 nSec)
{
@@ -74,7 +75,17 @@ inline static void xSleepUntilNSec(U64 nSec)
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &tmpTime, NULL);
}
-
+#define SPIN_UNTIL_NSEC(nsec) xSpinUntilNSec(nsec)
+inline static void xSpinUntilNSec(U64 nSec)
+{
+ do {
+ U64 spinNowNS;
+ CLOCK_GETTIME64(OPENAVB_CLOCK_WALLTIME, &spinNowNS);
+ if (spinNowNS > nSec)
+ break;
+ }
+ while (1);
+}
#define RAND() random()
#define SRAND(seed) srandom(seed)
@@ -119,6 +130,24 @@ thread##_type thread##_ThreadData
pthread_attr_destroy(&thread_attr); \
}
+#define THREAD_SET_RT_PRIORITY(threadhandle, priority) \
+ { \
+ struct sched_param param; \
+ param.__sched_priority = priority; \
+ pthread_setschedparam(threadhandle##_ThreadData.pthread, SCHED_RR, &param); \
+ }
+
+#define THREAD_PIN(threadhandle, affinity) \
+ { \
+ cpu_set_t cpuset; \
+ int i1; \
+ CPU_ZERO(&cpuset); \
+ for (i1 = 0; i1 < 32; i1++) { \
+ if (affinity & (1 << i1)) CPU_SET(i1, &cpuset); \
+ } \
+ pthread_setaffinity_np(threadhandle##_ThreadData.pthread, sizeof(cpu_set_t), &cpuset); \
+ }
+
#define THREAD_CHECK_ERROR(threadhandle, message, error) \
do { \
error=FALSE; \
@@ -151,7 +180,7 @@ thread##_type thread##_ThreadData
#define SEM_POST(sem, err) err = sem_post(&sem);
#define SEM_DESTROY(sem, err) err = sem_destroy(&sem);
#define SEM_IS_ERR_NONE(err) (0 == err)
-#define SEM_IS_ERR_TIMEOUT(err) (ETIMEDOUT == err)
+#define SEM_IS_ERR_TIMEOUT(err) (ETIMEDOUT == err || ((-1 == err) && (ETIMEDOUT == errno)))
#define SEM_LOG_ERR(err) if (0 != err) AVB_LOGF_ERROR("Semaphore error code: %d", err);
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_os_services_osal_pub.h b/lib/avtp_pipeline/platform/Linux/openavb_os_services_osal_pub.h
index fe235104..efe079bb 100644
--- a/lib/avtp_pipeline/platform/Linux/openavb_os_services_osal_pub.h
+++ b/lib/avtp_pipeline/platform/Linux/openavb_os_services_osal_pub.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -34,6 +35,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#define LINUX 1 // !!! FIX ME !!! THIS IS A HACK TO SUPPORT ANOTHER HACK IN openavb_avtp_time.c. REMOVE THIS WHEN openavb_avtp_time.c GETS FIXED !!!
#include "openavb_time_osal_pub.h"
+#include "openavb_grandmaster_osal_pub.h"
#define INLINE_VARIABLE_NUM_OF_ARGUMENTS inline // must be okay of gcc
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_osal.c b/lib/avtp_pipeline/platform/Linux/openavb_osal.c
index ba960ff6..05259809 100644
--- a/lib/avtp_pipeline/platform/Linux/openavb_osal.c
+++ b/lib/avtp_pipeline/platform/Linux/openavb_osal.c
@@ -1,55 +1,55 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-#include "openavb_platform.h"
-#include "openavb_ether_hal.h"
-#include "openavb_osal.h"
-#include "openavb_qmgr.h"
-
-#define AVB_LOG_COMPONENT "osal"
-#include "openavb_pub.h"
-#include "openavb_log.h"
-
-extern DLL_EXPORT bool osalAVBInitialize(const char* ifname)
-{
- avbLogInit();
- osalAVBTimeInit();
- openavbQmgrInitialize(FQTSS_MODE_HW_CLASS, 0, ifname, 0, 0, 0);
- return TRUE;
-}
-
-extern DLL_EXPORT bool osalAVBFinalize(void)
-{
- openavbQmgrFinalize();
- osalAVBTimeClose();
- avbLogExit();
- return TRUE;
-}
-
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#include "openavb_platform.h"
+#include "openavb_osal.h"
+#include "openavb_qmgr.h"
+
+#define AVB_LOG_COMPONENT "osal"
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+extern DLL_EXPORT bool osalAVBInitialize(const char* ifname)
+{
+ avbLogInit();
+ osalAVBTimeInit();
+ openavbQmgrInitialize(FQTSS_MODE_HW_CLASS, 0, ifname, 0, 0, 0);
+ return TRUE;
+}
+
+extern DLL_EXPORT bool osalAVBFinalize(void)
+{
+ openavbQmgrFinalize();
+ osalAVBTimeClose();
+ avbLogExit();
+ return TRUE;
+}
+
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_osal.h b/lib/avtp_pipeline/platform/Linux/openavb_osal.h
index dc1e4463..cbfd349c 100644
--- a/lib/avtp_pipeline/platform/Linux/openavb_osal.h
+++ b/lib/avtp_pipeline/platform/Linux/openavb_osal.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_osal_avdecc.c b/lib/avtp_pipeline/platform/Linux/openavb_osal_avdecc.c
new file mode 100644
index 00000000..e566e1a2
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/openavb_osal_avdecc.c
@@ -0,0 +1,58 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#include "openavb_platform.h"
+#include "openavb_osal.h"
+#include "openavb_qmgr.h"
+#include "openavb_avdecc.h"
+
+#define AVB_LOG_COMPONENT "osal"
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+extern DLL_EXPORT bool osalAvdeccInitialize(const char* ifname, const char **inifiles, int numfiles)
+{
+ avbLogInit();
+ osalAVBTimeInit();
+ if (!osalAVBGrandmasterInit()) { return FALSE; }
+ if (!startAvdecc(ifname, inifiles, numfiles)) { return FALSE; }
+ return TRUE;
+}
+
+extern DLL_EXPORT bool osalAvdeccFinalize(void)
+{
+ stopAvdecc();
+ osalAVBGrandmasterClose();
+ osalAVBTimeClose();
+ avbLogExit();
+ return TRUE;
+}
+
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_osal_endpoint.c b/lib/avtp_pipeline/platform/Linux/openavb_osal_endpoint.c
index 593155f4..ef204d32 100644
--- a/lib/avtp_pipeline/platform/Linux/openavb_osal_endpoint.c
+++ b/lib/avtp_pipeline/platform/Linux/openavb_osal_endpoint.c
@@ -1,56 +1,56 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-#include "openavb_platform.h"
-#include "openavb_ether_hal.h"
-#include "openavb_osal.h"
-#include "openavb_qmgr.h"
-#include "openavb_endpoint.h"
-
-#define AVB_LOG_COMPONENT "osal"
-#include "openavb_pub.h"
-#include "openavb_log.h"
-
-extern DLL_EXPORT bool osalAVBInitialize(const char* ifname)
-{
- avbLogInit();
- osalAVBTimeInit();
- startEndpoint(FQTSS_MODE_HW_CLASS, 0, ifname, 0, 0, 0);
- return TRUE;
-}
-
-extern DLL_EXPORT bool osalAVBFinalize(void)
-{
- stopEndpoint();
- osalAVBTimeClose();
- avbLogExit();
- return TRUE;
-}
-
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#include "openavb_platform.h"
+#include "openavb_osal.h"
+#include "openavb_qmgr.h"
+#include "openavb_endpoint.h"
+
+#define AVB_LOG_COMPONENT "osal"
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+extern DLL_EXPORT bool osalAVBInitialize(const char* ifname)
+{
+ avbLogInit();
+ osalAVBTimeInit();
+ startEndpoint(FQTSS_MODE_HW_CLASS, 0, ifname, 0, 0, 0);
+ return TRUE;
+}
+
+extern DLL_EXPORT bool osalAVBFinalize(void)
+{
+ stopEndpoint();
+ osalAVBTimeClose();
+ avbLogExit();
+ return TRUE;
+}
+
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_osal_pub.h b/lib/avtp_pipeline/platform/Linux/openavb_osal_pub.h
index 0cae719d..fcb8e778 100644
--- a/lib/avtp_pipeline/platform/Linux/openavb_osal_pub.h
+++ b/lib/avtp_pipeline/platform/Linux/openavb_osal_pub.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -40,5 +41,10 @@ bool osalAVBInitialize(const char *ifname);
bool osalAVBFinalize(void);
+
+bool osalAvdeccInitialize(const char *ifname, const char **inifiles, int numfiles);
+
+bool osalAvdeccFinalize(void);
+
#endif // _OPENAVB_OSAL_PUB_H
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_poll_osal.h b/lib/avtp_pipeline/platform/Linux/openavb_poll_osal.h
index bd4e925f..84866cbf 100644
--- a/lib/avtp_pipeline/platform/Linux/openavb_poll_osal.h
+++ b/lib/avtp_pipeline/platform/Linux/openavb_poll_osal.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_tasks.h b/lib/avtp_pipeline/platform/Linux/openavb_tasks.h
index d456b4f9..01969f09 100644
--- a/lib/avtp_pipeline/platform/Linux/openavb_tasks.h
+++ b/lib/avtp_pipeline/platform/Linux/openavb_tasks.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -62,6 +63,9 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
//task ListenerThread
#define listenerThread_THREAD_STK_SIZE THREAD_STACK_SIZE
+//task avdeccMsgThread
+#define avdeccMsgThread_THREAD_STK_SIZE THREAD_STACK_SIZE
+
//task openavbAecpSMEntityModelEntityThread
#define openavbAecpSMEntityModelEntityThread_THREAD_STK_SIZE THREAD_STACK_SIZE
@@ -86,8 +90,8 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
//task openavbAcmpSmTalkerThread
#define openavbAcmpSmTalkerThread_THREAD_STK_SIZE THREAD_STACK_SIZE
-//task openavbAcmpSmTalkerThread
-#define openavbAcmpSmTalkerThread_THREAD_STK_SIZE THREAD_STACK_SIZE
+//task openavbAcmpSmControllerThread
+#define openavbAcmpSmControllerThread_THREAD_STK_SIZE THREAD_STACK_SIZE
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_time_osal.c b/lib/avtp_pipeline/platform/Linux/openavb_time_osal.c
index b287cf13..9f2239b6 100644
--- a/lib/avtp_pipeline/platform/Linux/openavb_time_osal.c
+++ b/lib/avtp_pipeline/platform/Linux/openavb_time_osal.c
@@ -1,207 +1,197 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-#include <inttypes.h>
-#include <linux/ptp_clock.h>
-#include <sys/mman.h>
-#include <sys/ioctl.h>
-
-#include "igb.h"
-#include "avb.h"
-
-#include "openavb_platform.h"
-#include "openavb_time_osal.h"
-#include "openavb_time_hal.h"
-#include "openavb_trace.h"
-
-#define AVB_LOG_COMPONENT "osalTime"
-#include "openavb_pub.h"
-#include "openavb_log.h"
-
-//#include "openavb_time_util_osal.h"
-
-static pthread_mutex_t gOSALTimeInitMutex = PTHREAD_MUTEX_INITIALIZER;
-#define LOCK() pthread_mutex_lock(&gOSALTimeInitMutex)
-#define UNLOCK() pthread_mutex_unlock(&gOSALTimeInitMutex)
-
-static bool bInitialized = FALSE;
-static int gIgbShmFd = -1;
-static char *gIgbMmap = NULL;
-gPtpTimeData gPtpTD;
-
-static bool x_timeInit(void) {
- AVB_TRACE_ENTRY(AVB_TRACE_TIME);
-
- if (!halTimeInitialize()) {
- AVB_LOG_ERROR("HAL Time Init failed");
- AVB_TRACE_EXIT(AVB_TRACE_TIME);
- return FALSE;
- }
-
- if (gptpinit(&gIgbShmFd, &gIgbMmap) < 0) {
- AVB_LOG_ERROR("GPTP init failed");
- AVB_TRACE_EXIT(AVB_TRACE_TIME);
- return FALSE;
- }
-
- if (gptpgetdata(gIgbMmap, &gPtpTD) < 0) {
- AVB_LOG_ERROR("GPTP data fetch failed");
- AVB_TRACE_EXIT(AVB_TRACE_TIME);
- return FALSE;
- }
-
- AVB_LOGF_INFO("local_time = %" PRIu64, gPtpTD.local_time);
- AVB_LOGF_INFO("ml_phoffset = %" PRId64 ", ls_phoffset = %" PRId64, gPtpTD.ml_phoffset, gPtpTD.ls_phoffset);
- AVB_LOGF_INFO("ml_freqffset = %Lf, ls_freqoffset = %Lf", gPtpTD.ml_freqoffset, gPtpTD.ls_freqoffset);
-
- AVB_TRACE_EXIT(AVB_TRACE_TIME);
- return TRUE;
-}
-
-static bool x_getPTPTime(U64 *timeNsec) {
- AVB_TRACE_ENTRY(AVB_TRACE_TIME);
-
- if (gptpgetdata(gIgbMmap, &gPtpTD) < 0) {
- AVB_LOG_ERROR("GPTP data fetch failed");
- AVB_TRACE_EXIT(AVB_TRACE_TIME);
- return FALSE;
- }
-
- uint64_t now_local;
- uint64_t update_8021as;
- int64_t delta_8021as;
- int64_t delta_local;
-
- if (gptplocaltime(&gPtpTD, &now_local)) {
- update_8021as = gPtpTD.local_time - gPtpTD.ml_phoffset;
- delta_local = now_local - gPtpTD.local_time;
- delta_8021as = gPtpTD.ml_freqoffset * delta_local;
- *timeNsec = update_8021as + delta_8021as;
-
- AVB_TRACE_EXIT(AVB_TRACE_TIME);
- return TRUE;
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_TIME);
- return FALSE;
-}
-
-bool osalAVBTimeInit(void) {
- AVB_TRACE_ENTRY(AVB_TRACE_TIME);
-
- LOCK();
- if (!bInitialized) {
- if (x_timeInit())
- bInitialized = TRUE;
- }
- UNLOCK();
-
- AVB_TRACE_EXIT(AVB_TRACE_TIME);
- return TRUE;
-}
-
-bool osalAVBTimeClose(void) {
- AVB_TRACE_ENTRY(AVB_TRACE_TIME);
-
- gptpdeinit(&gIgbShmFd, &gIgbMmap);
-
- halTimeFinalize();
-
- AVB_TRACE_EXIT(AVB_TRACE_TIME);
- return TRUE;
-}
-
-bool osalClockGettime(openavb_clockId_t openavbClockId, struct timespec *getTime) {
- AVB_TRACE_ENTRY(AVB_TRACE_TIME);
-
- if (openavbClockId < OPENAVB_CLOCK_WALLTIME) {
- clockid_t clockId = CLOCK_MONOTONIC;
- switch (openavbClockId) {
- case OPENAVB_CLOCK_REALTIME:
- clockId = CLOCK_REALTIME;
- break;
- case OPENAVB_CLOCK_MONOTONIC:
- clockId = CLOCK_MONOTONIC;
- break;
- case OPENAVB_TIMER_CLOCK:
- clockId = CLOCK_MONOTONIC;
- break;
- case OPENAVB_CLOCK_WALLTIME:
- break;
- }
- if (!clock_gettime(clockId, getTime)) return TRUE;
- }
- else if (openavbClockId == OPENAVB_CLOCK_WALLTIME) {
- U64 timeNsec;
- if (!x_getPTPTime(&timeNsec)) {
- AVB_TRACE_EXIT(AVB_TRACE_TIME);
- return FALSE;
- }
- getTime->tv_sec = timeNsec / NANOSECONDS_PER_SECOND;
- getTime->tv_nsec = timeNsec % NANOSECONDS_PER_SECOND;
- AVB_TRACE_EXIT(AVB_TRACE_TIME);
- return TRUE;
- }
- AVB_TRACE_EXIT(AVB_TRACE_TIME);
- return FALSE;
-}
-
-bool osalClockGettime64(openavb_clockId_t openavbClockId, U64 *timeNsec) {
- if (openavbClockId < OPENAVB_CLOCK_WALLTIME) {
- clockid_t clockId = CLOCK_MONOTONIC;
- switch (openavbClockId) {
- case OPENAVB_CLOCK_REALTIME:
- clockId = CLOCK_REALTIME;
- break;
- case OPENAVB_CLOCK_MONOTONIC:
- clockId = CLOCK_MONOTONIC;
- break;
- case OPENAVB_TIMER_CLOCK:
- clockId = CLOCK_MONOTONIC;
- break;
- case OPENAVB_CLOCK_WALLTIME:
- break;
- }
- struct timespec getTime;
- if (!clock_gettime(clockId, &getTime)) {
- *timeNsec = ((U64)getTime.tv_sec * (U64)NANOSECONDS_PER_SECOND) + (U64)getTime.tv_nsec;
- AVB_TRACE_EXIT(AVB_TRACE_TIME);
- return TRUE;
- }
- }
- else if (openavbClockId == OPENAVB_CLOCK_WALLTIME) {
- AVB_TRACE_EXIT(AVB_TRACE_TIME);
- return x_getPTPTime(timeNsec);
- }
- AVB_TRACE_EXIT(AVB_TRACE_TIME);
- return FALSE;
-}
-
-
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#include <inttypes.h>
+#include <linux/ptp_clock.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include "avb_gptp.h"
+
+#include "openavb_platform.h"
+#include "openavb_time_osal.h"
+#include "openavb_trace.h"
+
+#define AVB_LOG_COMPONENT "osalTime"
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+static pthread_mutex_t gOSALTimeInitMutex = PTHREAD_MUTEX_INITIALIZER;
+#define LOCK() pthread_mutex_lock(&gOSALTimeInitMutex)
+#define UNLOCK() pthread_mutex_unlock(&gOSALTimeInitMutex)
+
+static bool bInitialized = FALSE;
+static int gPtpShmFd = -1;
+static char *gPtpMmap = NULL;
+gPtpTimeData gPtpTD;
+
+static bool x_timeInit(void) {
+ AVB_TRACE_ENTRY(AVB_TRACE_TIME);
+
+ if (gptpinit(&gPtpShmFd, &gPtpMmap) < 0) {
+ AVB_LOG_ERROR("GPTP init failed");
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return FALSE;
+ }
+
+ if (gptpgetdata(gPtpMmap, &gPtpTD) < 0) {
+ AVB_LOG_ERROR("GPTP data fetch failed");
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return FALSE;
+ }
+
+ AVB_LOGF_INFO("local_time = %" PRIu64, gPtpTD.local_time);
+ AVB_LOGF_INFO("ml_phoffset = %" PRId64 ", ls_phoffset = %" PRId64, gPtpTD.ml_phoffset, gPtpTD.ls_phoffset);
+ AVB_LOGF_INFO("ml_freqffset = %Lf, ls_freqoffset = %Lf", gPtpTD.ml_freqoffset, gPtpTD.ls_freqoffset);
+
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return TRUE;
+}
+
+static bool x_getPTPTime(U64 *timeNsec) {
+ AVB_TRACE_ENTRY(AVB_TRACE_TIME);
+
+ if (gptpgetdata(gPtpMmap, &gPtpTD) < 0) {
+ AVB_LOG_ERROR("GPTP data fetch failed");
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return FALSE;
+ }
+
+ uint64_t now_local;
+ uint64_t update_8021as;
+ int64_t delta_8021as;
+ int64_t delta_local;
+
+ if (gptplocaltime(&gPtpTD, &now_local)) {
+ update_8021as = gPtpTD.local_time - gPtpTD.ml_phoffset;
+ delta_local = now_local - gPtpTD.local_time;
+ delta_8021as = gPtpTD.ml_freqoffset * delta_local;
+ *timeNsec = update_8021as + delta_8021as;
+
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return TRUE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return FALSE;
+}
+
+bool osalAVBTimeInit(void) {
+ AVB_TRACE_ENTRY(AVB_TRACE_TIME);
+
+ LOCK();
+ if (!bInitialized) {
+ if (x_timeInit())
+ bInitialized = TRUE;
+ }
+ UNLOCK();
+
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return bInitialized;
+}
+
+bool osalAVBTimeClose(void) {
+ AVB_TRACE_ENTRY(AVB_TRACE_TIME);
+
+ gptpdeinit(&gPtpShmFd, &gPtpMmap);
+
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return TRUE;
+}
+
+bool osalClockGettime(openavb_clockId_t openavbClockId, struct timespec *getTime) {
+ AVB_TRACE_ENTRY(AVB_TRACE_TIME);
+
+ if (openavbClockId < OPENAVB_CLOCK_WALLTIME)
+ {
+ clockid_t clockId = CLOCK_MONOTONIC;
+ switch (openavbClockId) {
+ case OPENAVB_CLOCK_REALTIME:
+ clockId = CLOCK_REALTIME;
+ break;
+ case OPENAVB_CLOCK_MONOTONIC:
+ clockId = CLOCK_MONOTONIC;
+ break;
+ case OPENAVB_TIMER_CLOCK:
+ clockId = CLOCK_MONOTONIC;
+ break;
+ case OPENAVB_CLOCK_WALLTIME:
+ break;
+ }
+ if (!clock_gettime(clockId, getTime)) return TRUE;
+ }
+ else if (openavbClockId == OPENAVB_CLOCK_WALLTIME) {
+ U64 timeNsec;
+ if (!x_getPTPTime(&timeNsec)) {
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return FALSE;
+ }
+ getTime->tv_sec = timeNsec / NANOSECONDS_PER_SECOND;
+ getTime->tv_nsec = timeNsec % NANOSECONDS_PER_SECOND;
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return TRUE;
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return FALSE;
+}
+
+bool osalClockGettime64(openavb_clockId_t openavbClockId, U64 *timeNsec) {
+ if (openavbClockId < OPENAVB_CLOCK_WALLTIME)
+ {
+ clockid_t clockId = CLOCK_MONOTONIC;
+ switch (openavbClockId) {
+ case OPENAVB_CLOCK_REALTIME:
+ clockId = CLOCK_REALTIME;
+ break;
+ case OPENAVB_CLOCK_MONOTONIC:
+ clockId = CLOCK_MONOTONIC;
+ break;
+ case OPENAVB_TIMER_CLOCK:
+ clockId = CLOCK_MONOTONIC;
+ break;
+ case OPENAVB_CLOCK_WALLTIME:
+ break;
+ }
+ struct timespec getTime;
+ if (!clock_gettime(clockId, &getTime)) {
+ *timeNsec = ((U64)getTime.tv_sec * (U64)NANOSECONDS_PER_SECOND) + (U64)getTime.tv_nsec;
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return TRUE;
+ }
+ }
+ else if (openavbClockId == OPENAVB_CLOCK_WALLTIME) {
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return x_getPTPTime(timeNsec);
+ }
+ AVB_TRACE_EXIT(AVB_TRACE_TIME);
+ return FALSE;
+}
+
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_time_osal.h b/lib/avtp_pipeline/platform/Linux/openavb_time_osal.h
index 3fa07afd..a6879862 100644
--- a/lib/avtp_pipeline/platform/Linux/openavb_time_osal.h
+++ b/lib/avtp_pipeline/platform/Linux/openavb_time_osal.h
@@ -1,33 +1,34 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
#ifndef _OPENAVB_TIME_OSAL_H
#define _OPENAVB_TIME_OSAL_H
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_time_osal_pub.h b/lib/avtp_pipeline/platform/Linux/openavb_time_osal_pub.h
index 1f2c243f..ba693da9 100644
--- a/lib/avtp_pipeline/platform/Linux/openavb_time_osal_pub.h
+++ b/lib/avtp_pipeline/platform/Linux/openavb_time_osal_pub.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -42,7 +43,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#define TIMERFD_SETTIME(arg1, arg2, arg3, arg4) timerfd_settime(arg1, arg2, arg3, arg4)
#define TIMER_CLOSE(arg1) close(arg1)
-// In this Linux port all clock IDs preceeding OPENAVB_CLOCK_WALLTIME will be set to clock_gettime()
+// In this Linux port all clock IDs preceding OPENAVB_CLOCK_WALLTIME will be set to clock_gettime()
typedef enum {
OPENAVB_CLOCK_REALTIME,
OPENAVB_CLOCK_MONOTONIC,
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/avtp_rx.c b/lib/avtp_pipeline/platform/Linux/rawsock/avtp_rx.c
index e451fab9..80adbb59 100644
--- a/lib/avtp_pipeline/platform/Linux/rawsock/avtp_rx.c
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/avtp_rx.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/igb_rawsock.c b/lib/avtp_pipeline/platform/Linux/rawsock/igb_rawsock.c
index cbb6ce80..a9cf5ac2 100644
--- a/lib/avtp_pipeline/platform/Linux/rawsock/igb_rawsock.c
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/igb_rawsock.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -32,7 +33,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "pcap_rawsock.h"
#include "simple_rawsock.h"
#include "avb.h"
-#include "openavb_ether_hal.h"
+#include "openavb_igb.h"
#include "avb_sched.h"
#include "openavb_trace.h"
@@ -192,7 +193,7 @@ bool igbRawsockRelTxFrame(void *pvRawsock, U8 *pBuffer)
}
// Release a TX frame, and mark it as ready to send
-bool igbRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len)
+bool igbRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len, U64 timeNsec)
{
AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
igb_rawsock_t *rawsock = (igb_rawsock_t*)pvRawsock;
@@ -207,7 +208,7 @@ bool igbRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len)
rawsock->tx_packet->len = len;
#if IGB_LAUNCHTIME_ENABLED
- gptplocaltime(&gPtpTD, &rawsock->tx_packet->attime);
+ gptpmaster2local(&gPtpTD, timeNsec, &rawsock->tx_packet->attime);
#endif
err = igb_xmit(rawsock->igb_dev, rawsock->queue, rawsock->tx_packet);
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/igb_rawsock.h b/lib/avtp_pipeline/platform/Linux/rawsock/igb_rawsock.h
index efea97a9..70215981 100644
--- a/lib/avtp_pipeline/platform/Linux/rawsock/igb_rawsock.h
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/igb_rawsock.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -54,7 +55,7 @@ U8 *igbRawsockGetTxFrame(void *pvRawsock, bool blocking, unsigned int *len);
bool igbRawsockRelTxFrame(void *pvRawsock, U8 *pBuffer);
-bool igbRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len);
+bool igbRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len, U64 timeNsec);
int igbRawsockSend(void *pvRawsock);
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/openavb_rawsock.c b/lib/avtp_pipeline/platform/Linux/rawsock/openavb_rawsock.c
index b73d9e7b..c05053a5 100644
--- a/lib/avtp_pipeline/platform/Linux/rawsock/openavb_rawsock.c
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/openavb_rawsock.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -28,23 +29,25 @@ Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
-#include "openavb_rawsock.h"
-#include <malloc.h>
+#include "sendmmsg_rawsock.h"
#include "simple_rawsock.h"
#include "ring_rawsock.h"
-
-#define IGB
-
#if AVB_FEATURE_PCAP
#include "pcap_rawsock.h"
+#if AVB_FEATURE_IGB
#include "igb_rawsock.h"
#endif
+#endif
+
+#include "openavb_rawsock.h"
#include "openavb_trace.h"
#define AVB_LOG_COMPONENT "Raw Socket"
#include "openavb_log.h"
+#include <malloc.h>
+
// Get information about an interface
bool openavbCheckInterface(const char *ifname_uri, if_info_t *info)
@@ -73,11 +76,21 @@ void *openavbRawsockOpen(const char *ifname_uri, bool rx_mode, bool tx_mode, U16
AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
const char* ifname = ifname_uri;
+#if AVB_FEATURE_PCAP
+#if AVB_FEATURE_IGB
char proto[IF_NAMESIZE] = "igb";
+#else
+ char proto[IF_NAMESIZE] = "pcap";
+#endif
+#else
+ char proto[IF_NAMESIZE] = "simple";
+#endif
+
char *colon = strchr(ifname_uri, ':');
if (colon) {
ifname = colon + 1;
strncpy(proto, ifname_uri, colon - ifname_uri);
+ proto[colon - ifname_uri] = '\0';
}
AVB_LOGF_DEBUG("%s ifname_uri %s ifname %s proto %s", __func__, ifname_uri, ifname, proto);
@@ -103,7 +116,7 @@ void *openavbRawsockOpen(const char *ifname_uri, bool rx_mode, bool tx_mode, U16
AVB_LOG_INFO("Using *simple* implementation");
// allocate memory for rawsock object
- simple_rawsock_t *rawsock = calloc(1, sizeof(simple_rawsock_t));
+ simple_rawsock_t *rawsock = calloc(1, sizeof(simple_rawsock_t) + 4 /* Just in case */);
if (!rawsock) {
AVB_LOG_ERROR("Creating rawsock; malloc failed");
return NULL;
@@ -111,6 +124,19 @@ void *openavbRawsockOpen(const char *ifname_uri, bool rx_mode, bool tx_mode, U16
// call constructor
pvRawsock = simpleRawsockOpen(rawsock, ifname, rx_mode, tx_mode, ethertype, frame_size, num_frames);
+ } else if (strcmp(proto, "sendmmsg") == 0) {
+
+ AVB_LOG_INFO("Using *sendmmsg* implementation");
+
+ // allocate memory for rawsock object
+ sendmmsg_rawsock_t *rawsock = calloc(1, sizeof(sendmmsg_rawsock_t));
+ if (!rawsock) {
+ AVB_LOG_ERROR("Creating rawsock; malloc failed");
+ return NULL;
+ }
+
+ // call constructor
+ pvRawsock = sendmmsgRawsockOpen(rawsock, ifname, rx_mode, tx_mode, ethertype, frame_size, num_frames);
#if AVB_FEATURE_PCAP
} else if (strcmp(proto, "pcap") == 0) {
@@ -125,7 +151,7 @@ void *openavbRawsockOpen(const char *ifname_uri, bool rx_mode, bool tx_mode, U16
// call constructor
pvRawsock = pcapRawsockOpen(rawsock, ifname, rx_mode, tx_mode, ethertype, frame_size, num_frames);
-#ifdef IGB
+#if AVB_FEATURE_IGB
} else if (strcmp(proto, "igb") == 0) {
AVB_LOG_INFO("Using *igb* implementation");
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/pcap_rawsock.c b/lib/avtp_pipeline/platform/Linux/rawsock/pcap_rawsock.c
index 3a4a1046..de0d7967 100644
--- a/lib/avtp_pipeline/platform/Linux/rawsock/pcap_rawsock.c
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/pcap_rawsock.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -38,6 +39,36 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#define AVB_LOG_COMPONENT "Raw Socket"
#include "openavb_log.h"
+static pcap_t* open_pcap_dev(const char* ifname, int frameSize, char* errbuf)
+{
+ pcap_t* handle = pcap_create(ifname, errbuf);
+ if (handle) {
+ int err;
+ err = pcap_set_snaplen(handle, frameSize);
+ if (err) AVB_LOGF_WARNING("Cannot set snap len %d", err);
+
+ err = pcap_set_promisc(handle, 1);
+ if (err) AVB_LOGF_WARNING("Cannot set promisc %d", err);
+
+ err = pcap_set_immediate_mode(handle, 1);
+ if (err) AVB_LOGF_WARNING("Cannot set immediate mode %d", err);
+
+ // we need timeout (here 100ms) otherwise we could block for ever
+ err = pcap_set_timeout(handle, 100);
+ if (err) AVB_LOGF_WARNING("Cannot set timeout %d", err);
+
+ err = pcap_set_tstamp_precision(handle, PCAP_TSTAMP_PRECISION_NANO);
+ if (err) AVB_LOGF_WARNING("Cannot set tstamp nano precision %d", err);
+
+ err = pcap_set_tstamp_type(handle, PCAP_TSTAMP_ADAPTER_UNSYNCED);
+ if (err) AVB_LOGF_WARNING("Cannot set tstamp adapter unsynced %d", err);
+
+ err = pcap_activate(handle);
+ if (err) AVB_LOGF_WARNING("Cannot activate pcap %d", err);
+ }
+ return handle;
+}
+
// Open a rawsock for TX or RX
void *pcapRawsockOpen(pcap_rawsock_t* rawsock, const char *ifname, bool rx_mode, bool tx_mode, U16 ethertype, U32 frame_size, U32 num_frames)
{
@@ -67,14 +98,14 @@ void *pcapRawsockOpen(pcap_rawsock_t* rawsock, const char *ifname, bool rx_mode,
rawsock->base.frameSize = rawsock->base.ifInfo.mtu + ETH_HLEN + VLAN_HLEN;
}
else if (rawsock->base.frameSize > rawsock->base.ifInfo.mtu + ETH_HLEN + VLAN_HLEN) {
- AVB_LOG_ERROR("Creating raswsock; requested frame size exceeds MTU");
+ AVB_LOG_ERROR("Creating rawsock; requested frame size exceeds MTU");
free(rawsock);
AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
return NULL;
}
char errbuf[PCAP_ERRBUF_SIZE];
- rawsock->handle = pcap_open_live(ifname, rawsock->base.frameSize, 1, 1, errbuf);
+ rawsock->handle = open_pcap_dev(ifname, rawsock->base.frameSize, errbuf);
if (!rawsock->handle) {
AVB_LOGF_ERROR("Cannot open device %s: %s", ifname, errbuf);
free(rawsock);
@@ -87,8 +118,10 @@ void *pcapRawsockOpen(pcap_rawsock_t* rawsock, const char *ifname, bool rx_mode,
cb->close = pcapRawsockClose;
cb->getTxFrame = pcapRawsockGetTxFrame;
cb->txFrameReady = pcapRawsockTxFrameReady;
+ cb->send = pcapRawsockSend;
cb->getRxFrame = pcapRawsockGetRxFrame;
cb->rxMulticast = pcapRawsockRxMulticast;
+ cb->rxParseHdr = pcapRawsockRxParseHdr;
AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
return rawsock;
@@ -117,11 +150,15 @@ U8 *pcapRawsockGetTxFrame(void *pvRawsock, bool blocking, unsigned int *len)
return false;
}
-bool pcapRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len)
+bool pcapRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len, U64 timeNsec)
{
pcap_rawsock_t *rawsock = (pcap_rawsock_t*)pvRawsock;
int ret = -1;
+ if (timeNsec) {
+ IF_LOG_INTERVAL(1000) AVB_LOG_WARNING("launch time is unsupported in pcap_rawsock");
+ }
+
if (rawsock) {
ret = pcap_sendpacket(rawsock->handle, pBuffer, len);
if (ret == -1) {
@@ -132,20 +169,28 @@ bool pcapRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len)
return ret == 0;
}
+// Send all packets that are ready (i.e. tell kernel to send them)
+int pcapRawsockSend(void *pvRawsock)
+{
+ // pcapRawsock sends frames in pcapRawsockTxFrameReady
+
+ return 1;
+}
+
U8 *pcapRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, unsigned int *len)
{
pcap_rawsock_t *rawsock = (pcap_rawsock_t*)pvRawsock;
- struct pcap_pkthdr *header = 0;
+ rawsock->rxHeader = 0;
const u_char *packet = 0;
int ret;
if (rawsock) {
- ret = pcap_next_ex(rawsock->handle, &header, &packet);
+ ret = pcap_next_ex(rawsock->handle, &rawsock->rxHeader, &packet);
switch(ret) {
case 1:
*offset = 0;
- *len = header->caplen;
+ *len = rawsock->rxHeader->caplen;
return (U8*)packet;
case -1:
AVB_LOGF_ERROR("pcap_next_ex failed: %s", pcap_geterr(rawsock->handle));
@@ -155,7 +200,7 @@ U8 *pcapRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, un
break;
case -2:
// no packets to be read from savefile
- // this should not happend
+ // this should not happened
break;
default:
break;
@@ -165,6 +210,19 @@ U8 *pcapRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, un
return NULL;
}
+int pcapRawsockRxParseHdr(void* pvRawsock, U8* pBuffer, hdr_info_t* pInfo)
+{
+ int hdrLen = baseRawsockRxParseHdr(pvRawsock, pBuffer, pInfo);
+
+ pcap_rawsock_t *rawsock = (pcap_rawsock_t*)pvRawsock;
+ if (rawsock && rawsock->rxHeader) {
+ pInfo->ts.tv_sec = rawsock->rxHeader->ts.tv_sec;
+ // we requested nanosecond timestamp precision, so probably we don't have to scale here
+ pInfo->ts.tv_nsec = rawsock->rxHeader->ts.tv_usec;
+ }
+ return hdrLen;
+}
+
// Setup the rawsock to receive multicast packets
bool pcapRawsockRxMulticast(void *pvRawsock, bool add_membership, const U8 addr[ETH_ALEN])
{
@@ -173,7 +231,7 @@ bool pcapRawsockRxMulticast(void *pvRawsock, bool add_membership, const U8 addr[
struct bpf_program comp_filter_exp;
char filter_exp[30];
- sprintf(filter_exp, "ether dst %x:%x:%x:%x:%x:%x", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+ sprintf(filter_exp, "ether dst %02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
AVB_LOGF_DEBUG("%s %d %s", __func__, (int)add_membership, filter_exp);
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/pcap_rawsock.h b/lib/avtp_pipeline/platform/Linux/rawsock/pcap_rawsock.h
index ed8e7943..32b01854 100644
--- a/lib/avtp_pipeline/platform/Linux/rawsock/pcap_rawsock.h
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/pcap_rawsock.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -38,6 +39,7 @@ typedef struct {
base_rawsock_t base;
pcap_t* handle;
U8 txBuffer[1518];
+ struct pcap_pkthdr *rxHeader;
} pcap_rawsock_t;
void *pcapRawsockOpen(pcap_rawsock_t* rawsock, const char *ifname, bool rx_mode, bool tx_mode, U16 ethertype, U32 frame_size, U32 num_frames);
@@ -46,10 +48,14 @@ void pcapRawsockClose(void *pvRawsock);
U8 *pcapRawsockGetTxFrame(void *pvRawsock, bool blocking, unsigned int *len);
-bool pcapRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len);
+bool pcapRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len, U64 timeNsec);
+
+int pcapRawsockSend(void *pvRawsock);
U8 *pcapRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, unsigned int *len);
+int pcapRawsockRxParseHdr(void* pvRawsock, U8* pBuffer, hdr_info_t* pInfo);
+
bool pcapRawsockRxMulticast(void *pvRawsock, bool add_membership, const U8 addr[ETH_ALEN]);
#endif
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/rawsock_rx.c b/lib/avtp_pipeline/platform/Linux/rawsock/rawsock_rx.c
index 4fa4682f..7e78516a 100644
--- a/lib/avtp_pipeline/platform/Linux/rawsock/rawsock_rx.c
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/rawsock_rx.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/rawsock_tx.c b/lib/avtp_pipeline/platform/Linux/rawsock/rawsock_tx.c
index e01b5998..20a41a94 100644
--- a/lib/avtp_pipeline/platform/Linux/rawsock/rawsock_tx.c
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/rawsock_tx.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -34,6 +35,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include <string.h>
#include <glib.h>
#include "./openavb_rawsock.h"
+#include "openavb_log.h"
//Common usage: ./rawsock_tx -i eth0 -t 8944 -r 8000 -s 1 -c 1 -m 1 -l 100
@@ -150,6 +152,8 @@ int main(int argc, char* argv[])
U32 buflen, hdrlen, datalen;
hdr_info_t hdr;
+ avbLogInit();
+
memset(&hdr, 0, sizeof(hdr_info_t));
openavbRawsockTxSetHdr(rs, &hdr);
@@ -165,6 +169,7 @@ int main(int argc, char* argv[])
nextReportInterval = TIMESPEC_TO_NSEC(now) + (NANOSECONDS_PER_SECOND * reportSec);
while (1) {
+ int remainder = 0;
pBuf = (U8*)openavbRawsockGetTxFrame(rs, TRUE, &buflen);
if (!pBuf) {
printf("failed to get TX frame buffer\n");
@@ -191,7 +196,7 @@ int main(int argc, char* argv[])
txlen = hdrlen + 3;
}
- openavbRawsockTxFrameReady(rs, pBuf, txlen);
+ openavbRawsockTxFrameReady(rs, pBuf, txlen, 0);
packetCnt++;
@@ -204,8 +209,9 @@ int main(int argc, char* argv[])
U64 nowNSec = TIMESPEC_TO_NSEC(now);;
if (nowNSec > nextReportInterval) {
- printf("TX Packets: %d\n", packetCnt);
- packetCnt = 0;
+ printf("TX Packets: %d\n", packetCnt-remainder);
+ packetCnt %= chunkSize;
+ remainder = packetCnt;
nextReportInterval = nowNSec + (NANOSECONDS_PER_SECOND * reportSec);
}
@@ -215,5 +221,6 @@ int main(int argc, char* argv[])
}
openavbRawsockClose(rs);
+ avbLogExit();
return 0;
}
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/ring_rawsock.c b/lib/avtp_pipeline/platform/Linux/rawsock/ring_rawsock.c
index 71c7a3af..f66878c1 100644
--- a/lib/avtp_pipeline/platform/Linux/rawsock/ring_rawsock.c
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/ring_rawsock.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -218,9 +219,9 @@ U8* ringRawsockGetTxFrame(void *pvRawsock, bool blocking, unsigned int *len)
// And pointer to portion of buffer to be filled with frame
volatile U8 *pBuffer = (U8*)pHdr + rawsock->bufHdrSize;
- AVB_LOGF_VERBOSE("block=%d, buffer=%d, out=%d, pHdr=%p, pBuffer=%p",
+ AVB_LOGF_VERBOSE("block=%d, buffer=%d, out=%d, pBuffer=%p, pHdr=%p",
rawsock->blockIndex, rawsock->bufferIndex, rawsock->buffersOut,
- pHdr, pBuffer);
+ pBuffer, pHdr);
// Check if buffer ready for user
// In send mode, we want to see TP_STATUS_AVAILABLE
@@ -324,7 +325,7 @@ bool ringRawsockRelTxFrame(void *pvRawsock, U8 *pBuffer)
}
// Release a TX frame, and mark it as ready to send
-bool ringRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len)
+bool ringRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len, U64 timeNsec)
{
AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
ring_rawsock_t *rawsock = (ring_rawsock_t*)pvRawsock;
@@ -335,6 +336,11 @@ bool ringRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len)
return FALSE;
}
+ if (timeNsec) {
+ IF_LOG_INTERVAL(1000) AVB_LOG_WARNING("launch time is unsupported in ring_rawsock");
+ }
+
+
volatile struct tpacket2_hdr *pHdr = (struct tpacket2_hdr*)(pBuffer - rawsock->bufHdrSize);
AVB_LOGF_VERBOSE("pBuffer=%p, pHdr=%p szFrame=%d, len=%d", pBuffer, pHdr, rawsock->base.frameSize, len);
@@ -479,9 +485,9 @@ U8* ringRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, un
+ (rawsock->bufferIndex * rawsock->bufferSize));
volatile U8 *pBuffer = (U8*)pHdr + rawsock->bufHdrSize;
- AVB_LOGF_VERBOSE("block=%d, buffer=%d, out=%d, pHdr=%p, pBuffer=%p",
+ AVB_LOGF_VERBOSE("block=%d, buffer=%d, out=%d, pBuffer=%p, pHdr=%p",
rawsock->blockIndex, rawsock->bufferIndex, rawsock->buffersOut,
- pHdr, pBuffer);
+ pBuffer, pHdr);
// Check if buffer ready for user
// In receive mode, we want TP_STATUS_USER flag set
@@ -595,7 +601,12 @@ U8* ringRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, un
rawsock->buffersOut += 1;
if (pHdr->tp_snaplen < pHdr->tp_len) {
+#if (AVB_LOG_LEVEL >= AVB_LOG_LEVEL_VERBOSE)
+ AVB_LOGF_WARNING("Getting RX frame; partial frame ignored (len %d, snaplen %d)", pHdr->tp_len, pHdr->tp_snaplen);
+ AVB_LOG_BUFFER(AVB_LOG_LEVEL_VERBOSE, (const U8 *) pBuffer + (pHdr->tp_mac - rawsock->bufHdrSize), pHdr->tp_len, 16);
+#else
IF_LOG_INTERVAL(1000) AVB_LOGF_WARNING("Getting RX frame; partial frame ignored (len %d, snaplen %d)", pHdr->tp_len, pHdr->tp_snaplen);
+#endif
ringRawsockRelRxFrame(rawsock, (U8*)pBuffer);
AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
return NULL;
@@ -604,6 +615,7 @@ U8* ringRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, un
// Return pointer to the buffer and length
*offset = pHdr->tp_mac - rawsock->bufHdrSize;
*len = pHdr->tp_snaplen;
+ AVB_LOGF_VERBOSE("Good RX frame (len %d, snaplen %d)", pHdr->tp_len, pHdr->tp_snaplen);
AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
return (U8*)pBuffer;
@@ -622,7 +634,7 @@ int ringRawsockRxParseHdr(void *pvRawsock, U8 *pBuffer, hdr_info_t *pInfo)
}
volatile struct tpacket2_hdr *pHdr = (struct tpacket2_hdr*)(pBuffer - rawsock->bufHdrSize);
- AVB_LOGF_VERBOSE("pBuffer=%p, pHdr=%p", pBuffer, pHdr);
+ AVB_LOGF_VERBOSE("ringRawsockRxParseHdr: pBuffer=%p, pHdr=%p", pBuffer, pHdr);
memset(pInfo, 0, sizeof(hdr_info_t));
@@ -631,6 +643,8 @@ int ringRawsockRxParseHdr(void *pvRawsock, U8 *pBuffer, hdr_info_t *pInfo)
pInfo->shost = pNoTag->shost;
pInfo->dhost = pNoTag->dhost;
pInfo->ethertype = ntohs(pNoTag->ethertype);
+ pInfo->ts.tv_sec = pHdr->tp_sec;
+ pInfo->ts.tv_nsec = pHdr->tp_nsec;
if (pInfo->ethertype == ETHERTYPE_8021Q) {
pInfo->vlan = TRUE;
@@ -657,7 +671,7 @@ bool ringRawsockRelRxFrame(void *pvRawsock, U8 *pBuffer)
}
volatile struct tpacket2_hdr *pHdr = (struct tpacket2_hdr*)(pBuffer - rawsock->bufHdrSize);
- AVB_LOGF_VERBOSE("pBuffer=%p, pHdr=%p", pBuffer, pHdr);
+ AVB_LOGF_VERBOSE("ringRawsockRelRxFrame: pBuffer=%p, pHdr=%p", pBuffer, pHdr);
pHdr->tp_status = TP_STATUS_KERNEL;
rawsock->buffersOut -= 1;
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/ring_rawsock.h b/lib/avtp_pipeline/platform/Linux/rawsock/ring_rawsock.h
index 92117f84..aa98ff7f 100644
--- a/lib/avtp_pipeline/platform/Linux/rawsock/ring_rawsock.h
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/ring_rawsock.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -88,7 +89,7 @@ U8* ringRawsockGetTxFrame(void *pvRawsock, bool blocking, unsigned int *len);
bool ringRawsockRelTxFrame(void *pvRawsock, U8 *pBuffer);
// Release a TX frame, and mark it as ready to send
-bool ringRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len);
+bool ringRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len, U64 timeNsec);
// Send all packets that are ready (i.e. tell kernel to send them)
int ringRawsockSend(void *pvRawsock);
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/sendmmsg_rawsock.c b/lib/avtp_pipeline/platform/Linux/rawsock/sendmmsg_rawsock.c
new file mode 100644
index 00000000..2a2be5c3
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/sendmmsg_rawsock.c
@@ -0,0 +1,503 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#include "sendmmsg_rawsock.h"
+
+#include "simple_rawsock.h"
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <linux/if_packet.h>
+#include <linux/filter.h>
+
+#define AVB_LOG_LEVEL AVB_LOG_LEVEL_INFO
+
+#include "openavb_trace.h"
+
+#define AVB_LOG_COMPONENT "Raw Socket"
+#include "openavb_log.h"
+
+
+#if USE_LAUNCHTIME
+
+#ifndef SCM_TIMEDLAUNCH
+#define SCM_TIMEDLAUNCH 0x04
+#endif
+
+#endif /* if USE_LAUNCHTIME */
+
+
+static void fillmsghdr(struct msghdr *msg, struct iovec *iov,
+#if USE_LAUNCHTIME
+ unsigned char *cmsgbuf, uint64_t time,
+#endif
+ void *pktdata, size_t pktlen)
+{
+ msg->msg_name = NULL;
+ msg->msg_namelen = 0;
+
+ iov->iov_base = pktdata;
+ iov->iov_len = pktlen;
+ msg->msg_iov = iov;
+ msg->msg_iovlen = 1;
+
+#if USE_LAUNCHTIME
+ {
+ struct cmsghdr *cmsg;
+ uint64_t *tsptr;
+
+ msg->msg_control = cmsgbuf;
+ msg->msg_controllen = CMSG_LEN(sizeof time);
+
+ cmsg = CMSG_FIRSTHDR(msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_TIMEDLAUNCH;
+ cmsg->cmsg_len = CMSG_LEN(sizeof time);
+
+ tsptr = (uint64_t *)CMSG_DATA(cmsg);
+ *tsptr = time;
+ }
+#else
+ msg->msg_control = NULL;
+ msg->msg_controllen = 0;
+#endif
+
+ msg->msg_flags = 0;
+}
+
+// Open a rawsock for TX or RX
+void* sendmmsgRawsockOpen(sendmmsg_rawsock_t* rawsock, const char *ifname, bool rx_mode, bool tx_mode, U16 ethertype, U32 frame_size, U32 num_frames)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+
+ AVB_LOGF_DEBUG("Open, ifname=%s, rx=%d, tx=%d, ethertype=%x size=%d, num=%d",
+ ifname, rx_mode, tx_mode, ethertype, frame_size, num_frames);
+
+ baseRawsockOpen(&rawsock->base, ifname, rx_mode, tx_mode, ethertype, frame_size, num_frames);
+
+ rawsock->sock = -1;
+
+ // Get info about the network device
+ if (!simpleAvbCheckInterface(ifname, &(rawsock->base.ifInfo))) {
+ AVB_LOGF_ERROR("Creating rawsock; bad interface name: %s", ifname);
+ free(rawsock);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return NULL;
+ }
+
+ // Deal with frame size.
+ if (rawsock->base.frameSize == 0) {
+ // use interface MTU as max frames size, if none specified
+ rawsock->base.frameSize = rawsock->base.ifInfo.mtu + ETH_HLEN + VLAN_HLEN;
+ }
+ else if (rawsock->base.frameSize > rawsock->base.ifInfo.mtu + ETH_HLEN + VLAN_HLEN) {
+ AVB_LOG_ERROR("Creating raswsock; requested frame size exceeds MTU");
+ free(rawsock);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return NULL;
+ }
+ rawsock->base.frameSize = TPACKET_ALIGN(rawsock->base.frameSize);
+ assert(rawsock->base.frameSize <= MAX_FRAME_SIZE);
+
+ // Prepare default Ethernet header.
+ rawsock->base.ethHdrLen = sizeof(eth_hdr_t);
+ memset(&(rawsock->base.ethHdr.notag.dhost), 0xFF, ETH_ALEN);
+ memcpy(&(rawsock->base.ethHdr.notag.shost), &(rawsock->base.ifInfo.mac), ETH_ALEN);
+ rawsock->base.ethHdr.notag.ethertype = htons(rawsock->base.ethertype);
+
+ // Create socket
+ rawsock->sock = socket(PF_PACKET, SOCK_RAW, htons(rawsock->base.ethertype));
+ if (rawsock->sock == -1) {
+ AVB_LOGF_ERROR("Creating rawsock; opening socket: %s", strerror(errno));
+ sendmmsgRawsockClose(rawsock);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return NULL;
+ }
+
+ // Allow address reuse
+ int temp = 1;
+ if(setsockopt(rawsock->sock, SOL_SOCKET, SO_REUSEADDR, &temp, sizeof(int)) < 0) {
+ AVB_LOG_ERROR("Creating rawsock; failed to set reuseaddr");
+ sendmmsgRawsockClose(rawsock);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return NULL;
+ }
+
+ // Bind to interface
+ struct sockaddr_ll my_addr;
+ memset(&my_addr, 0, sizeof(my_addr));
+ my_addr.sll_family = PF_PACKET;
+ my_addr.sll_protocol = htons(rawsock->base.ethertype);
+ my_addr.sll_ifindex = rawsock->base.ifInfo.index;
+
+ if (bind(rawsock->sock, (struct sockaddr*)&my_addr, sizeof(my_addr)) == -1) {
+ AVB_LOGF_ERROR("Creating rawsock; bind socket: %s", strerror(errno));
+ sendmmsgRawsockClose(rawsock);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return NULL;
+ }
+
+ // Clear our buffers and other tracking data
+ memset(rawsock->mmsg, 0, sizeof(rawsock->mmsg));
+ memset(rawsock->miov, 0, sizeof(rawsock->miov));
+ memset(rawsock->pktbuf, 0, sizeof(rawsock->pktbuf));
+#if USE_LAUNCHTIME
+ memset(rawsock->cmsgbuf, 0, sizeof(rawsock->cmsgbuf));
+#endif
+
+ rawsock->buffersOut = 0;
+ rawsock->buffersReady = 0;
+ rawsock->frameCount = MSG_COUNT;
+
+ // fill virtual functions table
+ rawsock_cb_t *cb = &rawsock->base.cb;
+ cb->close = sendmmsgRawsockClose;
+ cb->getTxFrame = sendmmsgRawsockGetTxFrame;
+ cb->txSetMark = sendmmsgRawsockTxSetMark;
+ cb->txSetHdr = sendmmsgRawsockTxSetHdr;
+ cb->txFrameReady = sendmmsgRawsockTxFrameReady;
+ cb->send = sendmmsgRawsockSend;
+ cb->getRxFrame = sendmmsgRawsockGetRxFrame;
+ cb->rxMulticast = sendmmsgRawsockRxMulticast;
+ cb->getSocket = sendmmsgRawsockGetSocket;
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return rawsock;
+}
+
+// Close the rawsock
+void sendmmsgRawsockClose(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+ sendmmsg_rawsock_t *rawsock = (sendmmsg_rawsock_t*)pvRawsock;
+
+ if (rawsock) {
+ if (rawsock->sock != -1) {
+ close(rawsock->sock);
+ rawsock->sock = -1;
+ }
+ }
+
+ baseRawsockClose(rawsock);
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+}
+
+// Get a buffer from the ring to use for TX
+U8* sendmmsgRawsockGetTxFrame(void *pvRawsock, bool blocking, unsigned int *len)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ sendmmsg_rawsock_t *rawsock = (sendmmsg_rawsock_t*)pvRawsock;
+
+ if (!VALID_TX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Getting TX frame; bad arguments");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return NULL;
+ }
+ if (rawsock->buffersOut >= rawsock->frameCount) {
+ AVB_LOG_ERROR("Getting TX frame; too many TX buffers in use");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return NULL;
+ }
+
+ U8 *pBuffer = rawsock->pktbuf[rawsock->buffersOut];
+ rawsock->buffersOut += 1;
+
+ // Remind client how big the frame buffer is
+ if (len)
+ *len = rawsock->base.frameSize;
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return pBuffer;
+}
+
+// Set the Firewall MARK on the socket
+// The mark is used by FQTSS to identify AVTP packets in kernel.
+// FQTSS creates a mark that includes the AVB class and stream index.
+bool sendmmsgRawsockTxSetMark(void *pvRawsock, int mark)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ sendmmsg_rawsock_t *rawsock = (sendmmsg_rawsock_t*)pvRawsock;
+ bool retval = FALSE;
+
+ if (!VALID_TX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Setting TX mark; invalid argument passed");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return FALSE;
+ }
+
+ if (setsockopt(rawsock->sock, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0) {
+ AVB_LOGF_ERROR("Setting TX mark; setsockopt failed: %s", strerror(errno));
+ }
+ else {
+ AVB_LOGF_DEBUG("SO_MARK=%d OK", mark);
+ retval = TRUE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return retval;
+}
+
+// Pre-set the ethernet header information that will be used on TX frames
+bool sendmmsgRawsockTxSetHdr(void *pvRawsock, hdr_info_t *pHdr)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ sendmmsg_rawsock_t *rawsock = (sendmmsg_rawsock_t*)pvRawsock;
+
+ bool ret = baseRawsockTxSetHdr(pvRawsock, pHdr);
+ if (ret && pHdr->vlan) {
+ // set the class'es priority on the TX socket
+ // (required by Telechips platform for FQTSS Credit Based Shaper to work)
+ U32 pcp = pHdr->vlan_pcp;
+ if (setsockopt(rawsock->sock, SOL_SOCKET, SO_PRIORITY, (char *)&pcp, sizeof(pcp)) < 0) {
+ AVB_LOGF_ERROR("openavbRawsockTxSetHdr; SO_PRIORITY setsockopt failed (%d: %s)\n", errno, strerror(errno));
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return FALSE;
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return ret;
+}
+
+// Release a TX frame, mark it ready to send
+bool sendmmsgRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len, U64 timeNsec)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ sendmmsg_rawsock_t *rawsock = (sendmmsg_rawsock_t*)pvRawsock;
+ int bufidx;
+
+ if (!VALID_TX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Marking TX frame ready; invalid argument");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return FALSE;
+ }
+
+ bufidx = rawsock->buffersReady;
+ assert(pBuffer == rawsock->pktbuf[bufidx]);
+
+#if USE_LAUNCHTIME
+ if (!timeNsec) {
+ IF_LOG_INTERVAL(1000) AVB_LOG_WARNING("launch time is enabled but not passed to TxFrameReady");
+ }
+ fillmsghdr(&(rawsock->mmsg[bufidx].msg_hdr), &(rawsock->miov[bufidx]), rawsock->cmsgbuf[bufidx],
+ timeNsec, rawsock->pktbuf[bufidx], len);
+#else
+ if (timeNsec) {
+ IF_LOG_INTERVAL(1000) AVB_LOG_WARNING("launch time is not enabled but was passed to TxFrameReady");
+ }
+ fillmsghdr(&(rawsock->mmsg[bufidx].msg_hdr), &(rawsock->miov[bufidx]), rawsock->pktbuf[bufidx], len);
+#endif
+
+
+ rawsock->buffersReady += 1;
+
+ if (rawsock->buffersReady >= rawsock->frameCount) {
+ AVB_LOG_DEBUG("All TxFrame slots marked ready");
+ //sendmmsgRawsockSend(rawsock);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return TRUE;
+}
+
+// Send all packets that are ready (i.e. tell kernel to send them)
+int sendmmsgRawsockSend(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ sendmmsg_rawsock_t *rawsock = (sendmmsg_rawsock_t*)pvRawsock;
+ int sz, bytes;
+
+ if (!VALID_TX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Marking TX frame ready; invalid argument");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return -1;
+ }
+
+ if (rawsock->buffersOut != rawsock->buffersReady) {
+ AVB_LOGF_ERROR("Tried to send with %d bufs out, %d bufs ready", rawsock->buffersOut, rawsock->buffersReady);
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return -1;
+ }
+
+ IF_LOG_INTERVAL(1000) AVB_LOGF_DEBUG("Send with %d of %d buffers ready", rawsock->buffersReady, rawsock->frameCount);
+ sz = sendmmsg(rawsock->sock, rawsock->mmsg, rawsock->buffersReady, 0);
+ if (sz < 0) {
+ AVB_LOGF_ERROR("Call to sendmmsg failed! Error code was %d", sz);
+ bytes = sz;
+ } else {
+ int i;
+ for (i = 0, bytes = 0; i < sz; i++) {
+ bytes += rawsock->mmsg[i].msg_len;
+ }
+ if (sz < rawsock->buffersReady) {
+ AVB_LOGF_WARNING("Only sent %ld of %d messages; dropping others", sz, rawsock->buffersReady);
+ }
+ }
+
+ rawsock->buffersOut = rawsock->buffersReady = 0;
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return bytes;
+}
+
+// Get a RX frame
+U8* sendmmsgRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, unsigned int *len)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ sendmmsg_rawsock_t *rawsock = (sendmmsg_rawsock_t*)pvRawsock;
+ if (!VALID_RX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Getting RX frame; invalid arguments");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return NULL;
+ }
+// For switching to recvmmsg eventually
+// if (rawsock->rxbuffersOut >= rawsock->rxframeCount) {
+// AVB_LOG_ERROR("Too many RX buffers in use");
+// AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+// return NULL;
+// }
+
+ int flags = 0;
+
+ U8 *pBuffer = rawsock->rxBuffer;
+ *offset = 0;
+ *len = recv(rawsock->sock, pBuffer, rawsock->base.frameSize, flags);
+
+ if (*len == (unsigned int)(-1)) {
+ AVB_LOGF_ERROR("%s %s", __func__, strerror(errno));
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return NULL;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return pBuffer;
+}
+
+// Setup the rawsock to receive multicast packets
+bool sendmmsgRawsockRxMulticast(void *pvRawsock, bool add_membership, const U8 addr[ETH_ALEN])
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+
+ sendmmsg_rawsock_t *rawsock = (sendmmsg_rawsock_t*)pvRawsock;
+ if (!VALID_RX_RAWSOCK(rawsock)) {
+ AVB_LOG_ERROR("Setting multicast; invalid arguments");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return FALSE;
+ }
+
+ struct ether_addr mcast_addr;
+ memcpy(mcast_addr.ether_addr_octet, addr, ETH_ALEN);
+
+ // Fill in the structure for the multicast ioctl
+ struct packet_mreq mreq;
+ memset(&mreq, 0, sizeof(struct packet_mreq));
+ mreq.mr_ifindex = rawsock->base.ifInfo.index;
+ mreq.mr_type = PACKET_MR_MULTICAST;
+ mreq.mr_alen = ETH_ALEN;
+ memcpy(&mreq.mr_address, &mcast_addr.ether_addr_octet, ETH_ALEN);
+
+ // And call the ioctl to add/drop the multicast address
+ int action = (add_membership ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP);
+ if (setsockopt(rawsock->sock, SOL_PACKET, action,
+ (void*)&mreq, sizeof(struct packet_mreq)) < 0) {
+ AVB_LOGF_ERROR("Setting multicast; setsockopt(%s) failed: %s",
+ (add_membership ? "PACKET_ADD_MEMBERSHIP" : "PACKET_DROP_MEMBERSHIP"),
+ strerror(errno));
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return FALSE;
+ }
+
+ // In addition to adding the multicast membership, we also want to
+ // add a packet filter to restrict the packets that we'll receive
+ // on this socket. Multicast memeberships are global - not
+ // per-socket, so without the filter, this socket would receieve
+ // packets for all the multicast addresses added by all other
+ // sockets.
+ //
+ if (add_membership)
+ {
+ // Here's the template packet filter code.
+ // It was produced by running:
+ // tcpdump -dd ether dest host 91:e0:01:02:03:04
+ struct sock_filter bpfCode[] = {
+ { 0x20, 0, 0, 0x00000002 },
+ { 0x15, 0, 3, 0x01020304 }, // last 4 bytes of dest mac
+ { 0x28, 0, 0, 0x00000000 },
+ { 0x15, 0, 1, 0x000091e0 }, // first 2 bytes of dest mac
+ { 0x06, 0, 0, 0x0000ffff },
+ { 0x06, 0, 0, 0x00000000 }
+ };
+
+ // We need to graft our multicast dest address into bpfCode
+ U32 tmp; U8 *buf = (U8*)&tmp;
+ memcpy(buf, mcast_addr.ether_addr_octet + 2, 4);
+ bpfCode[1].k = ntohl(tmp);
+ memset(buf, 0, 4);
+ memcpy(buf + 2, mcast_addr.ether_addr_octet, 2);
+ bpfCode[3].k = ntohl(tmp);
+
+ // Now wrap the filter code in the appropriate structure
+ struct sock_fprog filter;
+ memset(&filter, 0, sizeof(filter));
+ filter.len = 6;
+ filter.filter = bpfCode;
+
+ // And attach it to our socket
+ if (setsockopt(rawsock->sock, SOL_SOCKET, SO_ATTACH_FILTER,
+ &filter, sizeof(filter)) < 0) {
+ AVB_LOGF_ERROR("Setting multicast; setsockopt(SO_ATTACH_FILTER) failed: %s", strerror(errno));
+ }
+ }
+ else {
+ if (setsockopt(rawsock->sock, SOL_SOCKET, SO_DETACH_FILTER, NULL, 0) < 0) {
+ AVB_LOGF_ERROR("Setting multicast; setsockopt(SO_DETACH_FILTER) failed: %s", strerror(errno));
+ }
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return TRUE;
+}
+
+// Get the socket used for this rawsock; can be used for poll/select
+int sendmmsgRawsockGetSocket(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK);
+ sendmmsg_rawsock_t *rawsock = (sendmmsg_rawsock_t*)pvRawsock;
+ if (!rawsock) {
+ AVB_LOG_ERROR("Getting socket; invalid arguments");
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return -1;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
+ return rawsock->sock;
+}
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/sendmmsg_rawsock.h b/lib/avtp_pipeline/platform/Linux/rawsock/sendmmsg_rawsock.h
new file mode 100644
index 00000000..05cf4b54
--- /dev/null
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/sendmmsg_rawsock.h
@@ -0,0 +1,110 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#ifndef SENDMMSG_RAWSOCK_H
+#define SENDMMSG_RAWSOCK_H
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <sys/socket.h>
+
+#include "rawsock_impl.h"
+
+#define MSG_COUNT 8
+#define MAX_FRAME_SIZE 1024
+#define USE_LAUNCHTIME 0
+
+
+// State information for raw socket
+//
+typedef struct {
+ base_rawsock_t base;
+
+ // the underlying socket
+ int sock;
+
+ // count of total buffers available for messages
+ int frameCount;
+
+ // count of buffers taken by senders
+ int buffersOut;
+
+ // count of buffers ready to send
+ int buffersReady;
+
+ // buffer for receiving frames
+ U8 rxBuffer[1518];
+
+ struct mmsghdr mmsg[MSG_COUNT];
+
+ struct iovec miov[MSG_COUNT];
+
+ unsigned char pktbuf[MSG_COUNT][MAX_FRAME_SIZE];
+#if USE_LAUNCHTIME
+ unsigned char cmsgbuf[MSG_COUNT][CMSG_SPACE(sizeof(uint64_t))];
+#endif
+} sendmmsg_rawsock_t;
+
+// Open a rawsock for TX or RX
+void* sendmmsgRawsockOpen(sendmmsg_rawsock_t *rawsock, const char *ifname, bool rx_mode, bool tx_mode, U16 ethertype, U32 frame_size, U32 num_frames);
+
+// Close the rawsock
+void sendmmsgRawsockClose(void *pvRawsock);
+
+// Get a buffer from the simple to use for TX
+U8* sendmmsgRawsockGetTxFrame(void *pvRawsock, bool blocking, unsigned int *len);
+
+// Set the Firewall MARK on the socket
+// The mark is used by FQTSS to identify AVTP packets in kernel.
+// FQTSS creates a mark that includes the AVB class and stream index.
+bool sendmmsgRawsockTxSetMark(void *pvRawsock, int mark);
+
+// Pre-set the ethernet header information that will be used on TX frames
+bool sendmmsgRawsockTxSetHdr(void *pvRawsock, hdr_info_t *pHdr);
+
+// Release a TX frame, and mark it as ready to send
+bool sendmmsgRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len, U64 timeNsec);
+
+// Send all packets that are ready (i.e. tell kernel to send them)
+int sendmmsgRawsockSend(void *pvRawsock);
+
+// Get a RX frame
+U8* sendmmsgRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, unsigned int *len);
+
+// Setup the rawsock to receive multicast packets
+bool sendmmsgRawsockRxMulticast(void *pvRawsock, bool add_membership, const U8 addr[ETH_ALEN]);
+
+// Get the socket used for this rawsock; can be used for poll/select
+int sendmmsgRawsockGetSocket(void *pvRawsock);
+
+#endif
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.c b/lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.c
index 385d57e6..18293a37 100644
--- a/lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.c
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -137,7 +138,7 @@ void* simpleRawsockOpen(simple_rawsock_t* rawsock, const char *ifname, bool rx_m
// Get info about the network device
if (!simpleAvbCheckInterface(ifname, &(rawsock->base.ifInfo))) {
AVB_LOGF_ERROR("Creating rawsock; bad interface name: %s", ifname);
- free(rawsock);
+ simpleRawsockClose(rawsock);
AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
return NULL;
}
@@ -149,7 +150,7 @@ void* simpleRawsockOpen(simple_rawsock_t* rawsock, const char *ifname, bool rx_m
}
else if (rawsock->base.frameSize > rawsock->base.ifInfo.mtu + ETH_HLEN + VLAN_HLEN) {
AVB_LOG_ERROR("Creating raswsock; requested frame size exceeds MTU");
- free(rawsock);
+ simpleRawsockClose(rawsock);
AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
return NULL;
}
@@ -201,9 +202,12 @@ void* simpleRawsockOpen(simple_rawsock_t* rawsock, const char *ifname, bool rx_m
cb->txSetMark = simpleRawsockTxSetMark;
cb->txSetHdr = simpleRawsockTxSetHdr;
cb->txFrameReady = simpleRawsockTxFrameReady;
+ cb->send = simpleRawsockSend;
cb->getRxFrame = simpleRawsockGetRxFrame;
cb->rxMulticast = simpleRawsockRxMulticast;
+ cb->rxAVTPSubtype = simpleRawsockRxAVTPSubtype;
cb->getSocket = simpleRawsockGetSocket;
+ cb->relRxFrame = simpleRawsockRelRxFrame;
AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
return rawsock;
@@ -305,7 +309,7 @@ bool simpleRawsockTxSetHdr(void *pvRawsock, hdr_info_t *pHdr)
}
// Release a TX frame, and send it
-bool simpleRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len)
+bool simpleRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len, U64 timeNsec)
{
AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
simple_rawsock_t *rawsock = (simple_rawsock_t*)pvRawsock;
@@ -316,6 +320,10 @@ bool simpleRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len)
return FALSE;
}
+ if (timeNsec) {
+ IF_LOG_INTERVAL(1000) AVB_LOG_WARNING("launch time is unsupported in simple_rawsock");
+ }
+
int flags = MSG_DONTWAIT;
send(rawsock->sock, pBuffer, len, flags);
@@ -323,6 +331,17 @@ bool simpleRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len)
return TRUE;
}
+// Send all packets that are ready (i.e. tell kernel to send them)
+int simpleRawsockSend(void *pvRawsock)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+
+ // simpleRawsock sends frames in simpleRawsockTxFrameReady
+
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return 1;
+}
+
// Get a RX frame
U8* simpleRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, unsigned int *len)
{
@@ -339,10 +358,23 @@ U8* simpleRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset,
// return NULL;
// }
+ *offset = 0;
+ *len = 0;
+
+ // Wait until a packet is available, or a timeout occurs.
+ struct timeval tv_timeout = { timeout / MICROSECONDS_PER_SECOND, timeout % MICROSECONDS_PER_SECOND };
+ fd_set readfds;
+ FD_ZERO( &readfds );
+ FD_SET( rawsock->sock, &readfds );
+ int err = select( rawsock->sock + 1, &readfds, NULL, NULL, &tv_timeout );
+ if (err <= 0) {
+ AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
+ return NULL;
+ }
+
int flags = 0;
U8 *pBuffer = rawsock->rxBuffer;
- *offset = 0;
*len = recv(rawsock->sock, pBuffer, rawsock->base.frameSize, flags);
if (*len == -1) {
@@ -392,8 +424,8 @@ bool simpleRawsockRxMulticast(void *pvRawsock, bool add_membership, const U8 add
// In addition to adding the multicast membership, we also want to
// add a packet filter to restrict the packets that we'll receive
- // on this socket. Multicast memeberships are global - not
- // per-socket, so without the filter, this socket would receieve
+ // on this socket. Multicast memberships are global - not
+ // per-socket, so without the filter, this socket would receive
// packets for all the multicast addresses added by all other
// sockets.
//
@@ -441,6 +473,11 @@ bool simpleRawsockRxMulticast(void *pvRawsock, bool add_membership, const U8 add
return TRUE;
}
+bool simpleRawsockRxAVTPSubtype(void *rawsock, U8 subtype)
+{
+ return true; //TODO: implement as BPF to improve performance
+}
+
// Get the socket used for this rawsock; can be used for poll/select
int simpleRawsockGetSocket(void *pvRawsock)
{
@@ -455,3 +492,8 @@ int simpleRawsockGetSocket(void *pvRawsock)
AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK);
return rawsock->sock;
}
+
+bool simpleRawsockRelRxFrame(void *pvRawsock, U8 *pFrame)
+{
+ return true;
+}
diff --git a/lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.h b/lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.h
index db0ef1f3..2bbf8649 100644
--- a/lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.h
+++ b/lib/avtp_pipeline/platform/Linux/rawsock/simple_rawsock.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -68,7 +69,10 @@ bool simpleRawsockTxSetMark(void *pvRawsock, int mark);
bool simpleRawsockTxSetHdr(void *pvRawsock, hdr_info_t *pHdr);
// Release a TX frame, and mark it as ready to send
-bool simpleRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len);
+bool simpleRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len, U64 timeNsec);
+
+// Send all packets that are ready (i.e. tell kernel to send them)
+int simpleRawsockSend(void *pvRawsock);
// Get a RX frame
U8* simpleRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset, unsigned int *len);
@@ -76,7 +80,13 @@ U8* simpleRawsockGetRxFrame(void *pvRawsock, U32 timeout, unsigned int *offset,
// Setup the rawsock to receive multicast packets
bool simpleRawsockRxMulticast(void *pvRawsock, bool add_membership, const U8 addr[ETH_ALEN]);
+// Allows for filtering of AVTP subtypes at the rawsock level for rawsock implementations that aren't able to
+// delivery the same packet to multiple sockets.
+bool simpleRawsockRxAVTPSubtype(void *rawsock, U8 subtype);
+
// Get the socket used for this rawsock; can be used for poll/select
int simpleRawsockGetSocket(void *pvRawsock);
+bool simpleRawsockRelRxFrame(void *pvRawsock, U8 *pFrame);
+
#endif
diff --git a/lib/avtp_pipeline/platform/Linux/tl/openavb_tl_osal.c b/lib/avtp_pipeline/platform/Linux/tl/openavb_tl_osal.c
index d10ab6b8..f9e7d1f1 100644
--- a/lib/avtp_pipeline/platform/Linux/tl/openavb_tl_osal.c
+++ b/lib/avtp_pipeline/platform/Linux/tl/openavb_tl_osal.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -48,6 +49,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_rawsock.h"
#include "openavb_mediaq.h"
#include "openavb_tl.h"
+#include "openavb_avtp.h"
#define AVB_LOG_COMPONENT "Talker / Listener"
#include "openavb_log.h"
@@ -61,7 +63,7 @@ typedef struct {
openavb_tl_cfg_name_value_t *pNVCfg;
} parse_ini_data_t;
-bool parse_mac(const char *str, cfg_mac_t *mac)
+static bool parse_mac(const char *str, cfg_mac_t *mac)
{
memset(&mac->buffer, 0, sizeof(struct ether_addr));
@@ -173,6 +175,16 @@ static int openavbTLCfgCallback(void *user, const char *tlSection, const char *n
valOK = TRUE;
}
}
+ else if (MATCH(name, "initial_state")) {
+ if (MATCH(value, "running")) {
+ pCfg->initial_state = TL_INIT_STATE_RUNNING;
+ valOK = TRUE;
+ }
+ else if (MATCH(value, "stopped")) {
+ pCfg->initial_state = TL_INIT_STATE_STOPPED;
+ valOK = TRUE;
+ }
+ }
else if (MATCH(name, "dest_addr")) {
valOK = parse_mac(value, &pCfg->dest_addr);
}
@@ -283,6 +295,14 @@ static int openavbTLCfgCallback(void *user, const char *tlSection, const char *n
&& pCfg->report_seconds <= INT32_MAX)
valOK = TRUE;
}
+ else if (MATCH(name, "report_frames")) {
+ errno = 0;
+ pCfg->report_frames = strtol(value, &pEnd, 10);
+ if (*pEnd == '\0' && errno == 0
+ && (int)pCfg->report_frames >= 0
+ && pCfg->report_frames <= INT32_MAX)
+ valOK = TRUE;
+ }
else if (MATCH(name, "start_paused")) {
// ignore this item - tl_host doesn't use it because
// it pauses before reading any of its streams.
@@ -312,6 +332,56 @@ static int openavbTLCfgCallback(void *user, const char *tlSection, const char *n
valOK = TRUE;
}
}
+ else if (MATCH(name, "fixed_timestamp")) {
+ errno = 0;
+ long tmp;
+ tmp = strtol(value, &pEnd, 0);
+ if (*pEnd == '\0' && errno == 0) {
+ pCfg->fixed_timestamp = tmp;
+ valOK = TRUE;
+ }
+ }
+ else if (MATCH(name, "spin_wait")) {
+ errno = 0;
+ long tmp;
+ tmp = strtol(value, &pEnd, 0);
+ if (*pEnd == '\0' && errno == 0) {
+ pCfg->spin_wait = (tmp == 1);
+ valOK = TRUE;
+ }
+ }
+ else if (MATCH(name, "tx_blocking_in_intf")) {
+ errno = 0;
+ long tmp;
+ tmp = strtol(value, &pEnd, 0);
+ if (*pEnd == '\0' && errno == 0) {
+ pCfg->tx_blocking_in_intf = tmp;
+ valOK = TRUE;
+ }
+ }
+ else if (MATCH(name, "thread_rt_priority")) {
+ errno = 0;
+ long tmp;
+ tmp = strtol(value, &pEnd, 0);
+ if (*pEnd == '\0' && errno == 0) {
+ pCfg->thread_rt_priority = tmp;
+ valOK = TRUE;
+ }
+ }
+ else if (MATCH(name, "thread_affinity")) {
+ errno = 0;
+ unsigned long tmp;
+ tmp = strtoul(value, &pEnd, 0);
+ if (*pEnd == '\0' && errno == 0) {
+ pCfg->thread_affinity = tmp;
+ valOK = TRUE;
+ }
+ }
+
+ else if (MATCH(name, "friendly_name")) {
+ strncpy(pCfg->friendly_name, value, FRIENDLY_NAME_SIZE - 1);
+ valOK = TRUE;
+ }
else if (MATCH(name, "map_lib")) {
if (pTLState->mapLib.libName)
@@ -369,12 +439,14 @@ static int openavbTLCfgCallback(void *user, const char *tlSection, const char *n
else {
// unmatched item, fail
AVB_LOGF_ERROR("Unrecognized configuration item: name=%s", name);
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
return 0;
}
if (!valOK) {
// bad value
AVB_LOGF_ERROR("Invalid value: name=%s, value=%s", name, value);
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
return 0;
}
@@ -389,9 +461,6 @@ bool openavbTLThreadFnOsal(tl_state_t *pTLState)
}
-
-
-
EXTERN_DLL_EXPORT bool openavbTLReadIniFileOsal(tl_handle_t TLhandle, const char *fileName, openavb_tl_cfg_t *pCfg, openavb_tl_cfg_name_value_t *pNVCfg)
{
AVB_TRACE_ENTRY(AVB_TRACE_TL);
@@ -401,23 +470,62 @@ EXTERN_DLL_EXPORT bool openavbTLReadIniFileOsal(tl_handle_t TLhandle, const char
parseIniData.pCfg = pCfg;
parseIniData.pNVCfg = pNVCfg;
+ // Use the .INI file name as the default friendly name.
+ strncpy(parseIniData.pCfg->friendly_name, fileName, FRIENDLY_NAME_SIZE - 1);
+ char * pszComma = strchr(parseIniData.pCfg->friendly_name, ',');
+ if (pszComma) {
+ // Get rid of anything following the file name.
+ *pszComma = '\0';
+ }
+ char * pszExtension = strrchr(parseIniData.pCfg->friendly_name, '.');
+ if (pszExtension && strcasecmp(pszExtension, ".ini") == 0) {
+ // Get rid of the .INI file extension.
+ *pszExtension = '\0';
+ }
+
int result = ini_parse(fileName, openavbTLCfgCallback, &parseIniData);
if (result == 0) {
if_info_t ifinfo;
- if (!openavbCheckInterface(&parseIniData.pCfg->ifname, &ifinfo)) {
+ if (pCfg->ifname[0] && !openavbCheckInterface(parseIniData.pCfg->ifname, &ifinfo)) {
AVB_LOGF_ERROR("Invalid value: name=%s, value=%s", "ifname", parseIniData.pCfg->ifname);
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
return FALSE;
}
}
if (result < 0) {
AVB_LOGF_ERROR("Couldn't parse INI file: %s", fileName);
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
return FALSE;
}
if (result > 0) {
AVB_LOGF_ERROR("Error in INI file: %s, line %d", fileName, result);
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
return FALSE;
}
+ // For a Talker, use the adapter MAC Address as the stream address when one was not supplied.
+ if (parseIniData.pCfg->role == AVB_ROLE_TALKER &&
+ (!parseIniData.pCfg->stream_addr.mac || memcmp(parseIniData.pCfg->stream_addr.mac, "\x00\x00\x00\x00\x00\x00", 6) == 0))
+ {
+ // Open a rawsock may be the easiest cross platform way to get the MAC address.
+ void *txSock = openavbRawsockOpen(parseIniData.pCfg->ifname, FALSE, TRUE, ETHERTYPE_AVTP, 100, 1);
+ if (txSock) {
+ if (openavbRawsockGetAddr(txSock, parseIniData.pCfg->stream_addr.buffer.ether_addr_octet)) {
+ parseIniData.pCfg->stream_addr.mac = &(parseIniData.pCfg->stream_addr.buffer); // Indicate that the MAC Address is valid.
+ }
+ openavbRawsockClose(txSock);
+ txSock = NULL;
+ }
+
+ if (!parseIniData.pCfg->stream_addr.mac || memcmp(parseIniData.pCfg->stream_addr.mac, "\x00\x00\x00\x00\x00\x00", 6) == 0) {
+ AVB_LOG_ERROR("stream_addr required, but not specified.");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return FALSE;
+ }
+ AVB_LOGF_DEBUG("Detected stream_addr: " ETH_FORMAT,
+ ETH_OCTETS(parseIniData.pCfg->stream_addr.buffer.ether_addr_octet));
+ }
+
AVB_TRACE_EXIT(AVB_TRACE_TL);
return TRUE;
}
@@ -429,12 +537,14 @@ bool openavbTLOpenLinkLibsOsal(tl_state_t *pTLState)
if (!pTLState->cfg.pMapInitFn) {
if (!openMapLib(pTLState)) {
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
return FALSE;
}
}
if (!pTLState->cfg.pIntfInitFn) {
if (!openIntfLib(pTLState)) {
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
return FALSE;
}
}
diff --git a/lib/avtp_pipeline/platform/Linux/x86_i210_linux.cmake b/lib/avtp_pipeline/platform/Linux/x86_i210_linux.cmake
index ae9ce67a..48e62223 100644
--- a/lib/avtp_pipeline/platform/Linux/x86_i210_linux.cmake
+++ b/lib/avtp_pipeline/platform/Linux/x86_i210_linux.cmake
@@ -1,3 +1,16 @@
+
+if (AVB_FEATURE_AVDECC)
+ set ( AVB_FEATURE_GSTREAMER 0 )
+ set ( AVB_FEATURE_PCAP 0 )
+ set ( AVB_FEATURE_IGB 0 )
+else ()
+ set ( AVB_FEATURE_PCAP 1 )
+ set ( AVB_FEATURE_IGB 1 )
+
+ set ( GSTREAMER_1_0 0 )
+endif ()
+
+
# and another kernel sources
#set ( LINUX_KERNEL_DIR "/usr/src/kernel" )
@@ -8,26 +21,30 @@ set ( OPENAVB_TCAL "GNU" )
set ( OPENAVB_PLATFORM "${OPENAVB_HAL}-${OPENAVB_OSAL}" )
# Platform Additions
-set ( PLATFORM_INCLUDE_DIRECTORIES
- ${CMAKE_SOURCE_DIR}/platform/x86_i210/include
- ${CMAKE_SOURCE_DIR}/../igb
+set ( PLATFORM_INCLUDE_DIRECTORIES
+ ${CMAKE_SOURCE_DIR}/platform/x86_i210/include
+if (AVB_FEATURE_IGB)
+ ${CMAKE_SOURCE_DIR}/../igb
+endif ()
${CMAKE_SOURCE_DIR}/openavb_common
${CMAKE_SOURCE_DIR}/../../daemons/common
${CMAKE_SOURCE_DIR}/../../daemons/mrpd
+ ${CMAKE_SOURCE_DIR}/../../daemons/maap/common
)
-set ( PLATFORM_LINK_DIRECTORIES
- ${CMAKE_SOURCE_DIR}/../igb
-)
-
-set ( PLATFORM_LINK_LIBRARIES
- igb
-)
+if (AVB_FEATURE_IGB)
+ set ( PLATFORM_LINK_DIRECTORIES
+ ${CMAKE_SOURCE_DIR}/../igb
+ )
+endif ()
+if (AVB_FEATURE_IGB)
+ set ( PLATFORM_LINK_LIBRARIES
+ igb
+ pci
+ )
+endif ()
# TODO_OPENAVB : need this?
# Set platform specific define
#set ( PLATFORM_DEFINE "AVB_DELAY_TWEAK_USEC=15" )
-
-set ( GSTREAMER_1_0 0 )
-set ( AVB_FEATURE_PCAP 1 )
diff --git a/lib/avtp_pipeline/platform/generic/include/linux/ptp_clock.h b/lib/avtp_pipeline/platform/generic/include/linux/ptp_clock.h
deleted file mode 100644
index b829d8dd..00000000
--- a/lib/avtp_pipeline/platform/generic/include/linux/ptp_clock.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef _OPENAVB_GENERIC_LINUX_PTP_CLOCK_H
-#define _OPENAVB_GENERIC_LINUX_PTP_CLOCK_H
-
-#include "/usr/include/linux/ptp_clock.h"
-
-#ifndef ptpas_offset_request
-
-#warning "Adding missing PTP declarations, it is just to make everything compile, AVB stack will not work properly."
-
-struct ptpas_offset_request {
- unsigned long long syncReceiptTime;
- unsigned long long syncReceiptLocalTime;
- unsigned int gmRateRatioPPB; // gmRateRatio in ppb
- unsigned int gmSeqNumber; // an indication of the combination of clockID and clockIndex
-};
-
-struct ptpas_get_wallclock {
- long tv_sec; /* seconds */
- long tv_nsec; /* nanoseconds */
- unsigned int gmRateRatioPPB; // gmRateRatio in ppm
- unsigned int gmSeqNumber; // an indication of the combination of clockID and clockIndex
-};
-
-#define PTPAS_SET_OFFSET _IOW(PTP_CLK_MAGIC, 6, struct ptpas_offset_request)
-#define PTPAS_GET_WALLCLOCK _IOR(PTP_CLK_MAGIC, 7, struct ptpas_get_wallclock)
-
-#endif
-
-#endif // _OPENAVB_GENERIC_LINUX_PTP_CLOCK_H
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_ether_osal.h b/lib/avtp_pipeline/platform/generic/mcr/openavb_mcr_hal.c
index a75d2ac6..13236986 100644
--- a/lib/avtp_pipeline/platform/Linux/openavb_ether_osal.h
+++ b/lib/avtp_pipeline/platform/generic/mcr/openavb_mcr_hal.c
@@ -1,40 +1,63 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-#ifndef OPENAVB_ETHER_OSAL_H
-#define OPENAVB_ETHER_OSAL_H 1
-
-#include "openavb_types_base.h"
-#include "openavb_osal.h"
-
-struct ether_addr* ether_aton_r(const char *asc, struct ether_addr *addr);
-bool osalGetMacAddr(U8 *macAddr);
-
-#endif // OPENAVB_ETHER_OSAL_H
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#define AVB_LOG_COMPONENT "MCR"
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+#include "openavb_mcr_hal.h"
+
+
+bool halInitMCR(U32 packetRate, U32 pushInterval, U32 timestampInterval, U32 recoveryInterval)
+{
+ return TRUE;
+}
+
+bool halCloseMCR(void)
+{
+ return TRUE;
+}
+
+bool halPushMCR(void)
+{
+ return TRUE;
+}
+
+void halAdjustMCRNSec(S32 adjNSec)
+{
+}
+
+void halAdjustMCRGranularityNSec(U32 adjGranularityNSec)
+{
+}
+
+
+
diff --git a/lib/avtp_pipeline/platform/Linux/openavb_ether_osal.c b/lib/avtp_pipeline/platform/generic/mcr/openavb_mcr_hal.h
index 95239bf0..c6db6044 100644
--- a/lib/avtp_pipeline/platform/Linux/openavb_ether_osal.c
+++ b/lib/avtp_pipeline/platform/generic/mcr/openavb_mcr_hal.h
@@ -1,39 +1,38 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-#include "openavb_ether_osal.h"
-
-// MAC address is retrieved differently for Linux
-bool osalGetMacAddr(U8 *macAddr)
-{
- return TRUE;
-}
-
-
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#ifndef OPENAVB_MCR_HAL_H
+#define OPENAVB_MCR_HAL_H
+
+#include "openavb_platform.h"
+#include "openavb_mcr_hal_pub.h"
+
+#endif // OPENAVB_MCR_HAL_H
diff --git a/lib/avtp_pipeline/platform/generic/openavb_hal.h b/lib/avtp_pipeline/platform/generic/openavb_hal.h
index e48711eb..1b748de7 100644
--- a/lib/avtp_pipeline/platform/generic/openavb_hal.h
+++ b/lib/avtp_pipeline/platform/generic/openavb_hal.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal.c b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal.c
index deb113b9..33cefb5c 100644
--- a/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal.c
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal.c
@@ -1,39 +1,40 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-#include <malloc.h>
-
-void tcalGetHeapInfo(unsigned int *ttlMallocHeap, unsigned int *freeMallocHeap)
-{
- struct mallinfo minfo = mallinfo();
-
- *ttlMallocHeap = (minfo.arena + minfo.fordblks);
- *freeMallocHeap = minfo.fordblks;
-}
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#include <malloc.h>
+
+void tcalGetHeapInfo(unsigned int *ttlMallocHeap, unsigned int *freeMallocHeap)
+{
+ struct mallinfo minfo = mallinfo();
+
+ *ttlMallocHeap = (minfo.arena + minfo.fordblks);
+ *freeMallocHeap = minfo.fordblks;
+}
diff --git a/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal.h b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal.h
index 046ab971..95275438 100644
--- a/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal.h
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal.h
@@ -1,37 +1,38 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-#ifndef OPENAVB_MEM_TCAL_H
-#define OPENAVB_MEM_TCAL_H 1
-
-void tcalGetHeapInfo(unsigned int *ttlMallocHeap, unsigned int *freeMallocHeap);
-
-#endif // OPENAVB_MEM_TCAL_H
-
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#ifndef OPENAVB_MEM_TCAL_H
+#define OPENAVB_MEM_TCAL_H 1
+
+void tcalGetHeapInfo(unsigned int *ttlMallocHeap, unsigned int *freeMallocHeap);
+
+#endif // OPENAVB_MEM_TCAL_H
+
diff --git a/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal_pub.h b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal_pub.h
index b6d3b239..a0c772bf 100644
--- a/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal_pub.h
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_mem_tcal_pub.h
@@ -1,38 +1,39 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-#ifndef OPENAVB_MEM_TCAL_PUB_H
-#define OPENAVB_MEM_TCAL_PUB_H 1
-
-#include <stdlib.h>
-#include <stdint.h>
-
-#endif // OPENAVB_MEM_TCAL_PUB_H
-
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#ifndef OPENAVB_MEM_TCAL_PUB_H
+#define OPENAVB_MEM_TCAL_PUB_H 1
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#endif // OPENAVB_MEM_TCAL_PUB_H
+
diff --git a/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_tcal_pub.h b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_tcal_pub.h
index f3bb489b..6a1ff93f 100644
--- a/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_tcal_pub.h
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_tcal_pub.h
@@ -1,38 +1,39 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-#ifndef OPENAVB_TCAL_PUB_H
-#define OPENAVB_TCAL_PUB_H 1
-
-// Logging Extra Newline. Some platforms libraries require an extra newline
-static const bool OPENAVB_TCAL_LOG_EXTRA_NEWLINE = TRUE;
-
-#endif // OPENAVB_TCAL_PUB_H
-
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#ifndef OPENAVB_TCAL_PUB_H
+#define OPENAVB_TCAL_PUB_H 1
+
+// Logging Extra Newline. Some platforms libraries require an extra newline
+static const bool OPENAVB_TCAL_LOG_EXTRA_NEWLINE = TRUE;
+
+#endif // OPENAVB_TCAL_PUB_H
+
diff --git a/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_time_tcal_pub.h b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_time_tcal_pub.h
index 4afe007e..acbc1809 100644
--- a/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_time_tcal_pub.h
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_time_tcal_pub.h
@@ -1,49 +1,50 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-#ifndef _OPENAVB_TIME_TCAL_PUB_H
-#define _OPENAVB_TIME_TCAL_PUB_H
-
-#if PROVIDED_BY_PLATFORM
-typedef int clockid_t;
-#endif
-
-#if PROVIDED_BY_PLATFORM
-struct timespec {
- long tv_sec; /* seconds */
- long tv_nsec; /* nanoseconds */
-};
-struct itimerspec {
- struct timespec it_interval; /* timer period */
- struct timespec it_value; /* timer expiration */
-};
-#endif
-
-#endif // _OPENAVB_TIME_TCAL_PUB_H
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#ifndef _OPENAVB_TIME_TCAL_PUB_H
+#define _OPENAVB_TIME_TCAL_PUB_H
+
+#if PROVIDED_BY_PLATFORM
+typedef int clockid_t;
+#endif
+
+#if PROVIDED_BY_PLATFORM
+struct timespec {
+ long tv_sec; /* seconds */
+ long tv_nsec; /* nanoseconds */
+};
+struct itimerspec {
+ struct timespec it_interval; /* timer period */
+ struct timespec it_value; /* timer expiration */
+};
+#endif
+
+#endif // _OPENAVB_TIME_TCAL_PUB_H
diff --git a/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_types_base_tcal_pub.h b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_types_base_tcal_pub.h
index 5f4da71e..ce39caa9 100644
--- a/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_types_base_tcal_pub.h
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_types_base_tcal_pub.h
@@ -1,40 +1,41 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-#ifndef AVB_TYPES_BASE_TCAL_PUB_H
-#define AVB_TYPES_BASE_TCAL_PUB_H 1
-
-#define OPENAVB_PRAGMA(arg) _Pragma(#arg)
-
-#define OPENAVB_CODE_FUNCTION_PRI
-#define OPENAVB_CODE_MODULE_PRI
-#define OPENAVB_DATA_PRI
-
-#endif // AVB_TYPES_BASE_TCAL_PUB_H
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#ifndef AVB_TYPES_BASE_TCAL_PUB_H
+#define AVB_TYPES_BASE_TCAL_PUB_H 1
+
+#define OPENAVB_PRAGMA(arg) _Pragma(#arg)
+
+#define OPENAVB_CODE_FUNCTION_PRI
+#define OPENAVB_CODE_MODULE_PRI
+#define OPENAVB_DATA_PRI
+
+#endif // AVB_TYPES_BASE_TCAL_PUB_H
diff --git a/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_warnings_tcal.h b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_warnings_tcal.h
index 637910a2..99c24c91 100644
--- a/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_warnings_tcal.h
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/openavb_warnings_tcal.h
@@ -1,37 +1,38 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-#ifndef OPENAVB_WARNINGS_TCAL_H
-#define OPENAVB_WARNINGS_TCAL_H 1
-
-#define OPENAVB_SUPPRESS_WARNING_UNREACHABLE_CODE()
-
-#endif // OPENAVB_WARNINGS_TCAL_H
-
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#ifndef OPENAVB_WARNINGS_TCAL_H
+#define OPENAVB_WARNINGS_TCAL_H 1
+
+#define OPENAVB_SUPPRESS_WARNING_UNREACHABLE_CODE()
+
+#endif // OPENAVB_WARNINGS_TCAL_H
+
diff --git a/lib/avtp_pipeline/platform/platTCAL/GNU/rawsock/openavb_rawsock_tcal.h b/lib/avtp_pipeline/platform/platTCAL/GNU/rawsock/openavb_rawsock_tcal.h
index 460cf50e..51200551 100644
--- a/lib/avtp_pipeline/platform/platTCAL/GNU/rawsock/openavb_rawsock_tcal.h
+++ b/lib/avtp_pipeline/platform/platTCAL/GNU/rawsock/openavb_rawsock_tcal.h
@@ -1,59 +1,60 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-#ifndef OPENAVB_RAWSOCK_TCAL_H
-#define OPENAVB_RAWSOCK_TCAL_H 1
-
-
-// Ethernet header
-typedef struct {
- U8 dhost[ETH_ALEN];
- U8 shost[ETH_ALEN];
- uint16_t ethertype;
-}
-__attribute__ ((__packed__)) eth_hdr_t;
-
-// VLAN tag
-typedef struct {
- uint16_t tpip;
- uint16_t bits;
-}
-__attribute__ ((__packed__)) vlan_tag_t;
-
-// Ethernet header w/VLAN tag
-typedef struct {
- U8 dhost[ETH_ALEN];
- U8 shost[ETH_ALEN];
- vlan_tag_t vlan;
- uint16_t ethertype;
-}
-__attribute__ ((__packed__)) eth_vlan_hdr_t;
-
-#endif // OPENAVB_RAWSOCK_TCAL_H
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#ifndef OPENAVB_RAWSOCK_TCAL_H
+#define OPENAVB_RAWSOCK_TCAL_H 1
+
+
+// Ethernet header
+typedef struct {
+ U8 dhost[ETH_ALEN];
+ U8 shost[ETH_ALEN];
+ uint16_t ethertype;
+}
+__attribute__ ((__packed__)) eth_hdr_t;
+
+// VLAN tag
+typedef struct {
+ uint16_t tpip;
+ uint16_t bits;
+}
+__attribute__ ((__packed__)) vlan_tag_t;
+
+// Ethernet header w/VLAN tag
+typedef struct {
+ U8 dhost[ETH_ALEN];
+ U8 shost[ETH_ALEN];
+ vlan_tag_t vlan;
+ uint16_t ethertype;
+}
+__attribute__ ((__packed__)) eth_vlan_hdr_t;
+
+#endif // OPENAVB_RAWSOCK_TCAL_H
diff --git a/lib/avtp_pipeline/platform/x86_i210/mcr/openavb_mcr_hal.c b/lib/avtp_pipeline/platform/x86_i210/mcr/openavb_mcr_hal.c
index 5dee1f6f..13236986 100644
--- a/lib/avtp_pipeline/platform/x86_i210/mcr/openavb_mcr_hal.c
+++ b/lib/avtp_pipeline/platform/x86_i210/mcr/openavb_mcr_hal.c
@@ -1,62 +1,63 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-#define AVB_LOG_COMPONENT "MCR"
-#include "openavb_pub.h"
-#include "openavb_log.h"
-
-#include "openavb_mcr_hal.h"
-
-
-bool halInitMCR(U32 packetRate, U32 pushInterval, U32 timestampInterval, U32 recoveryInterval)
-{
- return TRUE;
-}
-
-bool halCloseMCR(void)
-{
- return TRUE;
-}
-
-bool halPushMCR(void)
-{
- return TRUE;
-}
-
-void halAdjustMCRNSec(S32 adjNSec)
-{
-}
-
-void halAdjustMCRGranularityNSec(U32 adjGranularityNSec)
-{
-}
-
-
-
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#define AVB_LOG_COMPONENT "MCR"
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+#include "openavb_mcr_hal.h"
+
+
+bool halInitMCR(U32 packetRate, U32 pushInterval, U32 timestampInterval, U32 recoveryInterval)
+{
+ return TRUE;
+}
+
+bool halCloseMCR(void)
+{
+ return TRUE;
+}
+
+bool halPushMCR(void)
+{
+ return TRUE;
+}
+
+void halAdjustMCRNSec(S32 adjNSec)
+{
+}
+
+void halAdjustMCRGranularityNSec(U32 adjGranularityNSec)
+{
+}
+
+
+
diff --git a/lib/avtp_pipeline/platform/x86_i210/mcr/openavb_mcr_hal.h b/lib/avtp_pipeline/platform/x86_i210/mcr/openavb_mcr_hal.h
index a458b262..c6db6044 100644
--- a/lib/avtp_pipeline/platform/x86_i210/mcr/openavb_mcr_hal.h
+++ b/lib/avtp_pipeline/platform/x86_i210/mcr/openavb_mcr_hal.h
@@ -1,37 +1,38 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-#ifndef OPENAVB_MCR_HAL_H
-#define OPENAVB_MCR_HAL_H
-
-#include "openavb_platform.h"
-#include "openavb_mcr_hal_pub.h"
-
-#endif // OPENAVB_MCR_HAL_H
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#ifndef OPENAVB_MCR_HAL_H
+#define OPENAVB_MCR_HAL_H
+
+#include "openavb_platform.h"
+#include "openavb_mcr_hal_pub.h"
+
+#endif // OPENAVB_MCR_HAL_H
diff --git a/lib/avtp_pipeline/platform/x86_i210/openavb_hal.h b/lib/avtp_pipeline/platform/x86_i210/openavb_hal.h
index 58d077a0..10114eb4 100644
--- a/lib/avtp_pipeline/platform/x86_i210/openavb_hal.h
+++ b/lib/avtp_pipeline/platform/x86_i210/openavb_hal.h
@@ -1,38 +1,39 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-#ifndef _OPENAVB_HAL_H
-#define _OPENAVB_HAL_H
-
-// Note this remains for backwards compatabilty with older prots. See openavb_mcr_hall_pub.h for newer APIs
-// halPushMCR() API not defined
-#define HAL_PUSH_MCR(mcrTimeStampPtr) FALSE
-
-#endif // _OPENAVB_HAL_H
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#ifndef _OPENAVB_HAL_H
+#define _OPENAVB_HAL_H
+
+// Note this remains for backwards compatabilty with older prots. See openavb_mcr_hall_pub.h for newer APIs
+// halPushMCR() API not defined
+#define HAL_PUSH_MCR(mcrTimeStampPtr) FALSE
+
+#endif // _OPENAVB_HAL_H
diff --git a/lib/avtp_pipeline/platform/x86_i210/openavb_ether_hal.c b/lib/avtp_pipeline/platform/x86_i210/openavb_igb.c
index fd57e263..f5c1acf0 100644
--- a/lib/avtp_pipeline/platform/x86_i210/openavb_ether_hal.c
+++ b/lib/avtp_pipeline/platform/x86_i210/openavb_igb.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -28,9 +29,9 @@ Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
-#include "openavb_ether_hal.h"
+#include "openavb_igb.h"
#include "openavb_osal.h"
-#include "avb.h"
+#include "avb_igb.h"
#include "igb.h"
#define AVB_LOG_COMPONENT "HAL Ethernet"
@@ -107,7 +108,7 @@ device_t *igbAcquireDevice()
LOCK();
if (!igb_dev) {
- device_t *tmp_dev = malloc(sizeof(device_t));
+ device_t *tmp_dev = calloc(1, sizeof(device_t));
if (!tmp_dev) {
AVB_LOGF_ERROR("Cannot allocate memory for device: %s", strerror(errno));
goto unlock;
diff --git a/lib/avtp_pipeline/platform/x86_i210/openavb_ether_hal.h b/lib/avtp_pipeline/platform/x86_i210/openavb_igb.h
index 2ccc9db8..2f160774 100644
--- a/lib/avtp_pipeline/platform/x86_i210/openavb_ether_hal.h
+++ b/lib/avtp_pipeline/platform/x86_i210/openavb_igb.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -28,8 +29,8 @@ Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
-#ifndef HAL_ETHER_H
-#define HAL_ETHER_H 1
+#ifndef OPENAVB_IGB_H
+#define OPENAVB_IGB_H 1
#include "openavb_platform.h"
#include "openavb_types_base.h"
@@ -41,8 +42,6 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
// how many pages to alloc for tx buffers (2 frames fit in one page)
#define IGB_PAGES 20
-#define IGB_LAUNCHTIME_ENABLED 0
-
device_t *igbAcquireDevice();
void igbReleaseDevice(device_t *igb_dev);
@@ -57,4 +56,4 @@ bool igbGetMacAddr(U8 mac_addr[ETH_ALEN]);
bool igbControlLaunchTime(device_t *dev, int enable);
-#endif // HAL_ETHER_H
+#endif // OPENAVB_IGB_H
diff --git a/lib/avtp_pipeline/qmgr/openavb_qmgr.c b/lib/avtp_pipeline/qmgr/openavb_qmgr.c
index 1dbd1db8..d3a9b84a 100644
--- a/lib/avtp_pipeline/qmgr/openavb_qmgr.c
+++ b/lib/avtp_pipeline/qmgr/openavb_qmgr.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -33,7 +34,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*/
#include <openavb_types.h>
-#include "openavb_ether_hal.h"
+
#define AVB_LOG_COMPONENT "QMGR"
//#define AVB_LOG_LEVEL AVB_LOG_LEVEL_DEBUG
#include "openavb_log.h"
@@ -41,7 +42,10 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_qmgr.h"
#include "avb_sched.h"
-#include "openavb_ether_hal.h"
+
+#if (AVB_FEATURE_IGB)
+#include "openavb_igb.h"
+#endif
#define AVB_DEFAULT_QDISC_MODE AVB_SHAPER_HWQ_PER_CLASS
@@ -49,17 +53,24 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
// Qdisc configuration
typedef struct {
+#if (AVB_FEATURE_IGB)
device_t *igb_dev;
+#endif
int mode;
int ifindex;
- char ifname[IFNAMSIZ];
+ char ifname[IFNAMSIZ + 10]; // Include space for the socket type prefix (e.g. "simple:eth0")
U32 linkKbit;
U32 nsrKbit;
U32 linkMTU;
int ref;
} qdisc_data_t;
-static qdisc_data_t qdisc_data;
+static qdisc_data_t qdisc_data = {
+#if (AVB_FEATURE_IGB)
+ NULL,
+#endif
+ 0, 0, {0}, 0, 0, 0, 0
+};
// We do get accessed from multiple threads, so need a mutex
pthread_mutex_t qmgr_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
@@ -92,21 +103,24 @@ static qmgrStream_t qmgr_streams[MAX_AVB_STREAMS];
static bool setupHWQueue(int nClass, unsigned classBytesPerSec)
{
int err = 0;
+#if (AVB_FEATURE_IGB)
U32 class_a_bytes_per_sec, class_b_bytes_per_sec;
+#endif
AVB_TRACE_ENTRY(AVB_TRACE_QUEUE_MANAGER);
+#if (AVB_FEATURE_IGB)
if (nClass == SR_CLASS_A) {
class_a_bytes_per_sec = classBytesPerSec;
- class_b_bytes_per_sec = qmgr_classes[SR_CLASS_B].classBytesPerSec;
+ class_b_bytes_per_sec = qmgr_classes[SR_CLASS_B].classBytesPerSec;
} else {
- class_a_bytes_per_sec = qmgr_classes[SR_CLASS_A].classBytesPerSec;
+ class_a_bytes_per_sec = qmgr_classes[SR_CLASS_A].classBytesPerSec;
class_b_bytes_per_sec = classBytesPerSec;
}
-
err = igb_set_class_bandwidth2(qdisc_data.igb_dev, class_a_bytes_per_sec, class_b_bytes_per_sec);
if (err)
AVB_LOGF_ERROR("Adding stream; igb_set_class_bandwidth failed: %s", strerror(err));
+#endif
AVB_TRACE_EXIT(AVB_TRACE_QUEUE_MANAGER);
return !err;
@@ -122,7 +136,7 @@ static bool setupHWQueue(int nClass, unsigned classBytesPerSec)
*/
U16 openavbQmgrAddStream(SRClassIdx_t nClass, unsigned classRate, unsigned maxIntervalFrames, unsigned maxFrameSize)
{
- unsigned fullFrameSize = maxFrameSize + OPENAVB_AVTP_ETHER_FRAME_OVERHEAD;
+ unsigned fullFrameSize = maxFrameSize + OPENAVB_AVTP_ETHER_FRAME_OVERHEAD + 1;
unsigned long streamBytesPerSec = fullFrameSize * maxIntervalFrames * classRate;
int idx, nStream;
U16 fwmark = INVALID_FWMARK;
@@ -208,7 +222,7 @@ void openavbQmgrRemoveStream(U16 fwmark)
// update class
qmgr_classes[nClass].classBytesPerSec -= qmgr_streams[idx].streamBytesPerSec;
- AVB_LOGF_DEBUG("Removed strea; classBPS=%u, streamBPS=%u", qmgr_classes[nClass].classBytesPerSec, qmgr_streams[idx].streamBytesPerSec);
+ AVB_LOGF_DEBUG("Removed stream; classBPS=%u, streamBPS=%u", qmgr_classes[nClass].classBytesPerSec, qmgr_streams[idx].streamBytesPerSec);
// and stream
memset(&qmgr_streams[idx], 0, sizeof(qmgrStream_t));
}
@@ -246,12 +260,14 @@ bool openavbQmgrInitialize(int mode, int ifindex, const char* ifname, unsigned m
AVB_LOGF_DEBUG("Initializing QMgr; mode=%d, idx=%d, mtu=%u, link_kbit=%u, nsr_kbit=%u",
qdisc_data.mode, ifindex, mtu, link_kbit, nsr_kbit);
+#if (AVB_FEATURE_IGB)
if ( qdisc_data.mode != AVB_SHAPER_DISABLED
&& (qdisc_data.igb_dev = igbAcquireDevice()) == 0)
{
AVB_LOG_ERROR("Initializing QMgr; unable to acquire igb device");
}
else
+#endif
{
// Initialize data for classes and streams
memset(qmgr_classes, 0, sizeof(qmgr_classes));
@@ -294,8 +310,11 @@ void openavbQmgrFinalize(void)
}
}
}
+
+#if (AVB_FEATURE_IGB)
igbReleaseDevice(qdisc_data.igb_dev);
qdisc_data.igb_dev = NULL;
+#endif
}
UNLOCK();
diff --git a/lib/avtp_pipeline/qmgr/openavb_qmgr.h b/lib/avtp_pipeline/qmgr/openavb_qmgr.h
index 8e67257d..0a225d47 100644
--- a/lib/avtp_pipeline/qmgr/openavb_qmgr.h
+++ b/lib/avtp_pipeline/qmgr/openavb_qmgr.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/rawsock/CMakeLists.txt b/lib/avtp_pipeline/rawsock/CMakeLists.txt
index 39c5c63c..e3e0f49e 100644
--- a/lib/avtp_pipeline/rawsock/CMakeLists.txt
+++ b/lib/avtp_pipeline/rawsock/CMakeLists.txt
@@ -1,4 +1,23 @@
+if (AVB_FEATURE_PCAP)
+ message("-- Rawsock PCAP enabled")
+ SET (PCAP_FILES
+ ${AVB_OSAL_DIR}/rawsock/pcap_rawsock.c
+ )
+ if (AVB_FEATURE_IGB)
+ message("-- Rawsock IGB enabled")
+ SET (IGB_FILES
+ ${AVB_OSAL_DIR}/rawsock/igb_rawsock.c
+ ${AVB_HAL_DIR}/openavb_igb.c
+ )
+ endif ()
+endif ()
SET (SRC_FILES ${SRC_FILES}
${AVB_SRC_DIR}/rawsock/rawsock_impl.c
+ ${AVB_OSAL_DIR}/rawsock/openavb_rawsock.c
+ ${AVB_OSAL_DIR}/rawsock/simple_rawsock.c
+ ${AVB_OSAL_DIR}/rawsock/ring_rawsock.c
+ ${AVB_OSAL_DIR}/rawsock/sendmmsg_rawsock.c
+ ${PCAP_FILES}
+ ${IGB_FILES}
PARENT_SCOPE
)
diff --git a/lib/avtp_pipeline/rawsock/openavb_rawsock.h b/lib/avtp_pipeline/rawsock/openavb_rawsock.h
index 04671450..11eb2b69 100644
--- a/lib/avtp_pipeline/rawsock/openavb_rawsock.h
+++ b/lib/avtp_pipeline/rawsock/openavb_rawsock.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -61,6 +62,7 @@ typedef struct {
bool vlan; // Include VLAN header?
U8 vlan_pcp; // VLAN Priority Code Point
U16 vlan_vid; // VLAN ID
+ struct timespec ts; // RX timestamp
} hdr_info_t;
@@ -143,7 +145,8 @@ bool openavbRawsockRelTxFrame(void *rawsock, U8 *pBuffer);
// Submit a frame and mark it "ready to send"
bool openavbRawsockTxFrameReady(void *rawsock, // rawsock handle
U8 *pFrame, // pointer to frame buffer
- U32 len); // length of frame to send
+ U32 len, // length of frame to send
+ U64 timeNsec); // launch time (in gPTP wall clock)
// Send all packets that are marked "ready to send".
// Returns count of bytes in sent frames - or < 0 for error.
diff --git a/lib/avtp_pipeline/rawsock/rawsock_impl.c b/lib/avtp_pipeline/rawsock/rawsock_impl.c
index c351f47c..8e4756be 100644
--- a/lib/avtp_pipeline/rawsock/rawsock_impl.c
+++ b/lib/avtp_pipeline/rawsock/rawsock_impl.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -35,16 +36,16 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_log.h"
void baseRawsockSetRxSignalMode(void *rawsock, bool rxSignalMode) {}
-int baseRawsockGetSocket(void *rawsock) { return -1; }
-U8 *baseRawsockGetRxFrame(void *rawsock, U32 usecTimeout, U32 *offset, U32 *len) { return NULL; }
+int baseRawsockGetSocket(void *rawsock) { AVB_LOG_ERROR("baseRawsockGetSocket called"); return -1; }
+U8 *baseRawsockGetRxFrame(void *rawsock, U32 usecTimeout, U32 *offset, U32 *len) { AVB_LOG_ERROR("baseRawsockGetRxFrame called"); return NULL; }
bool baseRawsockRelRxFrame(void *rawsock, U8 *pFrame) { return false; }
bool baseRawsockRxMulticast(void *rawsock, bool add_membership, const U8 buf[]) { return false; }
bool baseRawsockRxAVTPSubtype(void *rawsock, U8 subtype) { return false; }
bool baseRawsockTxSetMark(void *rawsock, int prio) { return false; }
-U8 *baseRawsockGetTxFrame(void *rawsock, bool blocking, U32 *size) { return NULL; }
+U8 *baseRawsockGetTxFrame(void *rawsock, bool blocking, U32 *size) { AVB_LOG_ERROR("baseRawsockGetTxFrame called"); return NULL; }
bool baseRawsockRelTxFrame(void *rawsock, U8 *pBuffer) { return false; }
-bool baseRawsockTxFrameReady(void *rawsock, U8 *pFrame, U32 len) { return false; }
-int baseRawsockSend(void *rawsock) { return -1; }
+bool baseRawsockTxFrameReady(void *rawsock, U8 *pFrame, U32 len, U64 timeNsec) { AVB_LOG_ERROR("baseRawsockTxFrameReady called"); return false; }
+int baseRawsockSend(void *rawsock) { AVB_LOG_ERROR("baseRawsockSend called"); return -1; }
int baseRawsockTxBufLevel(void *rawsock) { return -1; }
int baseRawsockRxBufLevel(void *rawsock) { return -1; }
unsigned long baseRawsockGetTXOutOfBuffers(void *pvRawsock) { return 0; }
@@ -186,16 +187,24 @@ int baseRawsockRxParseHdr(void *pvRawsock, U8 *pBuffer, hdr_info_t *pInfo)
{
AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
+ memset(pInfo, 0, sizeof(hdr_info_t));
+
eth_hdr_t *eth_hdr = (eth_hdr_t*)pBuffer;
pInfo->dhost = eth_hdr->dhost;
pInfo->shost = eth_hdr->shost;
pInfo->ethertype = ntohs(eth_hdr->ethertype);
+ pInfo->ts.tv_sec = 0;
+ pInfo->ts.tv_nsec = 0;
int hdrLen = sizeof(eth_hdr_t);
if (pInfo->ethertype == ETHERTYPE_8021Q) {
+ U16 vlan_bits = ntohs(*(U16*)(pBuffer + hdrLen));
pInfo->vlan = TRUE;
- // TODO extract vlan_vid and vlan_pcp
- hdrLen += 4;
+ pInfo->vlan_vid = vlan_bits & 0x0FFF;
+ pInfo->vlan_pcp = (vlan_bits >> 13) & 0x0007;
+ hdrLen += 2;
+ pInfo->ethertype = ntohs(*(U16 *)(pBuffer + hdrLen));
+ hdrLen += 2;
}
AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
@@ -273,11 +282,11 @@ bool openavbRawsockRelTxFrame(void *pvRawsock, U8 *pBuffer)
return ret;
}
-bool openavbRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len)
+bool openavbRawsockTxFrameReady(void *pvRawsock, U8 *pBuffer, unsigned int len, U64 timeNsec)
{
AVB_TRACE_ENTRY(AVB_TRACE_RAWSOCK_DETAIL);
- bool ret = ((base_rawsock_t*)pvRawsock)->cb.txFrameReady(pvRawsock, pBuffer, len);
+ bool ret = ((base_rawsock_t*)pvRawsock)->cb.txFrameReady(pvRawsock, pBuffer, len, timeNsec);
AVB_TRACE_EXIT(AVB_TRACE_RAWSOCK_DETAIL);
return ret;
diff --git a/lib/avtp_pipeline/rawsock/rawsock_impl.h b/lib/avtp_pipeline/rawsock/rawsock_impl.h
index b1d6cf7b..050f32ab 100644
--- a/lib/avtp_pipeline/rawsock/rawsock_impl.h
+++ b/lib/avtp_pipeline/rawsock/rawsock_impl.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -75,7 +76,7 @@ typedef struct {
bool (*txSetMark)(void* rawsock, int prio);
U8* (*getTxFrame)(void* rawsock, bool blocking, U32* size);
bool (*relTxFrame)(void* rawsock, U8* pBuffer);
- bool (*txFrameReady)(void* rawsock, U8* pFrame, U32 len);
+ bool (*txFrameReady)(void* rawsock, U8* pFrame, U32 len, U64 timeNsec);
int (*send)(void* rawsock);
int (*txBufLevel)(void* rawsock);
int (*rxBufLevel)(void* rawsock);
diff --git a/lib/avtp_pipeline/shaper/openavb_shaper.h b/lib/avtp_pipeline/shaper/openavb_shaper.h
new file mode 100644
index 00000000..2639aab0
--- /dev/null
+++ b/lib/avtp_pipeline/shaper/openavb_shaper.h
@@ -0,0 +1,49 @@
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#ifndef OPENAVB_SHAPER_H
+#define OPENAVB_SHAPER_H 1
+#include "openavb_types.h"
+
+// Shaper library lifecycle
+bool openavbShaperInitialize(const char *ifname, unsigned int shaperPort);
+void openavbShaperFinalize();
+
+bool openavbShaperDaemonAvailable(void);
+
+// Tell the Shaper to shape outgoing packets.
+// Use the returned value for the call to openavbShapingRelease().
+void* openavbShaperHandle(SRClassIdx_t sr_class, int measurement_interval_usec, int max_frame_size_bytes, int max_frames_per_interval, const unsigned char * stream_da);
+
+// Have the Shaper stop shaping outgoing packets.
+void openavbShaperRelease(void* handle);
+
+#endif // OPENAVB_SHAPER_H
diff --git a/lib/avtp_pipeline/srp/openavb_srp.h b/lib/avtp_pipeline/srp/openavb_srp.h
index e5d1471f..c0d05e93 100755
--- a/lib/avtp_pipeline/srp/openavb_srp.h
+++ b/lib/avtp_pipeline/srp/openavb_srp.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -33,7 +34,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*
* Implementation of IEEE 802.1Q
* Multiple Stream Reservation Protocol
-* (limited intial implementation for end stations)
+* (limited initial implementation for end stations)
*
* This file declares the "Private" portion - see also openavb_srp_api.h
*/
@@ -132,8 +133,8 @@ typedef struct SrClassParameters {
} SrClassParameters_t;
// Applicant State - IEEE 802.1Q Table 10-3
-// State here are simplified becasue:
-// - we are suppporting point-to-point only and
+// State here are simplified because:
+// - we are supporting point-to-point only and
// - initial declaration sends are immediate so there is no need for VP and VN
typedef enum openavbSrpAppState {
openavbSrp_ApSt_VO = 0x00, // no declarations - note that we initialize to 0
@@ -154,7 +155,7 @@ typedef enum openavbSrpRegState {
// Element for linked list of declared / registered streams.
// Since both a talker and a listener can exist for the same stream on the same
-// end-station, seperate talker and listener lists are kept.
+// end-station, separate talker and listener lists are kept.
// IMPORTANT NOTE: This implementation assumes that on a given end-station, no
// more than one talker and no more than one listener exist for each stream; if
// this is not the case, individual stream list elements could be corrupted
@@ -170,7 +171,7 @@ typedef enum openavbSrpRegState {
// - avtpHandle, streamId, DA, tSpec, SRClassId, Rank, and Latency
// are as received from AVTP via openavbSrpRegisterStream();
// - failInfo is populated only if this station has insufficient outbound
-// bandwidth for this stream, so must send Talker Failed delcaration;
+// bandwidth for this stream, so must send Talker Failed declaration;
// - kbpsReserved is the bandwidth currently reserved for the stream.
//
// On Listener:
@@ -184,9 +185,9 @@ typedef enum openavbSrpRegState {
// received for the stream, if anything; (openavbSrp_AtTyp_None indicates that
// the listener currently has no talker declaration for the stream);
// - regSubType is not used;
-// - avtpHandle is as recieved from AVTP via openavbSrpAttachStream();
-// - strmId is either as recieved from AVTP via openavbSrpAttachStream() or
-// as recieved via a talker declaration packet (MSRPDU), whichever occurs first;
+// - avtpHandle is as received from AVTP via openavbSrpAttachStream();
+// - strmId is either as received from AVTP via openavbSrpAttachStream() or
+// as received via a talker declaration packet (MSRPDU), whichever occurs first;
// - SRClassIdx is derived from priority received in talker declaration packet;
// - DA, tSpec, latency, and, if applicable, failInfo are
// as received in talker declaration packet
@@ -202,8 +203,8 @@ typedef struct openavbSrpStrm {
// (declType == openavbSrp_AtTyp_None is redundant to appState == openavbSrp_ApSt_VO).
openavbSrpLsnrDeclSubtype_t declSubType; // listener subtype this station is declaring for this stream, if any;
// not used on talker; valid only if declType == openavbSrp_AtTyp_Listener.
- openavbSrpAttribType_t regType; // attribute type this station has recieved (registered) for this stream, if any;
- openavbSrpLsnrDeclSubtype_t regSubType; // listener subtype this station has recieved (registered) for this stream, if any;
+ openavbSrpAttribType_t regType; // attribute type this station has received (registered) for this stream, if any;
+ openavbSrpLsnrDeclSubtype_t regSubType; // listener subtype this station has received (registered) for this stream, if any;
// not used on listener; valid only if regType == openavbSrp_AtTyp_Listener.
U8 DA[ETH_MAC_ADDR_LEN];
AVBTSpec_t tSpec;
diff --git a/lib/avtp_pipeline/srp/openavb_srp_api.h b/lib/avtp_pipeline/srp/openavb_srp_api.h
index 4c13b637..3f1d9bba 100755
--- a/lib/avtp_pipeline/srp/openavb_srp_api.h
+++ b/lib/avtp_pipeline/srp/openavb_srp_api.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -33,7 +34,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*
* Implementation of IEEE 802.1Q
* Multiple Stream Reservation Protocol
-* (limited intial implementation for end stations)
+* (limited initial implementation for end stations)
*
* This file declares the "Public" API.
*
@@ -48,7 +49,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_types.h"
// TBD - If queue manager can fail to configure a queue for a granted reservation, SRP
-// needs to know about the failure in order to correct reseved bandwidth totals.
+// needs to know about the failure in order to correct reserved bandwidth totals.
// (we are probably toast if queue manager fails when removing a stream)
// TBD - This implementation handles bandwidth in kilobits per second
@@ -82,7 +83,7 @@ enum openavbSrpFailureCode {
openavbSrp_FC_NoClassBandwidth = 3, // Insufficient bandwidth for Traffic Class,
// 4: StreamID in use by another Talker,
// 5: Stream destination address already in use,
- // 6: Stream pre-empted by higher rank,
+ // 6: Stream preempted by higher rank,
// 7: Reported latency has changed,
openavbSrp_FC_NotCapable = 8, // Egress port is not AVBCapable,
// 9: Use a different destination_address,
diff --git a/lib/avtp_pipeline/tl/CMakeLists.txt b/lib/avtp_pipeline/tl/CMakeLists.txt
index 7c8a19d7..d3622cc9 100644
--- a/lib/avtp_pipeline/tl/CMakeLists.txt
+++ b/lib/avtp_pipeline/tl/CMakeLists.txt
@@ -3,6 +3,7 @@ SET (SRC_FILES_TL
${AVB_OSAL_DIR}/tl/openavb_tl_osal.c
${AVB_SRC_DIR}/tl/openavb_listener.c
${AVB_SRC_DIR}/tl/openavb_talker.c
+ ${AVB_SRC_DIR}/avdecc_msg/openavb_avdecc_msg_client.c
)
if(AVB_FEATURE_ENDPOINT)
@@ -13,6 +14,7 @@ if(AVB_FEATURE_ENDPOINT)
${AVB_SRC_DIR}/tl/openavb_tl_endpoint.c
${AVB_SRC_DIR}/tl/openavb_talker_endpoint.c
${AVB_SRC_DIR}/tl/openavb_listener_endpoint.c
+ ${AVB_OSAL_DIR}/openavb_osal_endpoint.c
)
else()
#Additional Files for No Endpoint
@@ -21,6 +23,7 @@ else()
${AVB_SRC_DIR}/tl/openavb_tl_no_endpoint.c
${AVB_SRC_DIR}/tl/openavb_talker_no_endpoint.c
${AVB_SRC_DIR}/tl/openavb_listener_no_endpoint.c
+ ${AVB_OSAL_DIR}/openavb_osal.c
)
endif()
diff --git a/lib/avtp_pipeline/tl/openavb_listener.c b/lib/avtp_pipeline/tl/openavb_listener.c
index 18333848..53cb3b2e 100644
--- a/lib/avtp_pipeline/tl/openavb_listener.c
+++ b/lib/avtp_pipeline/tl/openavb_listener.c
@@ -1,16 +1,17 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
+
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -21,10 +22,10 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -40,6 +41,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_tl.h"
#include "openavb_avtp.h"
#include "openavb_listener.h"
+#include "openavb_avdecc_msg_client.h"
// DEBUG Uncomment to turn on logging for just this module.
//#define AVB_LOG_ON 1
@@ -83,6 +85,7 @@ bool listenerStartStream(tl_state_t *pTLState)
U64 nowNS;
CLOCK_GETTIME64(OPENAVB_TIMER_CLOCK, &nowNS);
pListenerData->nextReportNS = nowNS + (pCfg->report_seconds * NANOSECONDS_PER_SECOND);
+ pListenerData->lastReportFrames = 0;
pListenerData->nextSecondNS = nowNS + NANOSECONDS_PER_SECOND;
// Clear counters
@@ -121,7 +124,7 @@ void listenerStopStream(tl_state_t *pTLState)
openavbListenerAddStat(pTLState, TL_STAT_RX_LOST, openavbAvtpLost(pListenerData->avtpHandle));
openavbListenerAddStat(pTLState, TL_STAT_RX_BYTES, openavbAvtpBytes(pListenerData->avtpHandle));
- AVB_LOGF_INFO("RX "STREAMID_FORMAT", Totals: calls=%" PRIu64 "frames=%" PRIu64 "lost=%" PRIu64 "bytes=%" PRIu64,
+ AVB_LOGF_INFO("RX "STREAMID_FORMAT", Totals: calls=%" PRIu64 ", frames=%" PRIu64 ", lost=%" PRIu64 ", bytes=%" PRIu64,
STREAMID_ARGS(&pListenerData->streamID),
openavbListenerGetStat(pTLState, TL_STAT_RX_CALLS),
openavbListenerGetStat(pTLState, TL_STAT_RX_FRAMES),
@@ -129,13 +132,34 @@ void listenerStopStream(tl_state_t *pTLState)
openavbListenerGetStat(pTLState, TL_STAT_RX_BYTES));
if (pTLState->bStreaming) {
- openavbAvtpShutdown(pListenerData->avtpHandle);
+ openavbAvtpShutdownListener(pListenerData->avtpHandle);
pTLState->bStreaming = FALSE;
}
AVB_TRACE_EXIT(AVB_TRACE_TL);
}
+static inline void listenerShowStats(listener_data_t *pListenerData, tl_state_t *pTLState)
+{
+ U64 lost = openavbAvtpLost(pListenerData->avtpHandle);
+ U64 bytes = openavbAvtpBytes(pListenerData->avtpHandle);
+ U32 rxbuf = openavbAvtpRxBufferLevel(pListenerData->avtpHandle);
+ U32 mqbuf = openavbMediaQCountItems(pTLState->pMediaQ, TRUE);
+ U32 mqrdy = openavbMediaQCountItems(pTLState->pMediaQ, FALSE);
+
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "RX UID:%d, ", LOG_RT_DATATYPE_U16, &pListenerData->streamID.uniqueID);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "calls=%ld, ", LOG_RT_DATATYPE_U32, &pListenerData->nReportCalls);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "frames=%ld, ", LOG_RT_DATATYPE_U32, &pListenerData->nReportFrames);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "lost=%lld, ", LOG_RT_DATATYPE_U64, &lost);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "bytes=%lld, ", LOG_RT_DATATYPE_U64, &bytes);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "rxbuf=%d, ", LOG_RT_DATATYPE_U32, &rxbuf);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "mqbuf=%d, ", LOG_RT_DATATYPE_U32, &mqbuf);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "mqrdy=%d", LOG_RT_DATATYPE_U32, &mqrdy);
+
+ openavbListenerAddStat(pTLState, TL_STAT_RX_LOST, lost);
+ openavbListenerAddStat(pTLState, TL_STAT_RX_BYTES, bytes);
+}
+
static inline bool listenerDoStream(tl_state_t *pTLState)
{
AVB_TRACE_ENTRY(AVB_TRACE_TL);
@@ -164,30 +188,19 @@ static inline bool listenerDoStream(tl_state_t *pTLState)
if (pCfg->report_seconds > 0) {
if (nowNS > pListenerData->nextReportNS) {
-
- U64 lost = openavbAvtpLost(pListenerData->avtpHandle);
- U64 bytes = openavbAvtpBytes(pListenerData->avtpHandle);
- U32 rxbuf = openavbAvtpRxBufferLevel(pListenerData->avtpHandle);
- U32 mqbuf = openavbMediaQCountItems(pTLState->pMediaQ, TRUE);
- U32 mqrdy = openavbMediaQCountItems(pTLState->pMediaQ, FALSE);
-
- AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "RX UID:%d, ", LOG_RT_DATATYPE_U16, &pListenerData->streamID.uniqueID);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "calls=%ld, ", LOG_RT_DATATYPE_U32, &pListenerData->nReportCalls);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "frames=%ld, ", LOG_RT_DATATYPE_U32, &pListenerData->nReportFrames);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "lost=%lld, ", LOG_RT_DATATYPE_U64, &lost);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "bytes=%lld, ", LOG_RT_DATATYPE_U64, &bytes);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "rxbuf=%d, ", LOG_RT_DATATYPE_U32, &rxbuf);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "mqbuf=%d, ", LOG_RT_DATATYPE_U32, &mqbuf);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "mqrdy=%d", LOG_RT_DATATYPE_U32, &mqrdy);
+ listenerShowStats(pListenerData, pTLState);
openavbListenerAddStat(pTLState, TL_STAT_RX_CALLS, pListenerData->nReportCalls);
openavbListenerAddStat(pTLState, TL_STAT_RX_FRAMES, pListenerData->nReportFrames);
- openavbListenerAddStat(pTLState, TL_STAT_RX_LOST, lost);
- openavbListenerAddStat(pTLState, TL_STAT_RX_BYTES, bytes);
pListenerData->nReportCalls = 0;
pListenerData->nReportFrames = 0;
- pListenerData->nextReportNS += (pCfg->report_seconds * NANOSECONDS_PER_SECOND);
+ pListenerData->nextReportNS += (pCfg->report_seconds * NANOSECONDS_PER_SECOND);
+ }
+ } else if (pCfg->report_frames > 0 && pListenerData->nReportFrames != pListenerData->lastReportFrames) {
+ if (pListenerData->nReportFrames % pCfg->report_frames == 1) {
+ listenerShowStats(pListenerData, pTLState);
+ pListenerData->lastReportFrames = pListenerData->nReportFrames;
}
}
@@ -197,15 +210,15 @@ static inline bool listenerDoStream(tl_state_t *pTLState)
}
}
else {
- SLEEP(1);
- bRet = TRUE;
+ SLEEP_MSEC(1);
+ bRet = TRUE;
}
AVB_TRACE_EXIT(AVB_TRACE_TL);
return bRet;
}
-// Called from openavbTLThreadFn() which is started from openavbTLRun()
+// Called from openavbTLThreadFn() which is started from openavbTLRun()
void openavbTLRunListener(tl_state_t *pTLState)
{
AVB_TRACE_ENTRY(AVB_TRACE_TL);
@@ -225,6 +238,7 @@ void openavbTLRunListener(tl_state_t *pTLState)
}
AVBStreamID_t streamID;
+ memset(&streamID, 0, sizeof(streamID));
memcpy(streamID.addr, pCfg->stream_addr.mac, ETH_ALEN);
streamID.uniqueID = pCfg->stream_uid;
@@ -244,11 +258,14 @@ void openavbTLRunListener(tl_state_t *pTLState)
// Tell endpoint to listen for our stream.
// If there is a talker, we'll get callback (above.)
pTLState->bConnected = openavbTLRunListenerInit(pTLState->endpointHandle, &streamID);
-
+
if (pTLState->bConnected) {
bool bServiceIPC;
- // Do until we are stopped or loose connection to endpoint
+ // Notify AVDECC Msg of the state change.
+ openavbAvdeccMsgClntNotifyCurrentState(pTLState);
+
+ // Do until we are stopped or lose connection to endpoint
while (pTLState->bRunning && pTLState->bConnected) {
// Listen for an RX frame (or just sleep if not streaming)
@@ -276,6 +293,9 @@ void openavbTLRunListener(tl_state_t *pTLState)
// withdraw our listener attach
if (pTLState->bConnected)
openavbEptClntStopStream(pTLState->endpointHandle, &streamID);
+
+ // Notify AVDECC Msg of the state change.
+ openavbAvdeccMsgClntNotifyCurrentState(pTLState);
}
else {
AVB_LOGF_WARNING("Failed to connect to endpoint "STREAMID_FORMAT, STREAMID_ARGS(&streamID));
@@ -306,8 +326,12 @@ void openavbTLPauseListener(tl_state_t *pTLState, bool bPause)
return;
}
+ pTLState->bPaused = bPause;
openavbAvtpPause(pListenerData->avtpHandle, bPause);
+ // Notify AVDECC Msg of the state change.
+ openavbAvdeccMsgClntNotifyCurrentState(pTLState);
+
AVB_TRACE_EXIT(AVB_TRACE_TL);
}
diff --git a/lib/avtp_pipeline/tl/openavb_listener.h b/lib/avtp_pipeline/tl/openavb_listener.h
index f802d8cb..bbbeb806 100644
--- a/lib/avtp_pipeline/tl/openavb_listener.h
+++ b/lib/avtp_pipeline/tl/openavb_listener.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -46,7 +47,7 @@ typedef struct {
typedef struct {
// Data from callback
- char ifname[IFNAMSIZ];
+ char ifname[IFNAMSIZ + 10]; // Include space for the socket type prefix (e.g. "simple:eth0")
AVBStreamID_t streamID;
U8 destAddr[ETH_ALEN];
AVBTSpec_t tSpec;
@@ -58,6 +59,7 @@ typedef struct {
unsigned long nReportCalls;
U64 nextReportNS;
U64 nextSecondNS;
+ unsigned long lastReportFrames;
listener_stats_t stats;
} listener_data_t;
diff --git a/lib/avtp_pipeline/tl/openavb_listener_endpoint.c b/lib/avtp_pipeline/tl/openavb_listener_endpoint.c
index b1d4446e..95c2b215 100644
--- a/lib/avtp_pipeline/tl/openavb_listener_endpoint.c
+++ b/lib/avtp_pipeline/tl/openavb_listener_endpoint.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -41,6 +42,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_endpoint.h"
#include "openavb_avtp.h"
#include "openavb_listener.h"
+#include "openavb_avdecc_msg.h"
// DEBUG Uncomment to turn on logging for just this module.
//#define AVB_LOG_ON 1
@@ -73,6 +75,12 @@ void openavbEptClntNotifyLstnrOfSrpCb(int endpointHandle,
return;
}
+ // If not a listener, ignore this callback.
+ if (pTLState->cfg.role != AVB_ROLE_LISTENER) {
+ AVB_LOG_DEBUG("Ignoring Listener callback");
+ return;
+ }
+
AVB_LOGF_DEBUG("%s streaming=%d, tlkrDecl=%d", __FUNCTION__, pTLState->bStreaming, tlkrDecl);
if (!pTLState->bStreaming
@@ -82,7 +90,11 @@ void openavbEptClntNotifyLstnrOfSrpCb(int endpointHandle,
bool rc = openavbEptClntAttachStream(pTLState->endpointHandle, streamID, openavbSrp_LDSt_Ready);
if (rc) {
// Save data provided by endpoint/SRP
- strncpy(pListenerData->ifname, ifname, IFNAMSIZ);
+ if (!pCfg->ifname[0]) {
+ strncpy(pListenerData->ifname, ifname, IFNAMSIZ);
+ } else {
+ strncpy(pListenerData->ifname, pCfg->ifname, IFNAMSIZ);
+ }
memcpy(&pListenerData->streamID, streamID, sizeof(AVBStreamID_t));
if (memcmp(destAddr, emptyMAC, ETH_ALEN) != 0) {
memcpy(&pListenerData->destAddr, destAddr, ETH_ALEN);
@@ -97,10 +109,8 @@ void openavbEptClntNotifyLstnrOfSrpCb(int endpointHandle,
}
else {
memcpy(&pListenerData->destAddr, &pCfg->dest_addr.mac->ether_addr_octet, ETH_ALEN);
- AVB_LOGF_INFO(" Listener configured dest_addr is %02x:%02x:%02x:%02x:%02x:%02x",
- pListenerData->destAddr[0], pListenerData->destAddr[1],
- pListenerData->destAddr[2], pListenerData->destAddr[3],
- pListenerData->destAddr[4], pListenerData->destAddr[5]);
+ AVB_LOGF_INFO(" Listener configured dest_addr is " ETH_FORMAT,
+ ETH_OCTETS(pListenerData->destAddr));
}
if ((!pCfg->max_interval_frames) || (!pCfg->max_frame_size)) {
AVB_LOG_ERROR(" Configuration Error - both max_interval_frames and max_frame_size required in listener config file");
@@ -128,6 +138,11 @@ void openavbEptClntNotifyLstnrOfSrpCb(int endpointHandle,
// We're still interested in the stream
openavbEptClntAttachStream(pTLState->endpointHandle, streamID, openavbSrp_LDSt_Interest);
+
+ // Notify AVDECC that fast connect is desired.
+ if (pTLState->bAvdeccMsgRunning) {
+ openavbAvdeccMsgClntChangeNotification(pTLState->avdeccMsgHandle, OPENAVB_AVDECC_MSG_STOPPED_UNEXPECTEDLY);
+ }
}
AVB_TRACE_EXIT(AVB_TRACE_TL);
diff --git a/lib/avtp_pipeline/tl/openavb_listener_no_endpoint.c b/lib/avtp_pipeline/tl/openavb_listener_no_endpoint.c
index 877d1c18..d006b708 100644
--- a/lib/avtp_pipeline/tl/openavb_listener_no_endpoint.c
+++ b/lib/avtp_pipeline/tl/openavb_listener_no_endpoint.c
@@ -1,80 +1,81 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-/*
-* MODULE SUMMARY : Listener implementation
-*/
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include "openavb_platform.h"
-#include "openavb_tl.h"
-#include "openavb_avtp.h"
-#include "openavb_listener.h"
-#include "openavb_endpoint.h"
-
-#define AVB_LOG_COMPONENT "Listener"
-#include "openavb_log.h"
-#include "openavb_trace.h"
-
-bool openavbTLRunListenerInit(int hnd, AVBStreamID_t *streamID)
-{
- tl_state_t *pTLState = TLHandleListGet(hnd);
- openavb_tl_cfg_t *pCfg = &pTLState->cfg;
- listener_data_t *pListenerData = pTLState->pPvtListenerData;
-
- strncpy(pListenerData->ifname, pCfg->ifname, IFNAMSIZ);
- memcpy(&pListenerData->streamID.addr, &pCfg->stream_addr.mac->ether_addr_octet, ETH_ALEN);
- pListenerData->streamID.uniqueID = pCfg->stream_uid;
- memcpy(&pListenerData->destAddr, &pCfg->dest_addr.mac->ether_addr_octet, ETH_ALEN);
- pListenerData->tSpec.maxIntervalFrames = pCfg->max_interval_frames;
- pListenerData->tSpec.maxFrameSize = pCfg->max_frame_size;
-
- AVB_LOGF_INFO("Dest Addr: "ETH_FORMAT, ETH_OCTETS(pListenerData->destAddr));
- AVB_LOGF_INFO("Starting stream: "STREAMID_FORMAT, STREAMID_ARGS(streamID));
- listenerStartStream(pTLState);
-
- return TRUE;
-}
-
-
-void openavbEptClntNotifyLstnrOfSrpCb(int endpointHandle,
- AVBStreamID_t *streamID,
- char *ifname,
- U8 destAddr[],
- openavbSrpAttribType_t tlkrDecl,
- AVBTSpec_t *tSpec,
- U8 srClassID,
- U32 latency,
- openavbSrpFailInfo_t *failInfo)
-{
-}
-
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+* MODULE SUMMARY : Listener implementation
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "openavb_platform.h"
+#include "openavb_tl.h"
+#include "openavb_avtp.h"
+#include "openavb_listener.h"
+#include "openavb_endpoint.h"
+
+#define AVB_LOG_COMPONENT "Listener"
+#include "openavb_log.h"
+#include "openavb_trace.h"
+
+bool openavbTLRunListenerInit(int hnd, AVBStreamID_t *streamID)
+{
+ tl_state_t *pTLState = TLHandleListGet(hnd);
+ openavb_tl_cfg_t *pCfg = &pTLState->cfg;
+ listener_data_t *pListenerData = pTLState->pPvtListenerData;
+
+ strncpy(pListenerData->ifname, pCfg->ifname, IFNAMSIZ);
+ memcpy(&pListenerData->streamID.addr, &pCfg->stream_addr.mac->ether_addr_octet, ETH_ALEN);
+ pListenerData->streamID.uniqueID = pCfg->stream_uid;
+ memcpy(&pListenerData->destAddr, &pCfg->dest_addr.mac->ether_addr_octet, ETH_ALEN);
+ pListenerData->tSpec.maxIntervalFrames = pCfg->max_interval_frames;
+ pListenerData->tSpec.maxFrameSize = pCfg->max_frame_size;
+
+ AVB_LOGF_INFO("Dest Addr: "ETH_FORMAT, ETH_OCTETS(pListenerData->destAddr));
+ AVB_LOGF_INFO("Starting stream: "STREAMID_FORMAT, STREAMID_ARGS(streamID));
+ listenerStartStream(pTLState);
+
+ return TRUE;
+}
+
+
+void openavbEptClntNotifyLstnrOfSrpCb(int endpointHandle,
+ AVBStreamID_t *streamID,
+ char *ifname,
+ U8 destAddr[],
+ openavbSrpAttribType_t tlkrDecl,
+ AVBTSpec_t *tSpec,
+ U8 srClassID,
+ U32 latency,
+ openavbSrpFailInfo_t *failInfo)
+{
+}
+
diff --git a/lib/avtp_pipeline/tl/openavb_talker.c b/lib/avtp_pipeline/tl/openavb_talker.c
index ed623a26..24fdacdd 100644
--- a/lib/avtp_pipeline/tl/openavb_talker.c
+++ b/lib/avtp_pipeline/tl/openavb_talker.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -38,7 +39,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_tl.h"
#include "openavb_avtp.h"
#include "openavb_talker.h"
-// #include "openavb_time.h"
+#include "openavb_avdecc_msg_client.h"
// DEBUG Uncomment to turn on logging for just this module.
//#define AVB_LOG_ON 1
@@ -71,6 +72,18 @@ bool talkerStartStream(tl_state_t *pTLState)
if (pCfg->max_transmit_deficit_usec == 0)
pCfg->max_transmit_deficit_usec = 50000;
+ U32 transmitInterval = pTalkerData->classRate;
+ if (pCfg->map_cb.map_transmit_interval_cb(pTLState->pMediaQ)) {
+ // Override the class observation interval with the one provided by the mapping module.
+ transmitInterval = pCfg->map_cb.map_transmit_interval_cb(pTLState->pMediaQ);
+ }
+
+ if (pCfg->intf_cb.intf_enable_fixed_timestamp) {
+ pCfg->intf_cb.intf_enable_fixed_timestamp(pTLState->pMediaQ, pCfg->fixed_timestamp, transmitInterval, pCfg->batch_factor);
+ } else if (pCfg->fixed_timestamp) {
+ AVB_LOG_ERROR("Fixed timestamp enabled but interface doesn't support it");
+ }
+
openavbRC rc = openavbAvtpTxInit(pTLState->pMediaQ,
&pCfg->map_cb,
&pCfg->intf_cb,
@@ -91,13 +104,8 @@ bool talkerStartStream(tl_state_t *pTLState)
avtp_stream_t *pStream = (avtp_stream_t *)(pTalkerData->avtpHandle);
- if (!pStream->pMapCB->map_transmit_interval_cb(pTLState->pMediaQ)) {
- pTalkerData->wakeRate = pTalkerData->classRate / pCfg->batch_factor;
- }
- else {
- // Override the class observation interval with the one provided by the mapping module.
- pTalkerData->wakeRate = pStream->pMapCB->map_transmit_interval_cb(pTLState->pMediaQ) / pCfg->batch_factor;
- }
+ pTalkerData->wakeRate = transmitInterval / pCfg->batch_factor;
+
pTalkerData->sleepUsec = MICROSECONDS_PER_SECOND / pTalkerData->wakeRate;
pTalkerData->intervalNS = NANOSECONDS_PER_SECOND / pTalkerData->wakeRate;
@@ -118,12 +126,18 @@ bool talkerStartStream(tl_state_t *pTLState)
// setup the initial times
U64 nowNS;
- CLOCK_GETTIME64(OPENAVB_TIMER_CLOCK, &nowNS);
-
+
+ if (!pCfg->spin_wait) {
+ CLOCK_GETTIME64(OPENAVB_TIMER_CLOCK, &nowNS);
+ } else {
+ CLOCK_GETTIME64(OPENAVB_CLOCK_WALLTIME, &nowNS);
+ }
+
// Align clock : allows for some performance gain
nowNS = ((nowNS + (pTalkerData->intervalNS)) / pTalkerData->intervalNS) * pTalkerData->intervalNS;
pTalkerData->nextReportNS = nowNS + (pCfg->report_seconds * NANOSECONDS_PER_SECOND);
+ pTalkerData->lastReportFrames = 0;
pTalkerData->nextSecondNS = nowNS + NANOSECONDS_PER_SECOND;
pTalkerData->nextCycleNS = nowNS + pTalkerData->intervalNS;
@@ -161,7 +175,7 @@ void talkerStopStream(tl_state_t *pTLState)
openavbTalkerAddStat(pTLState, TL_STAT_TX_CALLS, pTalkerData->cntWakes);
openavbTalkerAddStat(pTLState, TL_STAT_TX_FRAMES, pTalkerData->cntFrames);
-// openavbTalkerAddStat(pTLState, TL_STAT_TX_LATE, 0); // Can't calulate at this time
+// openavbTalkerAddStat(pTLState, TL_STAT_TX_LATE, 0); // Can't calculate at this time
openavbTalkerAddStat(pTLState, TL_STAT_TX_BYTES, openavbAvtpBytes(pTalkerData->avtpHandle));
AVB_LOGF_INFO("TX "STREAMID_FORMAT", Totals: calls=%" PRIu64 ", frames=%" PRIu64 ", late=%" PRIu64 ", bytes=%" PRIu64 ", TXOutOfBuffs=%ld",
@@ -174,13 +188,33 @@ void talkerStopStream(tl_state_t *pTLState)
);
if (pTLState->bStreaming) {
- openavbAvtpShutdown(pTalkerData->avtpHandle);
+ openavbAvtpShutdownTalker(pTalkerData->avtpHandle);
pTLState->bStreaming = FALSE;
}
AVB_TRACE_EXIT(AVB_TRACE_TL);
}
+static inline void talkerShowStats(talker_data_t *pTalkerData, tl_state_t *pTLState)
+{
+ S32 late = pTalkerData->wakesPerReport - pTalkerData->cntWakes;
+ U64 bytes = openavbAvtpBytes(pTalkerData->avtpHandle);
+ if (late < 0) late = 0;
+ U32 txbuf = openavbAvtpTxBufferLevel(pTalkerData->avtpHandle);
+ U32 mqbuf = openavbMediaQCountItems(pTLState->pMediaQ, TRUE);
+
+ AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "TX UID:%d, ", LOG_RT_DATATYPE_U16, &pTalkerData->streamID.uniqueID);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "calls=%ld, ", LOG_RT_DATATYPE_U32, &pTalkerData->cntWakes);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "frames=%ld, ", LOG_RT_DATATYPE_U32, &pTalkerData->cntFrames);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "late=%d, ", LOG_RT_DATATYPE_U32, &late);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "bytes=%lld, ", LOG_RT_DATATYPE_U64, &bytes);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "txbuf=%d, ", LOG_RT_DATATYPE_U32, &txbuf);
+ AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "mqbuf=%d, ", LOG_RT_DATATYPE_U32, &mqbuf);
+
+ openavbTalkerAddStat(pTLState, TL_STAT_TX_LATE, late);
+ openavbTalkerAddStat(pTLState, TL_STAT_TX_BYTES, bytes);
+}
+
static inline bool talkerDoStream(tl_state_t *pTLState)
{
AVB_TRACE_ENTRY(AVB_TRACE_TL);
@@ -200,62 +234,66 @@ static inline bool talkerDoStream(tl_state_t *pTLState)
if (!pCfg->tx_blocking_in_intf) {
- // sleep until the next interval
- SLEEP_UNTIL_NSEC(pTalkerData->nextCycleNS);
+ if (!pCfg->spin_wait) {
+ // sleep until the next interval
+ SLEEP_UNTIL_NSEC(pTalkerData->nextCycleNS);
+ } else {
+#if !IGB_LAUNCHTIME_ENABLED
+ SPIN_UNTIL_NSEC(pTalkerData->nextCycleNS);
+#endif
+ }
//AVB_DBG_INTERVAL(8000, TRUE);
// send the frames for this interval
int i;
for (i = pTalkerData->wakeFrames; i > 0; i--) {
- if (IS_OPENAVB_SUCCESS(openavbAvtpTx(pTalkerData->avtpHandle, i == 1, pCfg->tx_blocking_in_intf)))
+ if (IS_OPENAVB_SUCCESS(openavbAvtpTx(pTalkerData->avtpHandle, i == 1, pCfg->tx_blocking_in_intf)))
pTalkerData->cntFrames++;
- else break;
- }
+ else
+ break;
}
+ }
else {
// Interface module block option
if (IS_OPENAVB_SUCCESS(openavbAvtpTx(pTalkerData->avtpHandle, TRUE, pCfg->tx_blocking_in_intf)))
pTalkerData->cntFrames++;
}
+ if (!pCfg->spin_wait) {
+ CLOCK_GETTIME64(OPENAVB_TIMER_CLOCK, &nowNS);
+ } else {
+ CLOCK_GETTIME64(OPENAVB_CLOCK_WALLTIME, &nowNS);
+ }
+
if (pTalkerData->cntWakes++ % pTalkerData->wakeRate == 0) {
// time to service the endpoint IPC
bRet = TRUE;
- }
- CLOCK_GETTIME64(OPENAVB_TIMER_CLOCK, &nowNS);
+ // Don't need to check again for another second.
+ pTalkerData->nextSecondNS = nowNS + NANOSECONDS_PER_SECOND;
+ }
if (pCfg->report_seconds > 0) {
if (nowNS > pTalkerData->nextReportNS) {
+ talkerShowStats(pTalkerData, pTLState);
- S32 late = pTalkerData->wakesPerReport - pTalkerData->cntWakes;
- U64 bytes = openavbAvtpBytes(pTalkerData->avtpHandle);
- if (late < 0) late = 0;
- U32 txbuf = openavbAvtpTxBufferLevel(pTalkerData->avtpHandle);
- U32 mqbuf = openavbMediaQCountItems(pTLState->pMediaQ, TRUE);
-
- AVB_LOGRT_INFO(LOG_RT_BEGIN, LOG_RT_ITEM, FALSE, "TX UID:%d, ", LOG_RT_DATATYPE_U16, &pTalkerData->streamID.uniqueID);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "calls=%ld, ", LOG_RT_DATATYPE_U32, &pTalkerData->cntWakes);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "frames=%ld, ", LOG_RT_DATATYPE_U32, &pTalkerData->cntFrames);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "late=%d, ", LOG_RT_DATATYPE_U32, &late);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "bytes=%lld, ", LOG_RT_DATATYPE_U64, &bytes);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, FALSE, "txbuf=%d, ", LOG_RT_DATATYPE_U32, &txbuf);
- AVB_LOGRT_INFO(FALSE, LOG_RT_ITEM, LOG_RT_END, "mqbuf=%d, ", LOG_RT_DATATYPE_U32, &mqbuf);
-
openavbTalkerAddStat(pTLState, TL_STAT_TX_CALLS, pTalkerData->cntWakes);
openavbTalkerAddStat(pTLState, TL_STAT_TX_FRAMES, pTalkerData->cntFrames);
- openavbTalkerAddStat(pTLState, TL_STAT_TX_LATE, late);
- openavbTalkerAddStat(pTLState, TL_STAT_TX_BYTES, bytes);
pTalkerData->cntFrames = 0;
pTalkerData->cntWakes = 0;
- pTalkerData->nextReportNS = nowNS + (pCfg->report_seconds * NANOSECONDS_PER_SECOND);
+ pTalkerData->nextReportNS = nowNS + (pCfg->report_seconds * NANOSECONDS_PER_SECOND);
+ }
+ } else if (pCfg->report_frames > 0 && pTalkerData->cntFrames != pTalkerData->lastReportFrames) {
+ if (pTalkerData->cntFrames % pCfg->report_frames == 1) {
+ talkerShowStats(pTalkerData, pTLState);
+ pTalkerData->lastReportFrames = pTalkerData->cntFrames;
}
}
if (nowNS > pTalkerData->nextSecondNS) {
- pTalkerData->nextSecondNS += NANOSECONDS_PER_SECOND;
+ pTalkerData->nextSecondNS = nowNS + NANOSECONDS_PER_SECOND;
bRet = TRUE;
}
@@ -271,9 +309,10 @@ static inline bool talkerDoStream(tl_state_t *pTLState)
}
}
else {
- SLEEP(1);
- // time to service the endpoint IPC
- bRet = TRUE;
+ SLEEP_MSEC(10);
+
+ // time to service the endpoint IPC
+ bRet = TRUE;
}
AVB_TRACE_EXIT(AVB_TRACE_TL);
@@ -316,13 +355,16 @@ void openavbTLRunTalker(tl_state_t *pTLState)
if (pTLState->bConnected) {
bool bServiceIPC;
- // Do until we are stopped or loose connection to endpoint
+ // Notify AVDECC Msg of the state change.
+ openavbAvdeccMsgClntNotifyCurrentState(pTLState);
+
+ // Do until we are stopped or lose connection to endpoint
while (pTLState->bRunning && pTLState->bConnected) {
// Talk (or just sleep if not streaming.)
bServiceIPC = talkerDoStream(pTLState);
- // TalkerDoStream() returns TRUE once per second,
+ // TalkerDoStream() returns TRUE occasionally,
// so that we can service our IPC at that low rate.
if (bServiceIPC) {
// Look for messages from endpoint. Don't block (timeout=0)
@@ -348,6 +390,9 @@ void openavbTLRunTalker(tl_state_t *pTLState)
openavbEptClntStopStream(pTLState->endpointHandle, &(((talker_data_t *)pTLState->pPvtTalkerData)->streamID));
openavbTLRunTalkerFinish(pTLState);
+
+ // Notify AVDECC Msg of the state change.
+ openavbAvdeccMsgClntNotifyCurrentState(pTLState);
}
else {
AVB_LOGF_WARNING("Failed to connect to endpoint"STREAMID_FORMAT, STREAMID_ARGS(&(((talker_data_t *)pTLState->pPvtTalkerData)->streamID)));
@@ -378,8 +423,12 @@ void openavbTLPauseTalker(tl_state_t *pTLState, bool bPause)
return;
}
+ pTLState->bPaused = bPause;
openavbAvtpPause(pTalkerData->avtpHandle, bPause);
+ // Notify AVDECC Msg of the state change.
+ openavbAvdeccMsgClntNotifyCurrentState(pTLState);
+
AVB_TRACE_EXIT(AVB_TRACE_TL);
}
diff --git a/lib/avtp_pipeline/tl/openavb_talker.h b/lib/avtp_pipeline/tl/openavb_talker.h
index b180d12a..86bfc39e 100644
--- a/lib/avtp_pipeline/tl/openavb_talker.h
+++ b/lib/avtp_pipeline/tl/openavb_talker.h
@@ -1,16 +1,17 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
+
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -21,10 +22,10 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -39,10 +40,11 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
typedef struct {
// Data from callback
- char ifname[IFNAMSIZ];
- AVBStreamID_t streamID;
+ char ifname[IFNAMSIZ + 10]; // Include space for the socket type prefix (e.g. "simple:eth0")
+ AVBStreamID_t streamID;
U8 destAddr[ETH_ALEN];
AVBTSpec_t tSpec;
+ U8 srClass;
U32 classRate;
U32 fwmark;
U16 vlanID;
@@ -60,6 +62,7 @@ typedef struct {
U64 intervalNS;
U64 nextReportNS;
U64 nextSecondNS;
+ unsigned long lastReportFrames;
talker_stats_t stats;
} talker_data_t;
diff --git a/lib/avtp_pipeline/tl/openavb_talker_endpoint.c b/lib/avtp_pipeline/tl/openavb_talker_endpoint.c
index 27511f96..e3343e78 100644
--- a/lib/avtp_pipeline/tl/openavb_talker_endpoint.c
+++ b/lib/avtp_pipeline/tl/openavb_talker_endpoint.c
@@ -1,16 +1,17 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
+
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -21,15 +22,15 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
/*
-* MODULE SUMMARY : Talker implementation for use with endpoint
+* MODULE SUMMARY : Talker implementation for use with endpoint
*/
#include <stdlib.h>
@@ -41,6 +42,7 @@ https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
#include "openavb_avtp.h"
#include "openavb_talker.h"
#include "openavb_time.h"
+#include "openavb_avdecc_msg.h"
// DEBUG Uncomment to turn on logging for just this module.
//#define AVB_LOG_ON 1
@@ -56,6 +58,7 @@ void openavbEptClntNotifyTlkrOfSrpCb(int endpointHandle,
char *ifname,
U8 destAddr[],
openavbSrpLsnrDeclSubtype_t lsnrDecl,
+ U8 srClass,
U32 classRate,
U16 vlanID,
U8 priority,
@@ -71,16 +74,29 @@ void openavbEptClntNotifyTlkrOfSrpCb(int endpointHandle,
return;
}
+ // If not a talker, ignore this callback.
+ if (pTLState->cfg.role != AVB_ROLE_TALKER) {
+ AVB_LOG_DEBUG("Ignoring Talker callback");
+ return;
+ }
+
AVB_LOGF_DEBUG("%s streaming=%d, lsnrDecl=%d", __FUNCTION__, pTLState->bStreaming, lsnrDecl);
+ openavb_tl_cfg_t *pCfg = &pTLState->cfg;
+
if (!pTLState->bStreaming) {
if (lsnrDecl == openavbSrp_LDSt_Ready
|| lsnrDecl == openavbSrp_LDSt_Ready_Failed) {
// Save the data provided by endpoint/SRP
- strncpy(pTalkerData->ifname, ifname, IFNAMSIZ);
+ if (!pCfg->ifname[0]) {
+ strncpy(pTalkerData->ifname, ifname, IFNAMSIZ);
+ } else {
+ strncpy(pTalkerData->ifname, pCfg->ifname, IFNAMSIZ);
+ }
memcpy(&pTalkerData->streamID, streamID, sizeof(AVBStreamID_t));
memcpy(&pTalkerData->destAddr, destAddr, ETH_ALEN);
+ pTalkerData->srClass = srClass;
pTalkerData->classRate = classRate;
pTalkerData->vlanID = vlanID;
pTalkerData->vlanPCP = priority;
@@ -92,9 +108,14 @@ void openavbEptClntNotifyTlkrOfSrpCb(int endpointHandle,
}
else if (lsnrDecl == openavbSrp_LDSt_Stream_Info) {
// Stream information is available does NOT mean listener is ready. Stream not started yet.
- strncpy(pTalkerData->ifname, ifname, IFNAMSIZ);
+ if (!pCfg->ifname[0]) {
+ strncpy(pTalkerData->ifname, ifname, IFNAMSIZ);
+ } else {
+ strncpy(pTalkerData->ifname, pCfg->ifname, IFNAMSIZ);
+ }
memcpy(&pTalkerData->streamID, streamID, sizeof(AVBStreamID_t));
memcpy(&pTalkerData->destAddr, destAddr, ETH_ALEN);
+ pTalkerData->srClass = srClass;
pTalkerData->classRate = classRate;
pTalkerData->vlanID = vlanID;
pTalkerData->vlanPCP = priority;
@@ -110,6 +131,14 @@ void openavbEptClntNotifyTlkrOfSrpCb(int endpointHandle,
}
}
+ // Let the AVDECC Msg server know our current stream ID, in case it was updated by MAAP.
+ if (pTLState->avdeccMsgHandle != AVB_AVDECC_MSG_HANDLE_INVALID) {
+ if (!openavbAvdeccMsgClntTalkerStreamID(pTLState->avdeccMsgHandle,
+ pTalkerData->srClass, pTalkerData->streamID.addr, pTalkerData->streamID.uniqueID,
+ pTalkerData->destAddr, pTalkerData->vlanID)) {
+ AVB_LOG_ERROR("openavbAvdeccMsgClntTalkerStreamID() failed");
+ }
+ }
AVB_TRACE_EXIT(AVB_TRACE_TL);
}
@@ -149,13 +178,20 @@ bool openavbTLRunTalkerInit(tl_state_t *pTLState)
// Tell endpoint to register our stream.
// SRP will send out talker declarations on the LAN.
// If there are listeners, we'll get callback (above.)
+ U32 transmitInterval = pTalkerData->classRate;
+ if (pCfg->map_cb.map_transmit_interval_cb(pTLState->pMediaQ)) {
+ // Override the class observation interval with the one provided by the mapping module.
+ transmitInterval = pCfg->map_cb.map_transmit_interval_cb(pTLState->pMediaQ);
+ }
return (openavbEptClntRegisterStream(pTLState->endpointHandle,
- &streamID,
- pCfg->dest_addr.mac->ether_addr_octet,
- &pTalkerData->tSpec,
- pCfg->sr_class,
- pCfg->sr_rank,
- pCfg->internal_latency));
+ &streamID,
+ pCfg->dest_addr.mac->ether_addr_octet,
+ pCfg->backup_dest_addr_valid, // If we have a backup dest_addr, then the current one was forced and MAAP should not be used.
+ &pTalkerData->tSpec,
+ pCfg->sr_class,
+ pCfg->sr_rank,
+ pCfg->internal_latency,
+ transmitInterval));
}
void openavbTLRunTalkerFinish(tl_state_t *pTLState)
diff --git a/lib/avtp_pipeline/tl/openavb_talker_no_endpoint.c b/lib/avtp_pipeline/tl/openavb_talker_no_endpoint.c
index d7e08225..03cb8ade 100644
--- a/lib/avtp_pipeline/tl/openavb_talker_no_endpoint.c
+++ b/lib/avtp_pipeline/tl/openavb_talker_no_endpoint.c
@@ -1,151 +1,164 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-/*
-* MODULE SUMMARY : Talker implementation for use without endpoint
-*/
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include "openavb_tl.h"
-#include "openavb_avtp.h"
-#include "openavb_talker.h"
-#include "openavb_qmgr.h"
-#include "openavb_endpoint.h"
-
-#define AVB_LOG_COMPONENT "Talker"
-#include "openavb_log.h"
-#include "openavb_trace.h"
-
-// SR Class default Priority (PCP) values per IEEE 802.1Q-2011 Table 6-6
-#define SR_CLASS_A_DEFAULT_PRIORITY 3
-#define SR_CLASS_B_DEFAULT_PRIORITY 2
-
-// SR Class default VLAN Id values per IEEE 802.1Q-2011 Table 9-2
-#define SR_CLASS_A_DEFAULT_VID 2
-#define SR_CLASS_B_DEFAULT_VID 2
-
-// Returns TRUE, to say we're connected and registers tspec with FQTSS tspec should be initialized
-bool openavbTLRunTalkerInit(tl_state_t *pTLState)
-{
- openavb_tl_cfg_t *pCfg = &pTLState->cfg;
- talker_data_t *pTalkerData = pTLState->pPvtTalkerData;
- //avtp_stream_t *pStream = (avtp_stream_t *)(pTalkerData->avtpHandle);
-
- strncpy(pTalkerData->ifname, pCfg->ifname, IFNAMSIZ);
-
- // CORE_TODO: It would be good to have some parts of endpoint moved into non-endpoint general code to handle some the stream
- // configuration values.
- // strncpy(pTalkerData->ifname, pCfg->ifname, IFNAMSIZ);
- if (pCfg->stream_addr.mac) {
- memcpy(pTalkerData->streamID.addr, pCfg->stream_addr.mac, ETH_ALEN);
- }else {
- AVB_LOG_WARNING("Stream Address Not Set");
- }
-
- pTalkerData->streamID.uniqueID = pCfg->stream_uid;
- if (pCfg->sr_class == SR_CLASS_A) {
- pTalkerData->classRate = 8000;
- pTalkerData->vlanID = pCfg->vlan_id == VLAN_NULL ?
- SR_CLASS_A_DEFAULT_VID : pCfg->vlan_id;
- pTalkerData->vlanPCP = SR_CLASS_A_DEFAULT_PRIORITY;
- }
- else if (pCfg->sr_class == SR_CLASS_B) {
- pTalkerData->classRate = 4000;
- pTalkerData->vlanID = pCfg->vlan_id == VLAN_NULL ?
- SR_CLASS_B_DEFAULT_VID : pCfg->vlan_id;
- pTalkerData->vlanPCP = SR_CLASS_B_DEFAULT_PRIORITY;
- }
- memcpy(&pTalkerData->destAddr, &pCfg->dest_addr.mac->ether_addr_octet, ETH_ALEN);
-
- unsigned int maxBitrate = 0;
- if (pCfg->intf_cb.intf_get_src_bitrate_cb != NULL) {
- maxBitrate = pCfg->intf_cb.intf_get_src_bitrate_cb(pTLState->pMediaQ);
- }
- if (maxBitrate > 0) {
- if (pCfg->map_cb.map_set_src_bitrate_cb != NULL) {
- pCfg->map_cb.map_set_src_bitrate_cb(pTLState->pMediaQ, maxBitrate);
- }
-
- if (pCfg->map_cb.map_get_max_interval_frames_cb != NULL) {
- unsigned int map_intv_frames = pCfg->map_cb.map_get_max_interval_frames_cb(pTLState->pMediaQ, pTLState->cfg.sr_class);
- pCfg->max_interval_frames = map_intv_frames > 0 ? map_intv_frames : pCfg->max_interval_frames;
- }
- }
- pTalkerData->tSpec.maxIntervalFrames = pCfg->max_interval_frames;
- pTalkerData->tSpec.maxFrameSize = pCfg->map_cb.map_max_data_size_cb(pTLState->pMediaQ);
-
- // TODO_COREAVB : This wakeRate should also be set in the endpoint case and removed from the tasker.c start stream
- if (!pCfg->map_cb.map_transmit_interval_cb(pTLState->pMediaQ)) {
- pTalkerData->wakeRate = pTalkerData->classRate / pCfg->batch_factor;
- }
- else {
- // Override the class observation interval with the one provided by the mapping module.
- pTalkerData->wakeRate = pCfg->map_cb.map_transmit_interval_cb(pTLState->pMediaQ) / pCfg->batch_factor;
- }
-
- if_info_t ifinfo;
- openavbCheckInterface(pTalkerData->ifname, &ifinfo);
-
- pTalkerData->fwmark = openavbQmgrAddStream((SRClassIdx_t)pCfg->sr_class,
- pTalkerData->wakeRate,
- pTalkerData->tSpec.maxIntervalFrames,
- pTalkerData->tSpec.maxFrameSize);
-
- if (pTalkerData->fwmark == INVALID_FWMARK)
- return FALSE;
-
- AVB_LOGF_INFO("Dest Addr: "ETH_FORMAT, ETH_OCTETS(pTalkerData->destAddr));
- AVB_LOGF_INFO("Starting stream: "STREAMID_FORMAT, STREAMID_ARGS(&pTalkerData->streamID));
- talkerStartStream(pTLState);
-
- return TRUE;
-}
-
-void openavbTLRunTalkerFinish(tl_state_t *pTLState)
-{
- talker_data_t *pTalkerData = pTLState->pPvtTalkerData;
- openavbQmgrRemoveStream(pTalkerData->fwmark);
-}
-
-void openavbEptClntNotifyTlkrOfSrpCb(
-int endpointHandle,
-AVBStreamID_t *streamID,
-char *ifname,
-U8 destAddr[],
-openavbSrpLsnrDeclSubtype_t lsnrDecl,
-U32 classRate,
-U16 vlanID,
-U8 priority,
-U16 fwmark)
-{
-}
-
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+* MODULE SUMMARY : Talker implementation for use without endpoint
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "openavb_tl.h"
+#include "openavb_avtp.h"
+#include "openavb_talker.h"
+#include "openavb_qmgr.h"
+#include "openavb_endpoint.h"
+#include "openavb_avdecc_msg.h"
+
+#define AVB_LOG_COMPONENT "Talker"
+#include "openavb_log.h"
+#include "openavb_trace.h"
+
+// SR Class default Priority (PCP) values per IEEE 802.1Q-2011 Table 6-6
+#define SR_CLASS_A_DEFAULT_PRIORITY 3
+#define SR_CLASS_B_DEFAULT_PRIORITY 2
+
+// SR Class default VLAN Id values per IEEE 802.1Q-2011 Table 9-2
+#define SR_CLASS_A_DEFAULT_VID 2
+#define SR_CLASS_B_DEFAULT_VID 2
+
+// Returns TRUE, to say we're connected and registers tspec with FQTSS tspec should be initialized
+bool openavbTLRunTalkerInit(tl_state_t *pTLState)
+{
+ openavb_tl_cfg_t *pCfg = &pTLState->cfg;
+ talker_data_t *pTalkerData = pTLState->pPvtTalkerData;
+ //avtp_stream_t *pStream = (avtp_stream_t *)(pTalkerData->avtpHandle);
+
+ strncpy(pTalkerData->ifname, pCfg->ifname, IFNAMSIZ);
+
+ // CORE_TODO: It would be good to have some parts of endpoint moved into non-endpoint general code to handle some the stream
+ // configuration values.
+ // strncpy(pTalkerData->ifname, pCfg->ifname, IFNAMSIZ);
+ if (pCfg->stream_addr.mac) {
+ memcpy(pTalkerData->streamID.addr, pCfg->stream_addr.mac, ETH_ALEN);
+ }else {
+ AVB_LOG_WARNING("Stream Address Not Set");
+ }
+
+ pTalkerData->streamID.uniqueID = pCfg->stream_uid;
+ pTalkerData->srClass = pCfg->sr_class;
+ if (pCfg->sr_class == SR_CLASS_A) {
+ pTalkerData->classRate = 8000;
+ pTalkerData->vlanID = (pCfg->vlan_id == 0 ?
+ SR_CLASS_A_DEFAULT_VID : pCfg->vlan_id);
+ pTalkerData->vlanPCP = SR_CLASS_A_DEFAULT_PRIORITY;
+ }
+ else if (pCfg->sr_class == SR_CLASS_B) {
+ pTalkerData->classRate = 4000;
+ pTalkerData->vlanID = (pCfg->vlan_id == 0 ?
+ SR_CLASS_B_DEFAULT_VID : pCfg->vlan_id);
+ pTalkerData->vlanPCP = SR_CLASS_B_DEFAULT_PRIORITY;
+ }
+ memcpy(&pTalkerData->destAddr, &pCfg->dest_addr.mac->ether_addr_octet, ETH_ALEN);
+
+ unsigned int maxBitrate = 0;
+ if (pCfg->intf_cb.intf_get_src_bitrate_cb != NULL) {
+ maxBitrate = pCfg->intf_cb.intf_get_src_bitrate_cb(pTLState->pMediaQ);
+ }
+ if (maxBitrate > 0) {
+ if (pCfg->map_cb.map_set_src_bitrate_cb != NULL) {
+ pCfg->map_cb.map_set_src_bitrate_cb(pTLState->pMediaQ, maxBitrate);
+ }
+
+ if (pCfg->map_cb.map_get_max_interval_frames_cb != NULL) {
+ unsigned int map_intv_frames = pCfg->map_cb.map_get_max_interval_frames_cb(pTLState->pMediaQ, pTLState->cfg.sr_class);
+ pCfg->max_interval_frames = map_intv_frames > 0 ? map_intv_frames : pCfg->max_interval_frames;
+ }
+ }
+ pTalkerData->tSpec.maxIntervalFrames = pCfg->max_interval_frames;
+ pTalkerData->tSpec.maxFrameSize = pCfg->map_cb.map_max_data_size_cb(pTLState->pMediaQ);
+
+ // TODO_COREAVB : This wakeRate should also be set in the endpoint case and removed from the tasker.c start stream
+ if (!pCfg->map_cb.map_transmit_interval_cb(pTLState->pMediaQ)) {
+ pTalkerData->wakeRate = pTalkerData->classRate / pCfg->batch_factor;
+ }
+ else {
+ // Override the class observation interval with the one provided by the mapping module.
+ pTalkerData->wakeRate = pCfg->map_cb.map_transmit_interval_cb(pTLState->pMediaQ) / pCfg->batch_factor;
+ }
+
+ if_info_t ifinfo;
+ openavbCheckInterface(pTalkerData->ifname, &ifinfo);
+
+ pTalkerData->fwmark = openavbQmgrAddStream((SRClassIdx_t)pCfg->sr_class,
+ pTalkerData->wakeRate,
+ pTalkerData->tSpec.maxIntervalFrames,
+ pTalkerData->tSpec.maxFrameSize);
+
+ if (pTalkerData->fwmark == INVALID_FWMARK)
+ return FALSE;
+
+ AVB_LOGF_INFO("Dest Addr: "ETH_FORMAT, ETH_OCTETS(pTalkerData->destAddr));
+ AVB_LOGF_INFO("Starting stream: "STREAMID_FORMAT, STREAMID_ARGS(&pTalkerData->streamID));
+ talkerStartStream(pTLState);
+
+ // Let the AVDECC Msg server know our current stream ID, in case it is waiting for an update.
+ if (pTLState->avdeccMsgHandle != AVB_AVDECC_MSG_HANDLE_INVALID) {
+ if (!openavbAvdeccMsgClntTalkerStreamID(pTLState->avdeccMsgHandle,
+ pTalkerData->srClass, pTalkerData->streamID.addr, pTalkerData->streamID.uniqueID,
+ pTalkerData->destAddr, pTalkerData->vlanID)) {
+ AVB_LOG_ERROR("openavbAvdeccMsgClntTalkerStreamID() failed");
+ }
+ }
+
+ return TRUE;
+}
+
+void openavbTLRunTalkerFinish(tl_state_t *pTLState)
+{
+ talker_data_t *pTalkerData = pTLState->pPvtTalkerData;
+ openavbQmgrRemoveStream(pTalkerData->fwmark);
+}
+
+void openavbEptClntNotifyTlkrOfSrpCb(
+int endpointHandle,
+AVBStreamID_t *streamID,
+char *ifname,
+U8 destAddr[],
+openavbSrpLsnrDeclSubtype_t lsnrDecl,
+U8 srClass,
+U32 classRate,
+U16 vlanID,
+U8 priority,
+U16 fwmark)
+{
+}
+
diff --git a/lib/avtp_pipeline/tl/openavb_tl.c b/lib/avtp_pipeline/tl/openavb_tl.c
index eb9ee145..4fc6eff5 100755
--- a/lib/avtp_pipeline/tl/openavb_tl.c
+++ b/lib/avtp_pipeline/tl/openavb_tl.c
@@ -1,734 +1,767 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-/*
-* MODULE SUMMARY : Common implementation for the talker and listener
-*/
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include "openavb_tl.h"
-#include "openavb_trace.h"
-#include "openavb_mediaq.h"
-#include "openavb_talker.h"
-#include "openavb_listener.h"
-// #include "openavb_avtp.h"
-#include "openavb_platform.h"
-
-#define AVB_LOG_COMPONENT "Talker / Listener"
-#include "openavb_pub.h"
-#include "openavb_log.h"
-
-U32 gMaxTL;
-tl_handle_t *gTLHandleList;
-
-// We are accessed from multiple threads, so need a mutex
-MUTEX_HANDLE(gTLStateMutex);
-
-#define MATCH(A, B)(strcasecmp((A), (B)) == 0)
-//#define MATCH_LEFT(A, B, C)(strncasecmp((A), (B), (C)) == 0)
-#define MATCH_LEFT(A, B, C) (memcmp((A), (B), (C)) == 0)
-
-THREAD_TYPE(listenerThread);
-THREAD_TYPE(talkerThread);
-
-void* openavbTLThreadFn(void *pv);
-#define THREAD_CREATE_TALKER() THREAD_CREATE(talkerThread, pTLState->TLThread, NULL, openavbTLThreadFn, pTLState)
-#define THREAD_CREATE_LISTENER() THREAD_CREATE(listenerThread, pTLState->TLThread, NULL, openavbTLThreadFn, pTLState)
-
-void timespec_add_usec(struct timespec *t, unsigned long us)
-{
- t->tv_nsec += us * NANOSECONDS_PER_USEC;
- t->tv_sec += t->tv_nsec / NANOSECONDS_PER_SECOND;
- t->tv_nsec = t->tv_nsec % NANOSECONDS_PER_SECOND;
-}
-
-void timespec_sub_usec(struct timespec *t, unsigned long us)
-{
- t->tv_nsec -= us * NANOSECONDS_PER_USEC;
- t->tv_sec += t->tv_nsec / NANOSECONDS_PER_SECOND;
- t->tv_nsec = t->tv_nsec % NANOSECONDS_PER_SECOND;
- if (t->tv_nsec < 0) {
- t->tv_sec--;
- t->tv_nsec = NANOSECONDS_PER_SECOND + t->tv_nsec;
- }
-}
-
-unsigned long timespec_usec_diff(struct timespec *t1, struct timespec *t2)
-{
- return (t1->tv_sec - t2->tv_sec) * MICROSECONDS_PER_SECOND
- + (t1->tv_nsec - t2->tv_nsec) / NANOSECONDS_PER_USEC;
-}
-
-int timespec_cmp(struct timespec *a, struct timespec *b)
-{
- if (a->tv_sec > b->tv_sec)
- return 1;
- else if (a->tv_sec < b->tv_sec)
- return -1;
- else {
- if (a->tv_nsec > b->tv_nsec)
- return 1;
- else if (a->tv_nsec < b->tv_nsec)
- return -1;
- }
- return 0;
-}
-
-static bool TLHandleListAdd(tl_handle_t handle)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
-
- if (!handle || !gTLHandleList) {
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return FALSE;
- }
-
- TL_LOCK();
- int i1;
- for (i1 = 0; i1 < gMaxTL; i1++) {
- if (!gTLHandleList[i1]) {
- gTLHandleList[i1] = handle;
- TL_UNLOCK();
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return TRUE;
- }
- }
- TL_UNLOCK();
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return FALSE;
-}
-
-bool TLHandleListRemove(tl_handle_t handle)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
-
- if (!handle || !gTLHandleList) {
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return FALSE;
- }
-
- TL_LOCK();
- int i1;
- for (i1 = 0; i1 < gMaxTL; i1++) {
- if (gTLHandleList[i1] == handle) {
- gTLHandleList[i1] = NULL;
- TL_UNLOCK();
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return TRUE;
- }
- }
- TL_UNLOCK();
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return FALSE;
-}
-
-static bool checkIntfCallbacks(openavb_tl_cfg_t *pCfg)
-{
- bool validCfg = TRUE;
-
- if (!pCfg->intf_cb.intf_cfg_cb) {
- AVB_LOG_WARNING("INI file doesn't specify inferface callback for '_cfg'.");
- // validCfg = FALSE;
- }
- if ((pCfg->role == AVB_ROLE_TALKER) && !pCfg->intf_cb.intf_tx_init_cb) {
- AVB_LOG_WARNING("INI file doesn't specify inferface callback for '_tx_init'.");
- // validCfg = FALSE;
- }
- if ((pCfg->role == AVB_ROLE_TALKER) && !pCfg->intf_cb.intf_tx_cb) {
- AVB_LOG_ERROR("INI file doesn't specify inferface callback for '_tx'.");
- validCfg = FALSE;
- }
- if ((pCfg->role == AVB_ROLE_LISTENER) && !pCfg->intf_cb.intf_rx_init_cb) {
- AVB_LOG_WARNING("INI file doesn't specify inferface callback for '_rx_init'.");
- // validCfg = FALSE;
- }
- if ((pCfg->role == AVB_ROLE_LISTENER) && !pCfg->intf_cb.intf_rx_cb) {
- AVB_LOG_ERROR("INI file doesn't specify inferface callback for '_rx'.");
- validCfg = FALSE;
- }
- if (!pCfg->intf_cb.intf_end_cb) {
- AVB_LOG_WARNING("INI file doesn't specify inferface callback for '_end'.");
- // validCfg = FALSE;
- }
- if (!pCfg->intf_cb.intf_gen_init_cb) {
- AVB_LOG_WARNING("INI file doesn't specify inferface callback for '_gen_init'.");
- // validCfg = FALSE;
- }
- if (!pCfg->intf_cb.intf_gen_end_cb) {
- AVB_LOG_WARNING("INI file doesn't specify inferface callback for '_gen_end'.");
- // validCfg = FALSE;
- }
- if (!pCfg->intf_cb.intf_avdecc_init_cb) {
- // Optional callback
- // CORE_TODO: AVDECC not formally supported yet.
- // AVB_LOG_WARNING("INI file doesn't specify inferface callback for '_avdecc_init'.");
- // validCfg = FALSE;
- }
-
- return validCfg;
-}
-
-static bool checkMapCallbacks(openavb_tl_cfg_t *pCfg)
-{
- bool validCfg = TRUE;
-
- if (!pCfg->map_cb.map_cfg_cb) {
- AVB_LOG_WARNING("INI doesn't specify mapping callback for '_cfg'.");
- // validCfg = FALSE;
- }
- if (!pCfg->map_cb.map_subtype_cb) {
- AVB_LOG_WARNING("INI doesn't specify mapping callback for '_subtype'.");
- // validCfg = FALSE;
- }
- if (!pCfg->map_cb.map_avtp_version_cb) {
- AVB_LOG_WARNING("INI doesn't specify mapping callback for '_avtp_version'.");
- // validCfg = FALSE;
- }
- if ((pCfg->role == AVB_ROLE_TALKER) && !pCfg->map_cb.map_tx_init_cb) {
- AVB_LOG_WARNING("INI doesn't specify mapping callback for '_tx_init'.");
- // validCfg = FALSE;
- }
- if ((pCfg->role == AVB_ROLE_TALKER) && !pCfg->map_cb.map_tx_cb) {
- AVB_LOG_ERROR("INI doesn't specify mapping callback for '_tx'.");
- validCfg = FALSE;
- }
- if ((pCfg->role == AVB_ROLE_LISTENER) && !pCfg->map_cb.map_rx_init_cb) {
- AVB_LOG_WARNING("INI doesn't specify mapping callback for '_rx_init'.");
- // validCfg = FALSE;
- }
- if ((pCfg->role == AVB_ROLE_LISTENER) && !pCfg->map_cb.map_rx_cb) {
- AVB_LOG_ERROR("INI doesn't specify mapping callback for '_rx'.");
- validCfg = FALSE;
- }
- if (!pCfg->map_cb.map_end_cb) {
- AVB_LOG_WARNING("INI doesn't specify mapping callback for '_end'.");
- // validCfg = FALSE;
- }
- if (!pCfg->map_cb.map_gen_init_cb) {
- AVB_LOG_WARNING("INI doesn't specify mapping callback for '_gen_init'.");
- // validCfg = FALSE;
- }
- if (!pCfg->map_cb.map_gen_end_cb) {
- AVB_LOG_WARNING("INI doesn't specify mapping callback for '_gen_end'.");
- // validCfg = FALSE;
- }
- if (!pCfg->map_cb.map_avdecc_init_cb) {
- // Optional callback
- // CORE_TODO: AVDECC not formally supported yet.
- // AVB_LOG_WARNING("INI doesn't specify mapping callback for '_avdecc_init'.");
- // validCfg = FALSE;
- }
-
- return validCfg;
-}
-
-void openavbTLUnconfigure(tl_state_t *pTLState)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
-
- // CORE_TODO: Disable this functionality until updated to properly handle distinction between values point to static const char
- // and dynamically allocated strings.
-#if 0
- openavb_tl_cfg_t *pCfg = &pTLState->cfg;
-
- int i1;
- for (i1 = 0; i1 < pCfg->nLibCfgItems; i1++) {
- if (pCfg->libCfgNames[i1])
- free(pCfg->libCfgNames[i1]);
- if (pNVCfg->libCfgValues[i1])
- free(pNVCfg->libCfgValues[i1]);
- pCfg->libCfgNames[i1] = pNVCfg->libCfgValues[i1] = NULL;
- }
- pCfg->nLibCfgItems = 0;
-#endif
-
- AVB_TRACE_EXIT(AVB_TRACE_TL);
-}
-
-
-/* Public APIs
- */
-// General initizlization of the talker and listener library. Must be called prior to using any other TL APIs.
-EXTERN_DLL_EXPORT bool openavbTLInitialize(U32 maxTL)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
- LOG_EAVB_CORE_VERSION();
-
- // CORE_TODO : This can be used to AVB stack init functionality once such a thing exists in the reference implementation
- AVB_TIME_INIT();
-
- gMaxTL = maxTL;
-
- {
- MUTEX_ATTR_HANDLE(mta);
- MUTEX_ATTR_INIT(mta);
- MUTEX_ATTR_SET_TYPE(mta, MUTEX_ATTR_TYPE_DEFAULT);
- MUTEX_ATTR_SET_NAME(mta, "gTLStateMutex");
- MUTEX_CREATE_ERR();
- MUTEX_CREATE(gTLStateMutex, mta);
- MUTEX_LOG_ERR("Error creating mutex");
- }
-
- gTLHandleList = calloc(1, sizeof(tl_handle_t) * gMaxTL);
- if (gTLHandleList) {
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return TRUE;
- }
- else {
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return FALSE;
- }
-}
-
-// General cleanup of the talker and listener library. Should be called after all Talker and Listeners are closed.
-EXTERN_DLL_EXPORT bool openavbTLCleanup()
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
- if (gTLHandleList) {
- free(gTLHandleList);
- gTLHandleList = NULL;
- }
- else {
- return FALSE;
- }
-
- {
- MUTEX_CREATE_ERR();
- MUTEX_DESTROY(gTLStateMutex);
- MUTEX_LOG_ERR("Error destroying mutex");
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return TRUE;
-}
-
-EXTERN_DLL_EXPORT bool openavbGetVersion(U8 *major, U8 *minor, U8 *revision)
-{
- if (!major || !minor || !revision) {
- return FALSE;
- }
-
- *major = AVB_CORE_VER_MAJOR;
- *minor = AVB_CORE_VER_MINOR;
- *revision = AVB_CORE_VER_REVISION;
- return TRUE;
-}
-
-EXTERN_DLL_EXPORT tl_handle_t openavbTLOpen(void)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
-
- tl_state_t *pTLState = calloc(1, sizeof(tl_state_t));
-
- if (!pTLState) {
- AVB_LOG_ERROR("Unable to allocate talker listener state data.");
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return NULL;
- }
-
- if (!TLHandleListAdd(pTLState)) {
- AVB_LOG_ERROR("To many talker listeners open.");
- free(pTLState);
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return NULL;
- }
-
- return pTLState;
-}
-
-EXTERN_DLL_EXPORT void openavbTLInitCfg(openavb_tl_cfg_t *pCfg)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
-
- memset(pCfg, 0, sizeof(openavb_tl_cfg_t));
-
- // Set default values.
- pCfg->role = AVB_ROLE_UNDEFINED;
- //pCfg->map_cb;
- //pCfg->intf_cb;
- //pCfg->dest_addr;
- //pCfg->stream_addr;
- pCfg->stream_uid = -1;
- pCfg->max_interval_frames = 1;
- pCfg->max_frame_size = 1500;
- pCfg->max_transit_usec = 50000;
- pCfg->max_transmit_deficit_usec = 50000;
- pCfg->internal_latency = 0;
- pCfg->max_stale = MICROSECONDS_PER_SECOND;
- pCfg->batch_factor = 1;
- pCfg->report_seconds = 0;
- pCfg->start_paused = FALSE;
- pCfg->sr_class = SR_CLASS_B;
- pCfg->sr_rank = SR_RANK_REGULAR;
- pCfg->raw_tx_buffers = 8;
- pCfg->raw_rx_buffers = 100;
- pCfg->tx_blocking_in_intf = 0;
- pCfg->rx_signal_mode = 1;
- pCfg->pMapInitFn = NULL;
- pCfg->pIntfInitFn = NULL;
- pCfg->vlan_id = VLAN_NULL;
-
- AVB_TRACE_EXIT(AVB_TRACE_TL);
-}
-
-EXTERN_DLL_EXPORT bool openavbTLConfigure(tl_handle_t handle, openavb_tl_cfg_t *pCfgIn, openavb_tl_cfg_name_value_t *pNVCfg)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
-
- tl_state_t *pTLState = (tl_state_t *)handle;
-
- if (!pTLState) {
- AVB_LOG_ERROR("Invalid handle.");
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return FALSE;
- }
-
- // Create the mediaQ
- pTLState->pMediaQ = openavbMediaQCreate();
- if (!pTLState->pMediaQ) {
- AVB_LOG_ERROR("Unable to create media queue");
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return FALSE;
- }
-
- // CORE_TODO: It's not safe to simply copy the openavb_tl_cfg_t since there are embedded pointers in the cfg_mac_t member.
- // Those pointers need to be updated after a copy. Longer term the cfg_mac_t should be changed to not contain the mac
- // member to remedy this issue and avoid further bugs.
- memcpy(&pTLState->cfg, pCfgIn, sizeof(openavb_tl_cfg_t));
- pTLState->cfg.dest_addr.mac = &pTLState->cfg.dest_addr.buffer;
- pTLState->cfg.stream_addr.mac = &pTLState->cfg.stream_addr.buffer;
-
- openavb_tl_cfg_t *pCfg = &pTLState->cfg;
-
- if (!((pCfg->role == AVB_ROLE_TALKER) || (pCfg->role == AVB_ROLE_LISTENER))) {
- AVB_LOG_ERROR("Talker - Listener Config Error: invalid role");
- return FALSE;
- }
-
- if ((pCfg->role == AVB_ROLE_TALKER) && (pCfg->max_interval_frames == 0)) {
- AVB_LOG_ERROR("Talker - Listener Config Error: talker role requires 'max_interval_frames'");
- return FALSE;
- }
-
- openavbMediaQSetMaxStaleTail(pTLState->pMediaQ, pCfg->max_stale);
-
- if (!openavbTLOpenLinkLibsOsal(pTLState)) {
- AVB_LOG_ERROR("Failed to open mapping / interface library");
- return FALSE;
- }
-
- if (pCfg->pMapInitFn && pCfg->pMapInitFn(pTLState->pMediaQ, &pCfg->map_cb, pCfg->max_transit_usec)) {
- checkMapCallbacks(&pTLState->cfg);
- }
- else {
- AVB_LOG_ERROR("Mapping initialize function error.");
- return FALSE;
- }
-
- if (pCfg->pIntfInitFn && pCfg->pIntfInitFn(pTLState->pMediaQ, &pCfg->intf_cb)) {
- checkIntfCallbacks(&pTLState->cfg);
- }
- else {
- AVB_LOG_ERROR("Interface initialize function error.");
- return FALSE;
- }
-
- // Submit configuration values to mapping and interface modules
- int i;
- for (i = 0; i < pNVCfg->nLibCfgItems; i++) {
- if (MATCH_LEFT(pNVCfg->libCfgNames[i], "intf_nv_", 8)) {
- if (pCfg->intf_cb.intf_cfg_cb) {
- pCfg->intf_cb.intf_cfg_cb(pTLState->pMediaQ, pNVCfg->libCfgNames[i], pNVCfg->libCfgValues[i]);
- }
- else {
- AVB_LOGF_ERROR("No interface module cfg function; ignoring %s", pNVCfg->libCfgNames[i]);
- }
- }
- else if (MATCH_LEFT(pNVCfg->libCfgNames[i], "map_nv_", 7)) {
- if (pCfg->map_cb.map_cfg_cb) {
- pCfg->map_cb.map_cfg_cb(pTLState->pMediaQ, pNVCfg->libCfgNames[i], pNVCfg->libCfgValues[i]);
- }
- else {
- AVB_LOGF_ERROR("No mapping module cfg function; ignoring %s", pNVCfg->libCfgNames[i]);
- }
- }
- else {
- assert(0);
- }
- } // for loop ends
-
- pTLState->cfg.map_cb.map_gen_init_cb(pTLState->pMediaQ);
- pTLState->cfg.intf_cb.intf_gen_init_cb(pTLState->pMediaQ);
-
- return TRUE;
-}
-
-EXTERN_DLL_EXPORT bool openavbTLRun(tl_handle_t handle)
-{
- bool retVal = FALSE;
-
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
-
- tl_state_t *pTLState = (tl_state_t *)handle;
-
- do {
- if (!pTLState) {
- AVB_LOG_ERROR("Invalid handle.");
- break;
- }
-
- pTLState->bRunning = TRUE;
- if (pTLState->cfg.role == AVB_ROLE_TALKER) {
- THREAD_CREATE_TALKER();
- }
- else if (pTLState->cfg.role == AVB_ROLE_LISTENER) {
- THREAD_CREATE_LISTENER();
- }
-
- retVal = TRUE;
-
- } while (0);
-
-
-
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return retVal;
-}
-
-extern DLL_EXPORT bool openavbTLStop(tl_handle_t handle)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
-
- tl_state_t *pTLState = (tl_state_t *)handle;
-
- if (!pTLState) {
- AVB_LOG_ERROR("Invalid handle.");
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return FALSE;
- }
-
- if (pTLState->bRunning) {
- // don't set bStreaming to false here, that's needed to track
- // that the streaming thread is running, so we can shut it down.
- //pTLState->bStreaming = FALSE;
- pTLState->bRunning = FALSE;
-
- THREAD_JOIN(pTLState->TLThread, NULL);
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return TRUE;
-}
-
-EXTERN_DLL_EXPORT bool openavbTLClose(tl_handle_t handle)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
-
- tl_state_t *pTLState = (tl_state_t *)handle;
-
- if (!pTLState) {
- AVB_LOG_ERROR("Invalid handle.");
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return FALSE;
- }
-
- if (pTLState->bRunning == TRUE) {
- // In case openavbTLStop wasn't called stop is now.
- openavbTLStop(handle);
- }
-
- pTLState->cfg.intf_cb.intf_gen_end_cb(pTLState->pMediaQ);
- pTLState->cfg.map_cb.map_gen_end_cb(pTLState->pMediaQ);
-
- TLHandleListRemove(handle);
-
- openavbTLUnconfigure(pTLState);
- openavbTLCloseLinkLibsOsal(pTLState);
-
- if (pTLState->pMediaQ) {
- openavbMediaQDelete(pTLState->pMediaQ);
- pTLState->pMediaQ = NULL;
- }
-
- // Free TLState
- free(pTLState);
- pTLState = NULL;
-
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return TRUE;
-}
-
-EXTERN_DLL_EXPORT void* openavbTLGetIntfHostCBList(tl_handle_t handle)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
-
- tl_state_t *pTLState = (tl_state_t *)handle;
-
- if (!pTLState) {
- AVB_LOG_ERROR("Invalid handle.");
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return FALSE;
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return pTLState->cfg.intf_cb.intf_host_cb_list;
-}
-
-EXTERN_DLL_EXPORT void* openavbTLGetIntfHandle(tl_handle_t handle)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
-
- tl_state_t *pTLState = (tl_state_t *)handle;
-
- if (!pTLState) {
- AVB_LOG_ERROR("Invalid handle.");
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return FALSE;
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return pTLState->pMediaQ;
-}
-
-EXTERN_DLL_EXPORT bool openavbTLIsRunning(tl_handle_t handle)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
-
- tl_state_t *pTLState = (tl_state_t *)handle;
-
- if (!pTLState) {
- AVB_LOG_ERROR("Invalid handle.");
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return FALSE;
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return pTLState->bRunning;
-}
-
-EXTERN_DLL_EXPORT bool openavbTLIsConnected(tl_handle_t handle)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
-
- tl_state_t *pTLState = (tl_state_t *)handle;
-
- if (!pTLState) {
- AVB_LOG_ERROR("Invalid handle.");
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return FALSE;
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return pTLState->bConnected;
-}
-
-EXTERN_DLL_EXPORT bool openavbTLIsStreaming(tl_handle_t handle)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
-
- tl_state_t *pTLState = (tl_state_t *)handle;
-
- if (!pTLState) {
- AVB_LOG_ERROR("Invalid handle.");
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return FALSE;
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return pTLState->bStreaming;
-}
-
-EXTERN_DLL_EXPORT avb_role_t openavbTLGetRole(tl_handle_t handle)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
-
- tl_state_t *pTLState = (tl_state_t *)handle;
-
- if (!pTLState) {
- AVB_LOG_ERROR("Invalid handle");
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return AVB_ROLE_UNDEFINED;
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return pTLState->cfg.role;
-}
-
-
-EXTERN_DLL_EXPORT U64 openavbTLStat(tl_handle_t handle, tl_stat_t stat)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
- U64 val = 0;
-
- tl_state_t *pTLState = (tl_state_t *)handle;
-
- if (!pTLState) {
- AVB_LOG_ERROR("Invalid handle");
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return 0;
- }
-
- if (pTLState->cfg.role == AVB_ROLE_TALKER) {
- val = openavbTalkerGetStat(pTLState, stat);
- }
- else if (pTLState->cfg.role == AVB_ROLE_LISTENER) {
- val = openavbListenerGetStat(pTLState, stat);
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return val;
-}
-
-EXTERN_DLL_EXPORT void openavbTLPauseStream(tl_handle_t handle, bool bPause)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
-
- tl_state_t *pTLState = (tl_state_t *)handle;
-
- if (!pTLState) {
- AVB_LOG_ERROR("Invalid handle.");
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return;
- }
-
- if (pTLState->cfg.role == AVB_ROLE_TALKER) {
- openavbTLPauseTalker(pTLState, bPause);
- }
- else if (pTLState->cfg.role == AVB_ROLE_LISTENER) {
- openavbTLPauseListener(pTLState, bPause);
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_TL);
-}
-
-
-
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+* MODULE SUMMARY : Common implementation for the talker and listener
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "openavb_tl.h"
+#include "openavb_trace.h"
+#include "openavb_mediaq.h"
+#include "openavb_talker.h"
+#include "openavb_listener.h"
+#include "openavb_avdecc_msg.h"
+#include "openavb_platform.h"
+
+#define AVB_LOG_COMPONENT "Talker / Listener"
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+U32 gMaxTL;
+tl_handle_t *gTLHandleList;
+
+// We are accessed from multiple threads, so need a mutex
+MUTEX_HANDLE(gTLStateMutex);
+
+#define MATCH(A, B)(strcasecmp((A), (B)) == 0)
+//#define MATCH_LEFT(A, B, C)(strncasecmp((A), (B), (C)) == 0)
+#define MATCH_LEFT(A, B, C) (memcmp((A), (B), (C)) == 0)
+
+THREAD_TYPE(listenerThread);
+THREAD_TYPE(talkerThread);
+
+void* openavbTLThreadFn(void *pv);
+#define THREAD_CREATE_TALKER() THREAD_CREATE(talkerThread, pTLState->TLThread, NULL, openavbTLThreadFn, pTLState)
+#define THREAD_CREATE_LISTENER() THREAD_CREATE(listenerThread, pTLState->TLThread, NULL, openavbTLThreadFn, pTLState)
+
+void* openavbAvdeccMsgThreadFn(void *pv);
+#define THREAD_CREATE_AVDECC_MSG() THREAD_CREATE(avdeccMsgThread, pTLState->avdeccMsgThread, NULL, openavbAvdeccMsgThreadFn, pTLState)
+
+void timespec_add_usec(struct timespec *t, unsigned long us)
+{
+ t->tv_nsec += us * NANOSECONDS_PER_USEC;
+ t->tv_sec += t->tv_nsec / NANOSECONDS_PER_SECOND;
+ t->tv_nsec = t->tv_nsec % NANOSECONDS_PER_SECOND;
+}
+
+void timespec_sub_usec(struct timespec *t, unsigned long us)
+{
+ t->tv_nsec -= us * NANOSECONDS_PER_USEC;
+ t->tv_sec += t->tv_nsec / NANOSECONDS_PER_SECOND;
+ t->tv_nsec = t->tv_nsec % NANOSECONDS_PER_SECOND;
+ if (t->tv_nsec < 0) {
+ t->tv_sec--;
+ t->tv_nsec = NANOSECONDS_PER_SECOND + t->tv_nsec;
+ }
+}
+
+unsigned long timespec_usec_diff(struct timespec *t1, struct timespec *t2)
+{
+ return (t1->tv_sec - t2->tv_sec) * MICROSECONDS_PER_SECOND
+ + (t1->tv_nsec - t2->tv_nsec) / NANOSECONDS_PER_USEC;
+}
+
+int timespec_cmp(struct timespec *a, struct timespec *b)
+{
+ if (a->tv_sec > b->tv_sec)
+ return 1;
+ else if (a->tv_sec < b->tv_sec)
+ return -1;
+ else {
+ if (a->tv_nsec > b->tv_nsec)
+ return 1;
+ else if (a->tv_nsec < b->tv_nsec)
+ return -1;
+ }
+ return 0;
+}
+
+static bool TLHandleListAdd(tl_handle_t handle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ if (!handle || !gTLHandleList) {
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return FALSE;
+ }
+
+ TL_LOCK();
+ int i1;
+ for (i1 = 0; i1 < gMaxTL; i1++) {
+ if (!gTLHandleList[i1]) {
+ gTLHandleList[i1] = handle;
+ TL_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return TRUE;
+ }
+ }
+ TL_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return FALSE;
+}
+
+bool TLHandleListRemove(tl_handle_t handle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ if (!handle || !gTLHandleList) {
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return FALSE;
+ }
+
+ TL_LOCK();
+ int i1;
+ for (i1 = 0; i1 < gMaxTL; i1++) {
+ if (gTLHandleList[i1] == handle) {
+ gTLHandleList[i1] = NULL;
+ TL_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return TRUE;
+ }
+ }
+ TL_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return FALSE;
+}
+
+static bool checkIntfCallbacks(openavb_tl_cfg_t *pCfg)
+{
+ bool validCfg = TRUE;
+
+ if (!pCfg->intf_cb.intf_cfg_cb) {
+ AVB_LOG_WARNING("INI file doesn't specify interface callback for '_cfg'.");
+ // validCfg = FALSE;
+ }
+ if ((pCfg->role == AVB_ROLE_TALKER) && !pCfg->intf_cb.intf_tx_init_cb) {
+ AVB_LOG_WARNING("INI file doesn't specify interface callback for '_tx_init'.");
+ // validCfg = FALSE;
+ }
+ if ((pCfg->role == AVB_ROLE_TALKER) && !pCfg->intf_cb.intf_tx_cb) {
+ AVB_LOG_ERROR("INI file doesn't specify interface callback for '_tx'.");
+ validCfg = FALSE;
+ }
+ if ((pCfg->role == AVB_ROLE_LISTENER) && !pCfg->intf_cb.intf_rx_init_cb) {
+ AVB_LOG_WARNING("INI file doesn't specify interface callback for '_rx_init'.");
+ // validCfg = FALSE;
+ }
+ if ((pCfg->role == AVB_ROLE_LISTENER) && !pCfg->intf_cb.intf_rx_cb) {
+ AVB_LOG_ERROR("INI file doesn't specify interface callback for '_rx'.");
+ validCfg = FALSE;
+ }
+ if (!pCfg->intf_cb.intf_end_cb) {
+ AVB_LOG_WARNING("INI file doesn't specify interface callback for '_end'.");
+ // validCfg = FALSE;
+ }
+ if (!pCfg->intf_cb.intf_gen_init_cb) {
+ AVB_LOG_WARNING("INI file doesn't specify interface callback for '_gen_init'.");
+ // validCfg = FALSE;
+ }
+ if (!pCfg->intf_cb.intf_gen_end_cb) {
+ AVB_LOG_WARNING("INI file doesn't specify interface callback for '_gen_end'.");
+ // validCfg = FALSE;
+ }
+
+ return validCfg;
+}
+
+static bool checkMapCallbacks(openavb_tl_cfg_t *pCfg)
+{
+ bool validCfg = TRUE;
+
+ if (!pCfg->map_cb.map_cfg_cb) {
+ AVB_LOG_WARNING("INI doesn't specify mapping callback for '_cfg'.");
+ // validCfg = FALSE;
+ }
+ if (!pCfg->map_cb.map_subtype_cb) {
+ AVB_LOG_WARNING("INI doesn't specify mapping callback for '_subtype'.");
+ // validCfg = FALSE;
+ }
+ if (!pCfg->map_cb.map_avtp_version_cb) {
+ AVB_LOG_WARNING("INI doesn't specify mapping callback for '_avtp_version'.");
+ // validCfg = FALSE;
+ }
+ if ((pCfg->role == AVB_ROLE_TALKER) && !pCfg->map_cb.map_tx_init_cb) {
+ AVB_LOG_WARNING("INI doesn't specify mapping callback for '_tx_init'.");
+ // validCfg = FALSE;
+ }
+ if ((pCfg->role == AVB_ROLE_TALKER) && !pCfg->map_cb.map_tx_cb) {
+ AVB_LOG_ERROR("INI doesn't specify mapping callback for '_tx'.");
+ validCfg = FALSE;
+ }
+ if ((pCfg->role == AVB_ROLE_LISTENER) && !pCfg->map_cb.map_rx_init_cb) {
+ AVB_LOG_WARNING("INI doesn't specify mapping callback for '_rx_init'.");
+ // validCfg = FALSE;
+ }
+ if ((pCfg->role == AVB_ROLE_LISTENER) && !pCfg->map_cb.map_rx_cb) {
+ AVB_LOG_ERROR("INI doesn't specify mapping callback for '_rx'.");
+ validCfg = FALSE;
+ }
+ if (!pCfg->map_cb.map_end_cb) {
+ AVB_LOG_WARNING("INI doesn't specify mapping callback for '_end'.");
+ // validCfg = FALSE;
+ }
+ if (!pCfg->map_cb.map_gen_init_cb) {
+ AVB_LOG_WARNING("INI doesn't specify mapping callback for '_gen_init'.");
+ // validCfg = FALSE;
+ }
+ if (!pCfg->map_cb.map_gen_end_cb) {
+ AVB_LOG_WARNING("INI doesn't specify mapping callback for '_gen_end'.");
+ // validCfg = FALSE;
+ }
+
+ return validCfg;
+}
+
+void openavbTLUnconfigure(tl_state_t *pTLState)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ // CORE_TODO: Disable this functionality until updated to properly handle distinction between values point to static const char
+ // and dynamically allocated strings.
+#if 0
+ openavb_tl_cfg_t *pCfg = &pTLState->cfg;
+
+ int i1;
+ for (i1 = 0; i1 < pCfg->nLibCfgItems; i1++) {
+ if (pCfg->libCfgNames[i1])
+ free(pCfg->libCfgNames[i1]);
+ if (pNVCfg->libCfgValues[i1])
+ free(pNVCfg->libCfgValues[i1]);
+ pCfg->libCfgNames[i1] = pNVCfg->libCfgValues[i1] = NULL;
+ }
+ pCfg->nLibCfgItems = 0;
+#endif
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+}
+
+
+/* Public APIs
+ */
+// General initizlization of the talker and listener library. Must be called prior to using any other TL APIs.
+EXTERN_DLL_EXPORT bool openavbTLInitialize(U32 maxTL)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+ LOG_EAVB_CORE_VERSION();
+
+ // CORE_TODO : This can be used to AVB stack init functionality once such a thing exists in the reference implementation
+ AVB_TIME_INIT();
+
+ gMaxTL = maxTL;
+
+ {
+ MUTEX_ATTR_HANDLE(mta);
+ MUTEX_ATTR_INIT(mta);
+ MUTEX_ATTR_SET_TYPE(mta, MUTEX_ATTR_TYPE_DEFAULT);
+ MUTEX_ATTR_SET_NAME(mta, "gTLStateMutex");
+ MUTEX_CREATE_ERR();
+ MUTEX_CREATE(gTLStateMutex, mta);
+ MUTEX_LOG_ERR("Error creating mutex");
+ }
+
+ gTLHandleList = calloc(1, sizeof(tl_handle_t) * gMaxTL);
+ if (gTLHandleList) {
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return TRUE;
+ }
+ else {
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return FALSE;
+ }
+}
+
+// General cleanup of the talker and listener library. Should be called after all Talker and Listeners are closed.
+EXTERN_DLL_EXPORT bool openavbTLCleanup()
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+ if (gTLHandleList) {
+ free(gTLHandleList);
+ gTLHandleList = NULL;
+ }
+ else {
+ return FALSE;
+ }
+
+ {
+ MUTEX_CREATE_ERR();
+ MUTEX_DESTROY(gTLStateMutex);
+ MUTEX_LOG_ERR("Error destroying mutex");
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return TRUE;
+}
+
+EXTERN_DLL_EXPORT bool openavbGetVersion(U8 *major, U8 *minor, U8 *revision)
+{
+ if (!major || !minor || !revision) {
+ return FALSE;
+ }
+
+ *major = AVB_CORE_VER_MAJOR;
+ *minor = AVB_CORE_VER_MINOR;
+ *revision = AVB_CORE_VER_REVISION;
+ return TRUE;
+}
+
+EXTERN_DLL_EXPORT tl_handle_t openavbTLOpen(void)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ tl_state_t *pTLState = calloc(1, sizeof(tl_state_t));
+ pTLState->avdeccMsgHandle = AVB_AVDECC_MSG_HANDLE_INVALID;
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Unable to allocate talker listener state data.");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return NULL;
+ }
+
+ if (!TLHandleListAdd(pTLState)) {
+ AVB_LOG_ERROR("To many talker listeners open.");
+ free(pTLState);
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return NULL;
+ }
+
+ return pTLState;
+}
+
+EXTERN_DLL_EXPORT void openavbTLInitCfg(openavb_tl_cfg_t *pCfg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ memset(pCfg, 0, sizeof(openavb_tl_cfg_t));
+
+ // Set default values.
+ // (These values should match those set in openavbIniCfgInit().)
+ pCfg->role = AVB_ROLE_UNDEFINED;
+ pCfg->initial_state = TL_INIT_STATE_UNSPECIFIED;
+ //pCfg->map_cb;
+ //pCfg->intf_cb;
+ //pCfg->dest_addr;
+ //pCfg->stream_addr;
+ pCfg->stream_uid = 0xFFFF;
+ pCfg->max_interval_frames = 1;
+ pCfg->max_frame_size = 1500;
+ pCfg->max_transit_usec = 50000;
+ pCfg->max_transmit_deficit_usec = 50000;
+ pCfg->internal_latency = 0;
+ pCfg->max_stale = MICROSECONDS_PER_SECOND;
+ pCfg->batch_factor = 1;
+ pCfg->report_seconds = 0;
+ pCfg->report_frames = 0;
+ pCfg->start_paused = FALSE;
+ pCfg->sr_class = SR_CLASS_B;
+ pCfg->sr_rank = SR_RANK_REGULAR;
+ pCfg->raw_tx_buffers = 8;
+ pCfg->raw_rx_buffers = 100;
+ pCfg->tx_blocking_in_intf = 0;
+ pCfg->rx_signal_mode = 1;
+ pCfg->pMapInitFn = NULL;
+ pCfg->pIntfInitFn = NULL;
+ pCfg->vlan_id = 0;
+ pCfg->fixed_timestamp = 0;
+ pCfg->spin_wait = FALSE;
+ pCfg->thread_rt_priority = 0;
+ pCfg->thread_affinity = 0xFFFFFFFF;
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+}
+
+EXTERN_DLL_EXPORT bool openavbTLConfigure(tl_handle_t handle, openavb_tl_cfg_t *pCfgIn, openavb_tl_cfg_name_value_t *pNVCfg)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ tl_state_t *pTLState = (tl_state_t *)handle;
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid handle.");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return FALSE;
+ }
+
+ // Create the mediaQ
+ pTLState->pMediaQ = openavbMediaQCreate();
+ if (!pTLState->pMediaQ) {
+ AVB_LOG_ERROR("Unable to create media queue");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return FALSE;
+ }
+
+ // CORE_TODO: It's not safe to simply copy the openavb_tl_cfg_t since there are embedded pointers in the cfg_mac_t member.
+ // Those pointers need to be updated after a copy. Longer term the cfg_mac_t should be changed to not contain the mac
+ // member to remedy this issue and avoid further bugs.
+ memcpy(&pTLState->cfg, pCfgIn, sizeof(openavb_tl_cfg_t));
+ pTLState->cfg.dest_addr.mac = &pTLState->cfg.dest_addr.buffer;
+ pTLState->cfg.stream_addr.mac = &pTLState->cfg.stream_addr.buffer;
+
+ openavb_tl_cfg_t *pCfg = &pTLState->cfg;
+
+ if (!((pCfg->role == AVB_ROLE_TALKER) || (pCfg->role == AVB_ROLE_LISTENER))) {
+ AVB_LOG_ERROR("Talker - Listener Config Error: invalid role");
+ return FALSE;
+ }
+
+ if ((pCfg->role == AVB_ROLE_TALKER) && (pCfg->max_interval_frames == 0)) {
+ AVB_LOG_ERROR("Talker - Listener Config Error: talker role requires 'max_interval_frames'");
+ return FALSE;
+ }
+
+ openavbMediaQSetMaxStaleTail(pTLState->pMediaQ, pCfg->max_stale);
+
+ if (!openavbTLOpenLinkLibsOsal(pTLState)) {
+ AVB_LOG_ERROR("Failed to open mapping / interface library");
+ return FALSE;
+ }
+
+ if (pCfg->pMapInitFn && pCfg->pMapInitFn(pTLState->pMediaQ, &pCfg->map_cb, pCfg->max_transit_usec)) {
+ checkMapCallbacks(&pTLState->cfg);
+ }
+ else {
+ AVB_LOG_ERROR("Mapping initialize function error.");
+ return FALSE;
+ }
+
+ if (pCfg->pIntfInitFn && pCfg->pIntfInitFn(pTLState->pMediaQ, &pCfg->intf_cb)) {
+ checkIntfCallbacks(&pTLState->cfg);
+ }
+ else {
+ AVB_LOG_ERROR("Interface initialize function error.");
+ return FALSE;
+ }
+
+ // Submit configuration values to mapping and interface modules
+ int i;
+ for (i = 0; i < pNVCfg->nLibCfgItems; i++) {
+ if (MATCH_LEFT(pNVCfg->libCfgNames[i], "intf_nv_", 8)) {
+ if (pCfg->intf_cb.intf_cfg_cb) {
+ pCfg->intf_cb.intf_cfg_cb(pTLState->pMediaQ, pNVCfg->libCfgNames[i], pNVCfg->libCfgValues[i]);
+ }
+ else {
+ AVB_LOGF_ERROR("No interface module cfg function; ignoring %s", pNVCfg->libCfgNames[i]);
+ }
+ }
+ else if (MATCH_LEFT(pNVCfg->libCfgNames[i], "map_nv_", 7)) {
+ if (pCfg->map_cb.map_cfg_cb) {
+ pCfg->map_cb.map_cfg_cb(pTLState->pMediaQ, pNVCfg->libCfgNames[i], pNVCfg->libCfgValues[i]);
+ }
+ else {
+ AVB_LOGF_ERROR("No mapping module cfg function; ignoring %s", pNVCfg->libCfgNames[i]);
+ }
+ }
+ else {
+ assert(0);
+ }
+ } // for loop ends
+
+ pTLState->cfg.map_cb.map_gen_init_cb(pTLState->pMediaQ);
+ pTLState->cfg.intf_cb.intf_gen_init_cb(pTLState->pMediaQ);
+
+ // Initialize the AVDECC support for this Talker/Listener.
+ pTLState->bAvdeccMsgRunning = TRUE;
+ THREAD_CREATE_AVDECC_MSG();
+
+ return TRUE;
+}
+
+EXTERN_DLL_EXPORT bool openavbTLRun(tl_handle_t handle)
+{
+ bool retVal = FALSE;
+
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ tl_state_t *pTLState = (tl_state_t *)handle;
+
+ do {
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid handle.");
+ break;
+ }
+
+ pTLState->bRunning = TRUE;
+ pTLState->bPaused = FALSE;
+ if (pTLState->cfg.role == AVB_ROLE_TALKER) {
+ THREAD_CREATE_TALKER();
+
+ if (pTLState->cfg.thread_rt_priority != 0) { THREAD_SET_RT_PRIORITY(pTLState->TLThread, pTLState->cfg.thread_rt_priority); }
+ if (pTLState->cfg.thread_affinity != 0xFFFFFFFF) { THREAD_PIN(pTLState->TLThread, pTLState->cfg.thread_affinity); }
+ }
+ else if (pTLState->cfg.role == AVB_ROLE_LISTENER) {
+ THREAD_CREATE_LISTENER();
+
+ if (pTLState->cfg.thread_rt_priority != 0) { THREAD_SET_RT_PRIORITY(pTLState->TLThread, pTLState->cfg.thread_rt_priority); }
+ if (pTLState->cfg.thread_affinity != 0xFFFFFFFF) { THREAD_PIN(pTLState->TLThread, pTLState->cfg.thread_affinity); }
+ }
+
+ retVal = TRUE;
+
+ } while (0);
+
+
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return retVal;
+}
+
+extern DLL_EXPORT bool openavbTLStop(tl_handle_t handle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ tl_state_t *pTLState = (tl_state_t *)handle;
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid handle.");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return FALSE;
+ }
+
+ pTLState->bPaused = FALSE;
+ if (pTLState->bRunning) {
+ // don't set bStreaming to false here, that's needed to track
+ // that the streaming thread is running, so we can shut it down.
+ //pTLState->bStreaming = FALSE;
+ pTLState->bRunning = FALSE;
+
+ THREAD_JOIN(pTLState->TLThread, NULL);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return TRUE;
+}
+
+EXTERN_DLL_EXPORT bool openavbTLClose(tl_handle_t handle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ tl_state_t *pTLState = (tl_state_t *)handle;
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid handle.");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return FALSE;
+ }
+
+ if (pTLState->bRunning == TRUE) {
+ // In case openavbTLStop wasn't called stop is now.
+ openavbTLStop(handle);
+ }
+
+ // Done with the AVDECC support.
+ if (pTLState->bAvdeccMsgRunning) {
+ pTLState->bAvdeccMsgRunning = FALSE;
+ THREAD_JOIN(pTLState->avdeccMsgThread, NULL);
+ }
+
+ pTLState->cfg.intf_cb.intf_gen_end_cb(pTLState->pMediaQ);
+ pTLState->cfg.map_cb.map_gen_end_cb(pTLState->pMediaQ);
+
+ TLHandleListRemove(handle);
+
+ openavbTLUnconfigure(pTLState);
+ openavbTLCloseLinkLibsOsal(pTLState);
+
+ if (pTLState->pMediaQ) {
+ openavbMediaQDelete(pTLState->pMediaQ);
+ pTLState->pMediaQ = NULL;
+ }
+
+ // Free TLState
+ free(pTLState);
+ pTLState = NULL;
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return TRUE;
+}
+
+EXTERN_DLL_EXPORT void* openavbTLGetIntfHostCBList(tl_handle_t handle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ tl_state_t *pTLState = (tl_state_t *)handle;
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid handle.");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return pTLState->cfg.intf_cb.intf_host_cb_list;
+}
+
+EXTERN_DLL_EXPORT void* openavbTLGetIntfHandle(tl_handle_t handle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ tl_state_t *pTLState = (tl_state_t *)handle;
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid handle.");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return pTLState->pMediaQ;
+}
+
+EXTERN_DLL_EXPORT bool openavbTLIsRunning(tl_handle_t handle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ tl_state_t *pTLState = (tl_state_t *)handle;
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid handle.");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return pTLState->bRunning;
+}
+
+EXTERN_DLL_EXPORT bool openavbTLIsConnected(tl_handle_t handle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ tl_state_t *pTLState = (tl_state_t *)handle;
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid handle.");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return pTLState->bConnected;
+}
+
+EXTERN_DLL_EXPORT bool openavbTLIsStreaming(tl_handle_t handle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ tl_state_t *pTLState = (tl_state_t *)handle;
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid handle.");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return FALSE;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return pTLState->bStreaming;
+}
+
+EXTERN_DLL_EXPORT avb_role_t openavbTLGetRole(tl_handle_t handle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ tl_state_t *pTLState = (tl_state_t *)handle;
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid handle");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return AVB_ROLE_UNDEFINED;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return pTLState->cfg.role;
+}
+
+EXTERN_DLL_EXPORT tl_init_state_t openavbTLGetInitialState(tl_handle_t handle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ tl_state_t *pTLState = (tl_state_t *)handle;
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid handle");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return TL_INIT_STATE_UNSPECIFIED;
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return pTLState->cfg.initial_state;
+}
+
+EXTERN_DLL_EXPORT U64 openavbTLStat(tl_handle_t handle, tl_stat_t stat)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+ U64 val = 0;
+
+ tl_state_t *pTLState = (tl_state_t *)handle;
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid handle");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return 0;
+ }
+
+ if (pTLState->cfg.role == AVB_ROLE_TALKER) {
+ val = openavbTalkerGetStat(pTLState, stat);
+ }
+ else if (pTLState->cfg.role == AVB_ROLE_LISTENER) {
+ val = openavbListenerGetStat(pTLState, stat);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return val;
+}
+
+EXTERN_DLL_EXPORT void openavbTLPauseStream(tl_handle_t handle, bool bPause)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ tl_state_t *pTLState = (tl_state_t *)handle;
+
+ if (!pTLState) {
+ AVB_LOG_ERROR("Invalid handle.");
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return;
+ }
+
+ if (pTLState->cfg.role == AVB_ROLE_TALKER) {
+ openavbTLPauseTalker(pTLState, bPause);
+ }
+ else if (pTLState->cfg.role == AVB_ROLE_LISTENER) {
+ openavbTLPauseListener(pTLState, bPause);
+ }
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+}
+
+
+
diff --git a/lib/avtp_pipeline/tl/openavb_tl.h b/lib/avtp_pipeline/tl/openavb_tl.h
index 82f38417..4b16da4b 100755
--- a/lib/avtp_pipeline/tl/openavb_tl.h
+++ b/lib/avtp_pipeline/tl/openavb_tl.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -55,11 +56,15 @@ typedef struct {
} talker_stats_t;
THREAD_TYPE(TLThread);
+THREAD_TYPE(avdeccMsgThread);
typedef struct {
// Running flag. (assumed atomic)
bool bRunning;
+ // Paused while Running flag. (assumed atomic)
+ bool bPaused;
+
// Connected to endpoint flag. (assumed atomic)
bool bConnected;
@@ -87,6 +92,15 @@ typedef struct {
// Thread for talker or listener
THREAD_DEFINITON(TLThread);
+ // AVDECC Msg Running flag. (assumed atomic)
+ bool bAvdeccMsgRunning;
+
+ // Thread for AVDECC Msg support
+ THREAD_DEFINITON(avdeccMsgThread);
+
+ // Handle to the AVDECC Msg support. (Value set by avdeccMsgThread)
+ int avdeccMsgHandle;
+
// Per stream Stats Mutex
MUTEX_HANDLE(statsMutex);
@@ -120,7 +134,7 @@ unsigned long timespec_usec_diff(struct timespec *t1, struct timespec *t2);
int timespec_cmp(struct timespec *a, struct timespec *b);
////////////////
-// TL Handle List functions. The TL handle list is created in the implemntation of openavbTLInitialize.
+// TL Handle List functions. The TL handle list is created in the implementation of openavbTLInitialize.
////////////////
// Get a tl_handle_t from the TLHandleList given an endpointHandle.
extern U32 gMaxTL;
@@ -135,21 +149,6 @@ bool TLHandleRemove(tl_handle_t handle);
////////////////
-// AVDECC Integration functions.
-////////////////
-// Run a single talker or listener. At this point data can be sent or recieved. Used in place of the public openavbTLRun
-bool openavbTLAVDECCRunListener(tl_handle_t handle, U16 configIdx, U16 descriptorType, U16 descriptorIdx, void *pVoidListenerStreamInfo);
-bool openavbTLAVDECCRunTalker(tl_handle_t handle, U16 configIdx, U16 descriptorType, U16 descriptorIdx, void *pVoidTalkerStreamInfo);
-
-// Stop a single talker or listener. At this point data will not be sent or recieved. Used in place of the public openavbTLStop.
-bool openavbTLAVDECCStopListener(tl_handle_t handle, U16 configIdx, void *pVoidListenerStreamInfo);
-bool openavbTLAVDECCStopTalker(tl_handle_t handle, U16 configIdx, void *pVoidTalkerStreamInfo);
-
-// Get talker stream details. Structure members in TalkerStrreamInfo will be filled.
-bool openavbTLAVDECCGetTalkerStreamInfo(tl_handle_t handle, U16 configIdx, void *pVoidTalkerStreamInfo);
-
-
-////////////////
// OSAL implementation functions
////////////////
bool openavbTLThreadFnOsal(tl_state_t *pTLState);
diff --git a/lib/avtp_pipeline/tl/openavb_tl_endpoint.c b/lib/avtp_pipeline/tl/openavb_tl_endpoint.c
index d6a4ad13..49c9420b 100644
--- a/lib/avtp_pipeline/tl/openavb_tl_endpoint.c
+++ b/lib/avtp_pipeline/tl/openavb_tl_endpoint.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -117,7 +118,7 @@ void* openavbTLThreadFn(void *pv)
}
if (pTLState->bRunning) {
- SLEEP(1);
+ SLEEP_MSEC(1);
}
}
@@ -153,126 +154,3 @@ tl_handle_t TLHandleListGet(int endpointHandle)
AVB_TRACE_EXIT(AVB_TRACE_TL);
return NULL;
}
-
-#ifdef AVTP_PIPELINE_AVDECC
-bool openavbTLAVDECCRunListener(tl_handle_t handle, U16 configIdx, U16 descriptorType, U16 descriptorIdx, void *pVoidListenerStreamInfo)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
-
- if (!handle) {
- AVB_LOG_ERROR("Invalid handle.");
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return FALSE;
- }
-
- if (!pVoidListenerStreamInfo) {
- AVB_LOG_ERROR("Invalid argument");
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return FALSE;
- }
-
- openavb_acmp_ListenerStreamInfo_t *pListenerStreamInfo = pVoidListenerStreamInfo;
- tl_state_t *pTLState = (tl_state_t *)handle;
-
- memcpy(pTLState->cfg.dest_addr.mac->ether_addr_octet, pListenerStreamInfo->stream_dest_mac, ETH_ALEN);
- memcpy(pTLState->cfg.stream_addr.mac->ether_addr_octet, pListenerStreamInfo->stream_id, ETH_ALEN);
- U8 *pStreamUID = pListenerStreamInfo->stream_id + 6;
-// pTLState->cfg.stream_uid = ntohs(*(U16 *)(pStreamUID));
- U16 align16;
- memcpy(&align16, (U16 *)(pStreamUID), sizeof(U16));
- pTLState->cfg.stream_uid = ntohs(align16);
-
- if (pTLState->cfg.intf_cb.intf_avdecc_init_cb) {
- pTLState->cfg.intf_cb.intf_avdecc_init_cb(pTLState->pMediaQ, configIdx, descriptorType, descriptorIdx);
- }
- if (pTLState->cfg.map_cb.map_avdecc_init_cb) {
- pTLState->cfg.map_cb.map_avdecc_init_cb(pTLState->pMediaQ, configIdx, descriptorType, descriptorIdx);
- }
-
- openavbTLRun(handle);
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return TRUE;
-}
-
-bool openavbTLAVDECCRunTalker(tl_handle_t handle, U16 configIdx, U16 descriptorType, U16 descriptorIdx, void *pVoidTalkerStreamInfo)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
-
- if (!handle) {
- AVB_LOG_ERROR("Invalid handle.");
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return FALSE;
- }
-
- tl_state_t *pTLState = (tl_state_t *)handle;
-
- if (pTLState->cfg.intf_cb.intf_avdecc_init_cb) {
- pTLState->cfg.intf_cb.intf_avdecc_init_cb(pTLState->pMediaQ, configIdx, descriptorType, descriptorIdx);
- }
- if (pTLState->cfg.map_cb.map_avdecc_init_cb) {
- pTLState->cfg.map_cb.map_avdecc_init_cb(pTLState->pMediaQ, configIdx, descriptorType, descriptorIdx);
- }
-
- if (!openavbTLIsRunning(handle)) {
- openavbTLRun(handle);
- }
-
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return TRUE;
-}
-
-bool openavbTLAVDECCStopListener(tl_handle_t handle, U16 configIdx, void *pVoidListenerStreamInfo)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
-
- openavbTLStop(handle);
-
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return TRUE;
-}
-
-bool openavbTLAVDECCStopTalker(tl_handle_t handle, U16 configIdx, void *pVoidTalkerStreamInfo)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
-
- openavbTLStop(handle);
-
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return TRUE;
-}
-
-// CORE_TODO: Consider having this functionality live in openavb_talker.c and then talker_data_t can again be private to openavb_talker.c
-bool openavbTLAVDECCGetTalkerStreamInfo(tl_handle_t handle, U16 configIdx, void *pVoidTalkerStreamInfo)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
-
- if (!handle) {
- AVB_LOG_ERROR("Invalid handle.");
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return FALSE;
- }
-
- if (!pVoidTalkerStreamInfo) {
- AVB_LOG_ERROR("Invalid argument");
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return FALSE;
- }
-
- openavb_acmp_TalkerStreamInfo_t *pTalkerStreamInfo = pVoidTalkerStreamInfo;
- tl_state_t *pTLState = (tl_state_t *)handle;
-
- talker_data_t *pTalkerData = pTLState->pPvtTalkerData;
-
- // Get the destination mac address.
- memcpy(pTalkerStreamInfo->stream_dest_mac, pTalkerData->destAddr, ETH_ALEN);
-
- // Get the stream ID
- memcpy(pTalkerStreamInfo->stream_id, pTalkerData->streamID.addr, ETH_ALEN);
- U8 *pStreamUID = pTalkerStreamInfo->stream_id + 6;
- *(U16 *)(pStreamUID) = htons(pTLState->cfg.stream_uid);
-
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return TRUE;
-}
-
-#endif //AVTP_PIPELINE_AVDECC
diff --git a/lib/avtp_pipeline/tl/openavb_tl_no_endpoint.c b/lib/avtp_pipeline/tl/openavb_tl_no_endpoint.c
index 85173d2c..5068fc0f 100644
--- a/lib/avtp_pipeline/tl/openavb_tl_no_endpoint.c
+++ b/lib/avtp_pipeline/tl/openavb_tl_no_endpoint.c
@@ -1,134 +1,135 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-/*
-* MODULE SUMMARY : Common implementation for the talker and listener
-*/
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include "openavb_tl.h"
-#include "openavb_trace.h"
-//#include "openavb_mediaq.h"
-#include "openavb_talker.h"
-#include "openavb_listener.h"
-#include "openavb_avtp.h"
-#include "openavb_endpoint.h"
-
-#include "openavb_platform.h"
-
-#define AVB_LOG_COMPONENT "Talker / Listener"
-#include "openavb_pub.h"
-#include "openavb_log.h"
-
-void openavbEptClntCheckVerMatchesSrvr(int endpointHandle, U32 AVBVersion)
-{
-}
-
-
-// Talker Listener thread function
-void* openavbTLThreadFn(void *pv)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
-
- tl_state_t *pTLState = (tl_state_t *)pv;
-
- openavbTLThreadFnOsal(pTLState);
-
- TL_LOCK();
- // Assign a unique endpoint handle
- static int gEndpointHandle = 1;
- pTLState->endpointHandle = gEndpointHandle++;
- TL_UNLOCK();
-
- while (pTLState->bRunning) {
- AVB_TRACE_LINE(AVB_TRACE_TL_DETAIL);
-
- if (pTLState->cfg.role == AVB_ROLE_TALKER) {
- openavbTLRunTalker(pTLState);
- }
- else {
- openavbTLRunListener(pTLState);
- }
-
- // Close the endpoint connection. unless connection already gone in which case the socket could already be reused.
- if (pTLState->bConnected) {
- pTLState->bConnected = FALSE;
- pTLState->endpointHandle = 0;
- }
-
- if (pTLState->bRunning) {
- SLEEP(1);
- }
- }
-
- THREAD_JOINABLE(pTLState->TLThread);
-
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return NULL;
-}
-
-tl_handle_t TLHandleListGet(int endpointHandle)
-{
- AVB_TRACE_ENTRY(AVB_TRACE_TL);
-
- if (!endpointHandle || !gTLHandleList) {
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return NULL;
- }
-
- TL_LOCK();
- int i1;
- for (i1 = 0; i1 < gMaxTL; i1++) {
- if (gTLHandleList[i1]) {
- tl_state_t *pTLState = (tl_state_t *)gTLHandleList[i1];
- if (pTLState->endpointHandle == endpointHandle) {
- TL_UNLOCK();
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return pTLState;
- }
- }
- }
- TL_UNLOCK();
- AVB_TRACE_EXIT(AVB_TRACE_TL);
- return NULL;
-}
-
-bool openavbEptClntStopStream(int h, AVBStreamID_t *streamID)
-{
- return TRUE;
-}
-
-bool openavbEptClntService(int h, int timeout)
-{
- return TRUE;
-}
-
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+/*
+* MODULE SUMMARY : Common implementation for the talker and listener
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "openavb_tl.h"
+#include "openavb_trace.h"
+//#include "openavb_mediaq.h"
+#include "openavb_talker.h"
+#include "openavb_listener.h"
+#include "openavb_avtp.h"
+#include "openavb_endpoint.h"
+
+#include "openavb_platform.h"
+
+#define AVB_LOG_COMPONENT "Talker / Listener"
+#include "openavb_pub.h"
+#include "openavb_log.h"
+
+void openavbEptClntCheckVerMatchesSrvr(int endpointHandle, U32 AVBVersion)
+{
+}
+
+
+// Talker Listener thread function
+void* openavbTLThreadFn(void *pv)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ tl_state_t *pTLState = (tl_state_t *)pv;
+
+ openavbTLThreadFnOsal(pTLState);
+
+ TL_LOCK();
+ // Assign a unique endpoint handle
+ static int gEndpointHandle = 1;
+ pTLState->endpointHandle = gEndpointHandle++;
+ TL_UNLOCK();
+
+ while (pTLState->bRunning) {
+ AVB_TRACE_LINE(AVB_TRACE_TL_DETAIL);
+
+ if (pTLState->cfg.role == AVB_ROLE_TALKER) {
+ openavbTLRunTalker(pTLState);
+ }
+ else {
+ openavbTLRunListener(pTLState);
+ }
+
+ // Close the endpoint connection. unless connection already gone in which case the socket could already be reused.
+ if (pTLState->bConnected) {
+ pTLState->bConnected = FALSE;
+ pTLState->endpointHandle = 0;
+ }
+
+ if (pTLState->bRunning) {
+ SLEEP_MSEC(1);
+ }
+ }
+
+ THREAD_JOINABLE(pTLState->TLThread);
+
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return NULL;
+}
+
+tl_handle_t TLHandleListGet(int endpointHandle)
+{
+ AVB_TRACE_ENTRY(AVB_TRACE_TL);
+
+ if (!endpointHandle || !gTLHandleList) {
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return NULL;
+ }
+
+ TL_LOCK();
+ int i1;
+ for (i1 = 0; i1 < gMaxTL; i1++) {
+ if (gTLHandleList[i1]) {
+ tl_state_t *pTLState = (tl_state_t *)gTLHandleList[i1];
+ if (pTLState->endpointHandle == endpointHandle) {
+ TL_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return pTLState;
+ }
+ }
+ }
+ TL_UNLOCK();
+ AVB_TRACE_EXIT(AVB_TRACE_TL);
+ return NULL;
+}
+
+bool openavbEptClntStopStream(int h, AVBStreamID_t *streamID)
+{
+ return TRUE;
+}
+
+bool openavbEptClntService(int h, int timeout)
+{
+ return TRUE;
+}
+
diff --git a/lib/avtp_pipeline/tl/openavb_tl_pub.h b/lib/avtp_pipeline/tl/openavb_tl_pub.h
index 6e46494b..d89729a1 100755
--- a/lib/avtp_pipeline/tl/openavb_tl_pub.h
+++ b/lib/avtp_pipeline/tl/openavb_tl_pub.h
@@ -1,16 +1,17 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
-
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-
+
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
-
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -21,10 +22,10 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
*************************************************************************************************************/
@@ -75,23 +76,35 @@ typedef enum {
/// Maximum size of interface name
#define IFNAMSIZE 16
-/// Indicatates that VLAN ID is not set in configuration
-#define VLAN_NULL UINT16_MAX
+/// Maximum size of the friendly name
+#define FRIENDLY_NAME_SIZE 64
+
+/// Initial talker/listener state
+typedef enum {
+ /// Unspecified
+ TL_INIT_STATE_UNSPECIFIED,
+ /// Stopped
+ TL_INIT_STATE_STOPPED,
+ /// Running
+ TL_INIT_STATE_RUNNING,
+} tl_init_state_t;
/// Structure containing configuration of the host
typedef struct {
/// Role of the host
avb_role_t role;
+ /// Initial Talker/Listener state
+ tl_init_state_t initial_state;
/// Structure with callbacks to mapping
openavb_map_cb_t map_cb;
- /// Structure with callbacks to inteface
+ /// Structure with callbacks to interface
openavb_intf_cb_t intf_cb;
/// MAC address of destination - multicast (talker only if SRP is enabled)
cfg_mac_t dest_addr;
/// MAC address of the source
cfg_mac_t stream_addr;
/// Stream UID (has to be unique)
- S32 stream_uid;
+ U16 stream_uid;
/// Maximum number of packets sent during one interval (talker only)
U32 max_interval_frames;
/// Maximum size of the frame
@@ -111,15 +124,17 @@ typedef struct {
U32 batch_factor;
/// Statistics reporting frequency
U32 report_seconds;
+ /// Statistics reporting frequency in frames
+ U32 report_frames;
/// Start paused
bool start_paused;
- /// Class in which host will operatea ::SRClassIdx_t (talker only)
+ /// Class in which host will operate ::SRClassIdx_t (talker only)
U8 sr_class;
/// Rank of the stream #SR_RANK_REGULAR or #SR_RANK_EMERGENCY (talker only)
U8 sr_rank;
/// Number of raw TX buffers that should be used (talker only)
U32 raw_tx_buffers;
- /// Number of raw rx buffers (listener only)
+ /// Number of raw RX buffers (listener only)
U32 raw_rx_buffers;
/// Is the interface module blocking in the TX CB.
bool tx_blocking_in_intf;
@@ -129,11 +144,37 @@ typedef struct {
U16 vlan_id;
/// When set incoming packets will trigger a signal to the stream task to wakeup.
bool rx_signal_mode;
+ /// Enable fixed timestamping in interface
+ U32 fixed_timestamp;
+ /// Wait for next observation interval by spinning rather than sleeping
+ bool spin_wait;
+ /// Bit mask used for CPU pinning
+ U32 thread_affinity;
+ /// Real time priority of thread.
+ U32 thread_rt_priority;
+ /// Friendly name for this configuration
+ char friendly_name[FRIENDLY_NAME_SIZE];
/// Initialization function in mapper
openavb_map_initialize_fn_t pMapInitFn;
/// Initialization function in interface
openavb_intf_initialize_fn_t pIntfInitFn;
+
+ /// TRUE if backup_stream_addr and backup_stream_uid are valid.
+ bool backup_stream_id_valid;
+ /// Saved original MAC address of the source
+ U8 backup_stream_addr[ETH_ALEN];
+ /// Stream UID (has to be unique)
+ U16 backup_stream_uid;
+ /// TRUE if backup_dest_addr_valid is valid.
+ bool backup_dest_addr_valid;
+ /// Saved original MAC address of destination - multicast (talker only if SRP is enabled)
+ U8 backup_dest_addr[ETH_ALEN];
+ /// TRUE if backup_vlan_id_valid is valid.
+ bool backup_vlan_id_valid;
+ /// Saved original VLAN ID
+ U16 backup_vlan_id;
+
} openavb_tl_cfg_t;
/// Structure holding configuration of mapping and interface modules
@@ -144,7 +185,7 @@ typedef struct openavb_tl_cfg_name_value_t {
char *libCfgValues[MAX_LIB_CFG_ITEMS];
/// Number of configuration parameters defined
U32 nLibCfgItems;
-} openavb_tl_cfg_name_value_t;
+} openavb_tl_cfg_name_value_t;
/** Initialize the talker listener library.
@@ -202,8 +243,8 @@ void openavbTLInitCfg(openavb_tl_cfg_t *pCfg);
* structure and name value pairs
*
* \param handle Handle of talker/listener
- * \param pCfg Pointer to configuration structure
- * \param pNVCfg Pointer to name value pair configuration
+ * \param pCfg Pointer to configuration structure
+ * \param pNVCfg Pointer to name value pair configuration
* structure
* \return TRUE on success or FALSE on failure
*/
@@ -314,6 +355,13 @@ bool openavbTLIsStreaming(tl_handle_t handle);
*/
avb_role_t openavbTLGetRole(tl_handle_t handle);
+/** Return the specified initial state of the talker or listener.
+ *
+ * \param handle The handle return from openavbTLOpen()
+ * \return The initial state requested
+ */
+tl_init_state_t openavbTLGetInitialState(tl_handle_t handle);
+
/** Allows pulling current stat counters for a running stream.
*
* The various stat counters for a stream can be retrieved with this function
@@ -324,15 +372,15 @@ avb_role_t openavbTLGetRole(tl_handle_t handle);
*/
U64 openavbTLStat(tl_handle_t handle, tl_stat_t stat);
-/** Read an ini file.
+/** Read an ini file.
*
* Parses an input configuration file tp populate configuration structures, and
* name value pairs. Only used in Operating Systems that have a file system
*
* \param TLhandle Pointer to handle of talker/listener
* \param fileName Pointer to configuration file name
- * \param pCfg Pointer to configuration structure
- * \param pNVCfg Pointer to name value pair configuration
+ * \param pCfg Pointer to configuration structure
+ * \param pNVCfg Pointer to name value pair configuration
* structure
* \return TRUE on success or FALSE on failure
*
diff --git a/lib/avtp_pipeline/util/CMakeLists.txt b/lib/avtp_pipeline/util/CMakeLists.txt
index 3e87f341..f51c0b40 100644
--- a/lib/avtp_pipeline/util/CMakeLists.txt
+++ b/lib/avtp_pipeline/util/CMakeLists.txt
@@ -7,6 +7,7 @@ SET (SRC_FILES ${SRC_FILES}
${AVB_SRC_DIR}/util/openavb_log.c
${AVB_SRC_DIR}/util/openavb_queue.c
${AVB_SRC_DIR}/util/openavb_time.c
+ ${AVB_OSAL_DIR}/openavb_time_osal.c
${AVB_SRC_DIR}/util/openavb_timestamp.c
${AVB_SRC_DIR}/util/openavb_printbuf.c
PARENT_SCOPE
diff --git a/lib/avtp_pipeline/util/openavb_array.c b/lib/avtp_pipeline/util/openavb_array.c
index ffebeba8..32ce1446 100644
--- a/lib/avtp_pipeline/util/openavb_array.c
+++ b/lib/avtp_pipeline/util/openavb_array.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/util/openavb_array.h b/lib/avtp_pipeline/util/openavb_array.h
index ba55a5b8..2a83dc8d 100644
--- a/lib/avtp_pipeline/util/openavb_array.h
+++ b/lib/avtp_pipeline/util/openavb_array.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/util/openavb_debug.c b/lib/avtp_pipeline/util/openavb_debug.c
index 42ebb977..cef411c1 100644
--- a/lib/avtp_pipeline/util/openavb_debug.c
+++ b/lib/avtp_pipeline/util/openavb_debug.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/util/openavb_debug.h b/lib/avtp_pipeline/util/openavb_debug.h
index b3c7b439..dba309c7 100644
--- a/lib/avtp_pipeline/util/openavb_debug.h
+++ b/lib/avtp_pipeline/util/openavb_debug.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/util/openavb_list.c b/lib/avtp_pipeline/util/openavb_list.c
index 9f36d819..7d045dba 100644
--- a/lib/avtp_pipeline/util/openavb_list.c
+++ b/lib/avtp_pipeline/util/openavb_list.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/util/openavb_list.h b/lib/avtp_pipeline/util/openavb_list.h
index 0d974abb..15826464 100644
--- a/lib/avtp_pipeline/util/openavb_list.h
+++ b/lib/avtp_pipeline/util/openavb_list.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -48,37 +49,37 @@ openavb_list_t openavbListNewList(void);
// Delete a link list.
void openavbListDeleteList(openavb_list_t list);
-// Add a data element as a node to a link list. Returns NULL on failure.
+// Add a data element as a node to the end (tail) of a link list. Returns NULL on failure.
openavb_list_node_t openavbListAdd(openavb_list_t list, void *data);
-// Allocate and manage data element and add as a node to a link list. Returns NULL on failure.
+// Allocate and manage data element and add as a node to the end (tail) of a link list. Returns NULL on failure.
openavb_list_node_t openavbListNew(openavb_list_t list, U32 size);
// Remove (delete) node. Returns NULL on failure otherwise next node.
openavb_list_node_t openavbListDelete(openavb_list_t list, openavb_list_node_t node);
-// Gets the next node. Returns FALSE on error or if already at the tail.
+// Gets the next node. Returns NULL on error or if already at the tail.
openavb_list_node_t openavbListNext(openavb_list_t list, openavb_list_node_t node);
-// Gets the previous node. Returns FALSE on error or if already at the head.
+// Gets the previous node. Returns NULL on error or if already at the head.
openavb_list_node_t openavbListPrev(openavb_list_t list, openavb_list_node_t node);
-// Gets the first (head) node. Returns FALSE on error or empty list.
+// Gets the first (head) node. Returns NULL on error or empty list.
openavb_list_node_t openavbListFirst(openavb_list_t list);
-// Gets the lastt (tail) node. Returns FALSE on error or empty list.
+// Gets the last (tail) node. Returns NULL on error or empty list.
openavb_list_node_t openavbListLast(openavb_list_t list);
-// Gets the first node and preps for iteration. Returns FALSE on error or empty list.
+// Gets the first node and preps for iteration. Returns NULL on error or empty list.
openavb_list_node_t openavbListIterFirst(openavb_list_t list);
-// Gets the last node and preps for iteration. Returns FALSE on error or empty list.
+// Gets the last node and preps for iteration. Returns NULL on error or empty list.
openavb_list_node_t openavbListIterLast(openavb_list_t list);
-// Gets the next node in the iteration. Returns FALSE on error or end of list.
+// Gets the next node in the iteration. Returns NULL on error or end of list.
openavb_list_node_t openavbListIterNext(openavb_list_t list);
-// Gets the prev node in the iteration. Returns FALSE on error or beginning of list.
+// Gets the previous node in the iteration. Returns NULL on error or beginning of list.
openavb_list_node_t openavbListIterPrev(openavb_list_t list);
// Get data element. Returns NULL on failure.
diff --git a/lib/avtp_pipeline/util/openavb_log.c b/lib/avtp_pipeline/util/openavb_log.c
index a0c937c4..5d32843f 100644
--- a/lib/avtp_pipeline/util/openavb_log.c
+++ b/lib/avtp_pipeline/util/openavb_log.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -61,6 +62,7 @@ typedef struct {
static openavb_queue_t logQueue;
static openavb_queue_t logRTQueue;
+static FILE *logOutputFd = NULL;
static char msg[LOG_MSG_LEN] = "";
static char time_msg[LOG_TIME_LEN] = "";
@@ -96,35 +98,35 @@ void avbLogRTRender(log_queue_item_t *pLogItem)
strcat((char *)pLogItem->msg, pLogRTItem->pFormat);
break;
case LOG_RT_DATATYPE_NOW_TS:
- sprintf(rt_msg, "[%lu:%09lu] ", pLogRTItem->data.nowTS.tv_sec, pLogRTItem->data.nowTS.tv_nsec);
+ snprintf(rt_msg, LOG_RT_MSG_LEN, "[%lu:%09lu] ", pLogRTItem->data.nowTS.tv_sec, pLogRTItem->data.nowTS.tv_nsec);
strcat((char *)pLogItem->msg, rt_msg);
break;
case LOG_RT_DATATYPE_U16:
- sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.unsignedShortVar);
+ snprintf(rt_msg, LOG_RT_MSG_LEN, pLogRTItem->pFormat, pLogRTItem->data.unsignedShortVar);
strcat((char *)pLogItem->msg, rt_msg);
break;
case LOG_RT_DATATYPE_S16:
- sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.signedShortVar);
+ snprintf(rt_msg, LOG_RT_MSG_LEN, pLogRTItem->pFormat, pLogRTItem->data.signedShortVar);
strcat((char *)pLogItem->msg, rt_msg);
break;
case LOG_RT_DATATYPE_U32:
- sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.unsignedLongVar);
+ snprintf(rt_msg, LOG_RT_MSG_LEN, pLogRTItem->pFormat, pLogRTItem->data.unsignedLongVar);
strcat((char *)pLogItem->msg, rt_msg);
break;
case LOG_RT_DATATYPE_S32:
- sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.signedLongVar);
+ snprintf(rt_msg, LOG_RT_MSG_LEN, pLogRTItem->pFormat, pLogRTItem->data.signedLongVar);
strcat((char *)pLogItem->msg, rt_msg);
break;
case LOG_RT_DATATYPE_U64:
- sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.unsignedLongLongVar);
+ snprintf(rt_msg, LOG_RT_MSG_LEN, pLogRTItem->pFormat, pLogRTItem->data.unsignedLongLongVar);
strcat((char *)pLogItem->msg, rt_msg);
break;
case LOG_RT_DATATYPE_S64:
- sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.signedLongLongVar);
+ snprintf(rt_msg, LOG_RT_MSG_LEN, pLogRTItem->pFormat, pLogRTItem->data.signedLongLongVar);
strcat((char *)pLogItem->msg, rt_msg);
break;
case LOG_RT_DATATYPE_FLOAT:
- sprintf(rt_msg, pLogRTItem->pFormat, pLogRTItem->data.floatVar);
+ snprintf(rt_msg, LOG_RT_MSG_LEN, pLogRTItem->pFormat, pLogRTItem->data.floatVar);
strcat((char *)pLogItem->msg, rt_msg);
break;
default:
@@ -168,33 +170,42 @@ extern U32 DLL_EXPORT avbLogGetMsg(U8 *pBuf, U32 bufSize)
void *loggingThreadFn(void *pv)
{
- while (loggingThreadRunning) {
+ do {
SLEEP_MSEC(LOG_QUEUE_SLEEP_MSEC);
bool more = TRUE;
+ bool flush = FALSE;
while (more) {
more = FALSE;
openavb_queue_elem_t elem = openavbQueueTailLock(logQueue);
if (elem) {
log_queue_item_t *pLogItem = (log_queue_item_t *)openavbQueueData(elem);
-
+
if (pLogItem->bRT)
avbLogRTRender(pLogItem);
-
- fputs((const char *)pLogItem->msg, AVB_LOG_OUTPUT_FD);
+
+ fputs((const char *)pLogItem->msg, logOutputFd);
openavbQueueTailPull(logQueue);
more = TRUE;
+ flush = TRUE;
}
}
- }
+ if (flush)
+ fflush(logOutputFd);
+ } while (loggingThreadRunning);
return NULL;
}
-extern void DLL_EXPORT avbLogInit(void)
+extern void DLL_EXPORT avbLogInitEx(FILE* file)
{
MUTEX_CREATE_ALT(gLogMutex);
+
+ if (file != NULL)
+ logOutputFd = file;
+ else
+ logOutputFd = AVB_LOG_OUTPUT_FD;
logQueue = openavbQueueNewQueue(sizeof(log_queue_item_t), LOG_QUEUE_MSG_CNT);
if (!logQueue) {
@@ -216,12 +227,20 @@ extern void DLL_EXPORT avbLogInit(void)
}
}
+extern void DLL_EXPORT avbLogInit(void)
+{
+ avbLogInitEx(NULL);
+}
+
extern void DLL_EXPORT avbLogExit()
{
if (OPENAVB_LOG_FROM_THREAD) {
loggingThreadRunning = false;
THREAD_JOIN(loggingThread, NULL);
}
+
+ fflush(logOutputFd);
+ logOutputFd = NULL;
}
extern void DLL_EXPORT avbLogFn(
@@ -250,36 +269,37 @@ extern void DLL_EXPORT avbLogFn(
file += 1;
else
file = (char*)path;
- sprintf(file_msg, " %s:%d", file, line);
+ snprintf(file_msg, LOG_FILE_LEN, " %s:%d", file, line);
}
if (OPENAVB_LOG_PROC_INFO) {
- sprintf(proc_msg, " P:%5.5d", GET_PID());
+ snprintf(proc_msg, LOG_PROC_LEN, " P:%5.5d", GET_PID());
}
if (OPENAVB_LOG_THREAD_INFO) {
- sprintf(thread_msg, " T:%lu", THREAD_SELF());
+ snprintf(thread_msg, LOG_THREAD_LEN, " T:%lu", THREAD_SELF());
}
if (OPENAVB_LOG_TIME_INFO) {
time_t tNow = time(NULL);
struct tm tmNow;
localtime_r(&tNow, &tmNow);
- sprintf(time_msg, "%2.2d:%2.2d:%2.2d", tmNow.tm_hour, tmNow.tm_min, tmNow.tm_sec);
+ snprintf(time_msg, LOG_TIME_LEN, "%2.2d:%2.2d:%2.2d", tmNow.tm_hour, tmNow.tm_min, tmNow.tm_sec);
}
if (OPENAVB_LOG_TIMESTAMP_INFO) {
struct timespec nowTS;
CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &nowTS);
- sprintf(timestamp_msg, "%lu:%09lu", nowTS.tv_sec, nowTS.tv_nsec);
+ snprintf(timestamp_msg, LOG_TIMESTAMP_LEN, "%lu:%09lu", nowTS.tv_sec, nowTS.tv_nsec);
}
// using sprintf and puts allows using static buffers rather than heap.
if (OPENAVB_TCAL_LOG_EXTRA_NEWLINE)
- /* S32 full_msg_len = */ sprintf(full_msg, "[%s%s%s%s %s %s%s] %s: %s\n", time_msg, timestamp_msg, proc_msg, thread_msg, company, component, file_msg, tag, msg);
+ /* S32 full_msg_len = */ snprintf(full_msg, LOG_FULL_MSG_LEN, "[%s%s%s%s %s %s%s] %s: %s\n", time_msg, timestamp_msg, proc_msg, thread_msg, company, component, file_msg, tag, msg);
else
- /* S32 full_msg_len = */ sprintf(full_msg, "[%s%s%s%s %s %s%s] %s: %s", time_msg, timestamp_msg, proc_msg, thread_msg, company, component, file_msg, tag, msg);
+ /* S32 full_msg_len = */ snprintf(full_msg, LOG_FULL_MSG_LEN, "[%s%s%s%s %s %s%s] %s: %s", time_msg, timestamp_msg, proc_msg, thread_msg, company, component, file_msg, tag, msg);
if (!OPENAVB_LOG_FROM_THREAD && !OPENAVB_LOG_PULL_MODE) {
- fputs(full_msg, AVB_LOG_OUTPUT_FD);
+ fputs(full_msg, logOutputFd);
+ fflush(logOutputFd);
}
else {
if (logQueue) {
@@ -301,94 +321,139 @@ extern void DLL_EXPORT avbLogFn(
extern void DLL_EXPORT avbLogRT(int level, bool bBegin, bool bItem, bool bEnd, char *pFormat, log_rt_datatype_t dataType, void *pVar)
{
- if (level <= AVB_LOG_LEVEL) {
- if (logRTQueue) {
- if (bBegin) {
- LOG_LOCK();
+ if (logRTQueue) {
+ if (bBegin) {
+ LOG_LOCK();
- openavb_queue_elem_t elem = openavbQueueHeadLock(logRTQueue);
- if (elem) {
- log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)openavbQueueData(elem);
+ openavb_queue_elem_t elem = openavbQueueHeadLock(logRTQueue);
+ if (elem) {
+ log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)openavbQueueData(elem);
+ pLogRTItem->bEnd = FALSE;
+ pLogRTItem->pFormat = NULL;
+ pLogRTItem->dataType = LOG_RT_DATATYPE_NOW_TS;
+ CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &pLogRTItem->data.nowTS);
+ openavbQueueHeadPush(logRTQueue);
+ }
+ }
+
+ if (bItem) {
+ openavb_queue_elem_t elem = openavbQueueHeadLock(logRTQueue);
+ if (elem) {
+ log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)openavbQueueData(elem);
+ if (bEnd)
+ pLogRTItem->bEnd = TRUE;
+ else
pLogRTItem->bEnd = FALSE;
- pLogRTItem->pFormat = NULL;
- pLogRTItem->dataType = LOG_RT_DATATYPE_NOW_TS;
- CLOCK_GETTIME(OPENAVB_CLOCK_REALTIME, &pLogRTItem->data.nowTS);
- openavbQueueHeadPush(logRTQueue);
+ pLogRTItem->pFormat = pFormat;
+ pLogRTItem->dataType = dataType;
+
+ switch (pLogRTItem->dataType) {
+ case LOG_RT_DATATYPE_CONST_STR:
+ break;
+ case LOG_RT_DATATYPE_U16:
+ pLogRTItem->data.unsignedLongVar = *(U16 *)pVar;
+ break;
+ case LOG_RT_DATATYPE_S16:
+ pLogRTItem->data.signedLongVar = *(S16 *)pVar;
+ break;
+ case LOG_RT_DATATYPE_U32:
+ pLogRTItem->data.unsignedLongVar = *(U32 *)pVar;
+ break;
+ case LOG_RT_DATATYPE_S32:
+ pLogRTItem->data.signedLongVar = *(S32 *)pVar;
+ break;
+ case LOG_RT_DATATYPE_U64:
+ pLogRTItem->data.unsignedLongLongVar = *(U64 *)pVar;
+ break;
+ case LOG_RT_DATATYPE_S64:
+ pLogRTItem->data.signedLongLongVar = *(S64 *)pVar;
+ break;
+ case LOG_RT_DATATYPE_FLOAT:
+ pLogRTItem->data.floatVar = *(float *)pVar;
+ break;
+ default:
+ break;
}
+ openavbQueueHeadPush(logRTQueue);
}
+ }
- if (bItem) {
- openavb_queue_elem_t elem = openavbQueueHeadLock(logRTQueue);
- if (elem) {
- log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)openavbQueueData(elem);
- if (bEnd)
- pLogRTItem->bEnd = TRUE;
- else
- pLogRTItem->bEnd = FALSE;
- pLogRTItem->pFormat = pFormat;
- pLogRTItem->dataType = dataType;
-
- switch (pLogRTItem->dataType) {
- case LOG_RT_DATATYPE_CONST_STR:
- break;
- case LOG_RT_DATATYPE_U16:
- pLogRTItem->data.unsignedLongVar = *(U16 *)pVar;
- break;
- case LOG_RT_DATATYPE_S16:
- pLogRTItem->data.signedLongVar = *(S16 *)pVar;
- break;
- case LOG_RT_DATATYPE_U32:
- pLogRTItem->data.unsignedLongVar = *(U32 *)pVar;
- break;
- case LOG_RT_DATATYPE_S32:
- pLogRTItem->data.signedLongVar = *(S32 *)pVar;
- break;
- case LOG_RT_DATATYPE_U64:
- pLogRTItem->data.unsignedLongLongVar = *(U64 *)pVar;
- break;
- case LOG_RT_DATATYPE_S64:
- pLogRTItem->data.signedLongLongVar = *(S64 *)pVar;
- break;
- case LOG_RT_DATATYPE_FLOAT:
- pLogRTItem->data.floatVar = *(float *)pVar;
- break;
- default:
- break;
- }
- openavbQueueHeadPush(logRTQueue);
- }
+ if (!bItem && bEnd) {
+ openavb_queue_elem_t elem = openavbQueueHeadLock(logRTQueue);
+ if (elem) {
+ log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)openavbQueueData(elem);
+ pLogRTItem->bEnd = TRUE;
+ pLogRTItem->pFormat = NULL;
+ pLogRTItem->dataType = LOG_RT_DATATYPE_NONE;
+ openavbQueueHeadPush(logRTQueue);
}
-
- if (!bItem && bEnd) {
- openavb_queue_elem_t elem = openavbQueueHeadLock(logRTQueue);
+ }
+
+ if (bEnd) {
+ if (logQueue) {
+ openavb_queue_elem_t elem = openavbQueueHeadLock(logQueue);
if (elem) {
- log_rt_queue_item_t *pLogRTItem = (log_rt_queue_item_t *)openavbQueueData(elem);
- pLogRTItem->bEnd = TRUE;
- pLogRTItem->pFormat = NULL;
- pLogRTItem->dataType = LOG_RT_DATATYPE_NONE;
- openavbQueueHeadPush(logRTQueue);
- }
- }
-
- if (bEnd) {
- if (logQueue) {
- openavb_queue_elem_t elem = openavbQueueHeadLock(logQueue);
- if (elem) {
- log_queue_item_t *pLogItem = (log_queue_item_t *)openavbQueueData(elem);
- pLogItem->bRT = TRUE;
- if (OPENAVB_LOG_FROM_THREAD) {
- openavbQueueHeadPush(logQueue);
- } else {
- avbLogRTRender(pLogItem);
- fputs((const char *)pLogItem->msg, AVB_LOG_OUTPUT_FD);
- openavbQueueHeadUnlock(logQueue);
- }
+ log_queue_item_t *pLogItem = (log_queue_item_t *)openavbQueueData(elem);
+ pLogItem->bRT = TRUE;
+ if (OPENAVB_LOG_FROM_THREAD) {
+ openavbQueueHeadPush(logQueue);
+ } else {
+ avbLogRTRender(pLogItem);
+ fputs((const char *)pLogItem->msg, logOutputFd);
+ fflush(logOutputFd);
+ openavbQueueHeadUnlock(logQueue);
}
}
-
- LOG_UNLOCK();
}
+
+ LOG_UNLOCK();
}
}
}
+extern void DLL_EXPORT avbLogBuffer(
+ int level,
+ const U8 *pData,
+ int dataLen,
+ int lineLen,
+ const char *company,
+ const char *component,
+ const char *path,
+ int line)
+{
+ char szDataLine[ 400 ];
+ char *pszOut;
+ int i, j;
+
+ if (level > AVB_LOG_LEVEL) { return; }
+
+ for (i = 0; i < dataLen; i += lineLen) {
+ /* Create the hexadecimal output for the buffer. */
+ pszOut = szDataLine;
+ *pszOut++ = '\t';
+ for (j = i; j < i + lineLen; ++j) {
+ if (j < dataLen) {
+ sprintf(pszOut, "%02x ", pData[j]);
+ } else {
+ strcpy(pszOut, " ");
+ }
+ pszOut += 3;
+ }
+
+ *pszOut++ = ' ';
+ *pszOut++ = ' ';
+
+ /* Append the ASCII equivalent of each character. */
+ for (j = i; j < dataLen && j < i + lineLen; ++j) {
+ if (pData[j] >= 0x20 && pData[j] < 0x7f) {
+ *pszOut++ = (char) pData[j];
+ } else {
+ *pszOut++ = '.';
+ }
+ }
+
+ /* Display this line of text. */
+ *pszOut = '\0';
+ avbLogFn(level, "BUFFER", company, component, path, line, "%s", szDataLine);
+ }
+}
diff --git a/lib/avtp_pipeline/util/openavb_plugin.c b/lib/avtp_pipeline/util/openavb_plugin.c
index 1400cad4..2b9c3162 100644
--- a/lib/avtp_pipeline/util/openavb_plugin.c
+++ b/lib/avtp_pipeline/util/openavb_plugin.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/util/openavb_plugin.h b/lib/avtp_pipeline/util/openavb_plugin.h
index 9b0b2d59..5e2f4420 100644
--- a/lib/avtp_pipeline/util/openavb_plugin.h
+++ b/lib/avtp_pipeline/util/openavb_plugin.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/util/openavb_printbuf.c b/lib/avtp_pipeline/util/openavb_printbuf.c
index ba435b6c..981656fe 100644
--- a/lib/avtp_pipeline/util/openavb_printbuf.c
+++ b/lib/avtp_pipeline/util/openavb_printbuf.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/util/openavb_printbuf.h b/lib/avtp_pipeline/util/openavb_printbuf.h
index a3732a75..db36a364 100644
--- a/lib/avtp_pipeline/util/openavb_printbuf.h
+++ b/lib/avtp_pipeline/util/openavb_printbuf.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/util/openavb_queue.c b/lib/avtp_pipeline/util/openavb_queue.c
index 4dbbf366..ea48bf90 100644
--- a/lib/avtp_pipeline/util/openavb_queue.c
+++ b/lib/avtp_pipeline/util/openavb_queue.c
@@ -1,196 +1,197 @@
-/*************************************************************************************************************
-Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Attributions: The inih library portion of the source code is licensed from
-Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
-Complete license and copyright information can be found at
-https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
-*************************************************************************************************************/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <inttypes.h>
-
-#include "openavb_debug.h"
-#include "openavb_queue.h"
-
-OPENAVB_CODE_MODULE_PRI
-
-struct openavb_queue_elem {
- bool setFlg;
- void *data;
-};
-
-struct openavb_queue {
- // Size of each element
- U32 elemSize;
-
- // Number of queue element slots
- U32 queueSize;
-
- // Next element to be filled
- int head;
-
- // Next element to be pulled
- int tail;
-
- openavb_queue_elem_t elemArray;
-};
-
-openavb_queue_t openavbQueueNewQueue(U32 elemSize, U32 queueSize)
-{
- if (elemSize < 1 || queueSize < 1)
- return NULL;
-
- openavb_queue_t retQueue = calloc(1, sizeof(struct openavb_queue));
- if (retQueue) {
- retQueue->elemArray = calloc(queueSize, sizeof(struct openavb_queue_elem));
- if (retQueue->elemArray) {
- U32 i1;
- for (i1 = 0; i1 < queueSize; i1++) {
- retQueue->elemArray[i1].data = calloc(1, elemSize);
- if (!retQueue->elemArray[i1].data) {
- openavbQueueDeleteQueue(retQueue);
- return NULL;
- }
- }
- }
- else {
- openavbQueueDeleteQueue(retQueue);
- return NULL;
- }
-
- retQueue->elemSize = elemSize;
- retQueue->queueSize = queueSize;
- retQueue->head = 0;
- retQueue->tail = 0;
- }
-
- return retQueue;
-}
-
-void openavbQueueDeleteQueue(openavb_queue_t queue)
-{
- if (queue) {
- U32 i1;
- for (i1 = 0; i1 < queue->queueSize; i1++) {
- free(queue->elemArray[i1].data);
- queue->elemArray[i1].data = NULL;
- }
- free(queue->elemArray);
- queue->elemArray = NULL;
- free(queue);
- }
-}
-
-U32 openavbQueueGetQueueSize(openavb_queue_t queue)
-{
- if (queue) {
- return queue->queueSize;
- }
- return 0;
-}
-
-U32 openavbQueueGetElemCount(openavb_queue_t queue)
-{
- U32 cnt = 0;
- if (queue) {
- if (queue->head > queue->tail) {
- cnt += queue->head - queue->tail - 1;
- }
- else if (queue->head < queue->tail) {
- cnt += queue->head + ((queue->queueSize - 1) - queue->tail);
- }
-
- if (queue->elemArray[queue->tail].setFlg) {
- cnt++;
- }
- }
- return cnt;
-}
-
-U32 openavbQueueGetElemSize(openavb_queue_t queue)
-{
- if (queue) {
- return queue->elemSize;
- }
- return 0;
-}
-
-void *openavbQueueData(openavb_queue_elem_t elem)
-{
- if (elem) {
- return elem->data;
- }
- return NULL;
-}
-
-openavb_queue_elem_t openavbQueueHeadLock(openavb_queue_t queue)
-{
- if (queue) {
- if (!queue->elemArray[queue->head].setFlg) {
- return &queue->elemArray[queue->head];
- }
- }
- return NULL;
-}
-
-void openavbQueueHeadUnlock(openavb_queue_t queue)
-{
-}
-
-void openavbQueueHeadPush(openavb_queue_t queue)
-{
- if (queue) {
- queue->elemArray[queue->head++].setFlg = TRUE;
- if (queue->head >= queue->queueSize) {
- queue->head = 0;
- }
- }
-}
-
-openavb_queue_elem_t openavbQueueTailLock(openavb_queue_t queue)
-{
- if (queue) {
- if (queue->elemArray[queue->tail].setFlg) {
- return &queue->elemArray[queue->tail];
- }
- }
- return NULL;
-}
-
-void openavbQueueTailUnlock(openavb_queue_t queue)
-{
-}
-
-void openavbQueueTailPull(openavb_queue_t queue)
-{
- if (queue) {
- queue->elemArray[queue->tail++].setFlg = FALSE;
- if (queue->tail >= queue->queueSize) {
- queue->tail = 0;
- }
- }
-}
+/*************************************************************************************************************
+Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS LISTED "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS LISTED BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Attributions: The inih library portion of the source code is licensed from
+Brush Technology and Ben Hoyt - Copyright (c) 2009, Brush Technology and Copyright (c) 2009, Ben Hoyt.
+Complete license and copyright information can be found at
+https://github.com/benhoyt/inih/commit/74d2ca064fb293bc60a77b0bd068075b293cf175.
+*************************************************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "openavb_debug.h"
+#include "openavb_queue.h"
+
+OPENAVB_CODE_MODULE_PRI
+
+struct openavb_queue_elem {
+ bool setFlg;
+ void *data;
+};
+
+struct openavb_queue {
+ // Size of each element
+ U32 elemSize;
+
+ // Number of queue element slots
+ U32 queueSize;
+
+ // Next element to be filled
+ int head;
+
+ // Next element to be pulled
+ int tail;
+
+ openavb_queue_elem_t elemArray;
+};
+
+openavb_queue_t openavbQueueNewQueue(U32 elemSize, U32 queueSize)
+{
+ if (elemSize < 1 || queueSize < 1)
+ return NULL;
+
+ openavb_queue_t retQueue = calloc(1, sizeof(struct openavb_queue));
+ if (retQueue) {
+ retQueue->elemArray = calloc(queueSize, sizeof(struct openavb_queue_elem));
+ if (retQueue->elemArray) {
+ U32 i1;
+ for (i1 = 0; i1 < queueSize; i1++) {
+ retQueue->elemArray[i1].data = calloc(1, elemSize);
+ if (!retQueue->elemArray[i1].data) {
+ openavbQueueDeleteQueue(retQueue);
+ return NULL;
+ }
+ }
+ }
+ else {
+ openavbQueueDeleteQueue(retQueue);
+ return NULL;
+ }
+
+ retQueue->elemSize = elemSize;
+ retQueue->queueSize = queueSize;
+ retQueue->head = 0;
+ retQueue->tail = 0;
+ }
+
+ return retQueue;
+}
+
+void openavbQueueDeleteQueue(openavb_queue_t queue)
+{
+ if (queue) {
+ U32 i1;
+ for (i1 = 0; i1 < queue->queueSize; i1++) {
+ free(queue->elemArray[i1].data);
+ queue->elemArray[i1].data = NULL;
+ }
+ free(queue->elemArray);
+ queue->elemArray = NULL;
+ free(queue);
+ }
+}
+
+U32 openavbQueueGetQueueSize(openavb_queue_t queue)
+{
+ if (queue) {
+ return queue->queueSize;
+ }
+ return 0;
+}
+
+U32 openavbQueueGetElemCount(openavb_queue_t queue)
+{
+ U32 cnt = 0;
+ if (queue) {
+ if (queue->head > queue->tail) {
+ cnt += queue->head - queue->tail - 1;
+ }
+ else if (queue->head < queue->tail) {
+ cnt += queue->head + ((queue->queueSize - 1) - queue->tail);
+ }
+
+ if (queue->elemArray[queue->tail].setFlg) {
+ cnt++;
+ }
+ }
+ return cnt;
+}
+
+U32 openavbQueueGetElemSize(openavb_queue_t queue)
+{
+ if (queue) {
+ return queue->elemSize;
+ }
+ return 0;
+}
+
+void *openavbQueueData(openavb_queue_elem_t elem)
+{
+ if (elem) {
+ return elem->data;
+ }
+ return NULL;
+}
+
+openavb_queue_elem_t openavbQueueHeadLock(openavb_queue_t queue)
+{
+ if (queue) {
+ if (!queue->elemArray[queue->head].setFlg) {
+ return &queue->elemArray[queue->head];
+ }
+ }
+ return NULL;
+}
+
+void openavbQueueHeadUnlock(openavb_queue_t queue)
+{
+}
+
+void openavbQueueHeadPush(openavb_queue_t queue)
+{
+ if (queue) {
+ queue->elemArray[queue->head++].setFlg = TRUE;
+ if (queue->head >= queue->queueSize) {
+ queue->head = 0;
+ }
+ }
+}
+
+openavb_queue_elem_t openavbQueueTailLock(openavb_queue_t queue)
+{
+ if (queue) {
+ if (queue->elemArray[queue->tail].setFlg) {
+ return &queue->elemArray[queue->tail];
+ }
+ }
+ return NULL;
+}
+
+void openavbQueueTailUnlock(openavb_queue_t queue)
+{
+}
+
+void openavbQueueTailPull(openavb_queue_t queue)
+{
+ if (queue) {
+ queue->elemArray[queue->tail++].setFlg = FALSE;
+ if (queue->tail >= queue->queueSize) {
+ queue->tail = 0;
+ }
+ }
+}
diff --git a/lib/avtp_pipeline/util/openavb_queue.h b/lib/avtp_pipeline/util/openavb_queue.h
index 69e22011..f2e62ff5 100644
--- a/lib/avtp_pipeline/util/openavb_queue.h
+++ b/lib/avtp_pipeline/util/openavb_queue.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/util/openavb_result_codes.c b/lib/avtp_pipeline/util/openavb_result_codes.c
index 61dd12b1..1e377b5b 100755
--- a/lib/avtp_pipeline/util/openavb_result_codes.c
+++ b/lib/avtp_pipeline/util/openavb_result_codes.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -163,6 +164,7 @@ char *openavbUtilRCCodeToString(openavbRC rc)
case OPENAVBAVDECC_RC_INVALID_CONFIG_IDX: return "Referenced an invalid configuration descriptor index";
case OPENAVBAVDECC_RC_PARSING_MAC_ADDRESS: return "Parsing Mac Address";
case OPENAVBAVDECC_RC_UNKNOWN_DESCRIPTOR: return "Unknown descriptor";
+ case OPENAVBAVDECC_RC_STALE_DATA: return "Stale data";
// No Default
}
diff --git a/lib/avtp_pipeline/util/openavb_result_codes.h b/lib/avtp_pipeline/util/openavb_result_codes.h
index 082828da..d2aadbc4 100644
--- a/lib/avtp_pipeline/util/openavb_result_codes.h
+++ b/lib/avtp_pipeline/util/openavb_result_codes.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -85,7 +86,7 @@ enum openavbCommonResultCodes {
OPENAVB_RC_FAILED_TO_OPEN = 0x1004, // Failed to open
};
-enum openavbPtpResultCodes {
+enum openavbPtpResultCodes {
OPENAVBPTP_RC_GENERIC = 0x0000,
OPENAVBPTP_RC_SHARED_MEMORY_OPEN = 0x0001, // Failed to open shared memory file
OPENAVBPTP_RC_SHARED_MEMORY_TRANC = 0x0002, // Failed to truncate shared memory file
@@ -115,7 +116,7 @@ enum openavbPtpResultCodes {
OPENAVBPTP_RC_TX_TIMESTAMP_FAIL = 0x0026, // Failed to get egress timestamp
};
-enum openavbSrpResultCodes {
+enum openavbSrpResultCodes {
OPENAVBSRP_RC_GENERIC = 0x0000,
OPENAVBSRP_RC_ALREADY_INIT = 0x0001, // Already initialized
OPENAVBSRP_RC_SOCK_OPEN = 0x0002, // Failed to open socket
@@ -140,7 +141,7 @@ enum openavbSrpResultCodes {
// limited to two bytes; max 0xffff
};
-enum openavbAVTPResultCodes {
+enum openavbAVTPResultCodes {
OPENAVBAVTP_RC_GENERIC = 0x0000,
OPENAVBAVTP_RC_TX_PACKET_NOT_READY = 0x0001, // Transmit packet not ready
OPENAVBAVTP_RC_MAPPING_CB_NOT_SET = 0x0002, // Mapping callback structure not set
@@ -152,7 +153,7 @@ enum openavbAVTPResultCodes {
OPENAVBAVTP_RC_PARSING_FRAME_HEADER = 0x0008, // Parsing frame header
};
-enum openavbAVTPTimeResultCodes {
+enum openavbAVTPTimeResultCodes {
OPENAVBAVTPTIME_RC_GENERIC = 0x0000,
OPENAVBAVTPTIME_RC_PTP_TIME_DESCRIPTOR = 0x0001, // PTP file descriptor not available
OPENAVBAVTPTIME_RC_OPEN_SRC_PTP_NOT_AVAIL = 0x0002, // Open source PTP configured but not available in this build
@@ -161,14 +162,15 @@ enum openavbAVTPTimeResultCodes {
OPENAVBAVTPTIME_RC_INVALID_PTP_TIME = 0x0005, // Invalid avtp_time_t
};
-enum openavbAVDECCResultCodes {
+enum openavbAvdeccResultCodes {
OPENAVBAVDECC_RC_GENERIC = 0x0000,
OPENAVBAVDECC_RC_BUFFER_TOO_SMALL = 0x0001, // Buffer size is too small
OPENAVBAVDECC_RC_ENTITY_MODEL_MISSING = 0x0002, // The Entity Model has not been created
OPENAVBAVDECC_RC_INVALID_CONFIG_IDX = 0x0003, // Referenced an invalid configuration descriptor index
OPENAVBAVDECC_RC_PARSING_MAC_ADDRESS = 0x0004, // Parsing Mac Address
OPENAVBAVDECC_RC_UNKNOWN_DESCRIPTOR = 0x0005, // Unknown descriptor
-};
+ OPENAVBAVDECC_RC_STALE_DATA = 0x0006, // Stale data
+};
#define OPENAVB_PTP_SUCCESS (OPENAVB_SUCCESS | OPENAVB_MODULE_GPTP)
diff --git a/lib/avtp_pipeline/util/openavb_time.c b/lib/avtp_pipeline/util/openavb_time.c
index 7b624806..126afd26 100644
--- a/lib/avtp_pipeline/util/openavb_time.c
+++ b/lib/avtp_pipeline/util/openavb_time.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -61,9 +62,17 @@ void openavbTimeTimespecAddUsec(struct timespec *pTime, U32 us)
return; // Error case - undefined behavior
}
- pTime->tv_nsec += us * NANOSECONDS_PER_USEC;
- pTime->tv_sec += pTime->tv_nsec / NANOSECONDS_PER_SECOND;
- pTime->tv_nsec = pTime->tv_nsec % NANOSECONDS_PER_SECOND;
+ /* Handle the seconds provided (to prevent overflowing). */
+ pTime->tv_sec += us / MICROSECONDS_PER_SECOND;
+ us = us % MICROSECONDS_PER_SECOND;
+
+ /* Handle the remaining microseconds provided. */
+ if (us > 0) {
+ pTime->tv_nsec += us * NANOSECONDS_PER_USEC;
+
+ pTime->tv_sec += pTime->tv_nsec / NANOSECONDS_PER_SECOND;
+ pTime->tv_nsec = pTime->tv_nsec % NANOSECONDS_PER_SECOND;
+ }
}
void openavbTimeTimespecSubUsec(struct timespec *pTime, U32 us)
@@ -72,10 +81,19 @@ void openavbTimeTimespecSubUsec(struct timespec *pTime, U32 us)
return; // Error case - undefined behavior
}
- U64 nSec = ((U64)pTime->tv_sec * (U64)NANOSECONDS_PER_SECOND) + (U64)pTime->tv_nsec;
- nSec -= us * NANOSECONDS_PER_USEC;
- pTime->tv_sec = nSec / NANOSECONDS_PER_SECOND;
- pTime->tv_nsec = nSec % NANOSECONDS_PER_SECOND;
+ /* Handle the seconds provided (to prevent overflowing). */
+ pTime->tv_sec -= us / MICROSECONDS_PER_SECOND;
+ us = us % MICROSECONDS_PER_SECOND;
+
+ /* Handle the remaining microseconds provided. */
+ if (us > 0) {
+ pTime->tv_nsec -= us * NANOSECONDS_PER_USEC;
+
+ if (pTime->tv_nsec < 0) {
+ pTime->tv_nsec += NANOSECONDS_PER_SECOND;
+ pTime->tv_sec -= 1;
+ }
+ }
}
S64 openavbTimeTimespecUsecDiff(struct timespec *pTime1, struct timespec *pTime2)
diff --git a/lib/avtp_pipeline/util/openavb_time.h b/lib/avtp_pipeline/util/openavb_time.h
index 1a3e7d72..c52fa47f 100644
--- a/lib/avtp_pipeline/util/openavb_time.h
+++ b/lib/avtp_pipeline/util/openavb_time.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -56,10 +57,10 @@ S64 openavbTimeTimespecUsecDiff(struct timespec *pTime1, struct timespec *pTime2
// Compares 2 timespecs and returns -1, 0 or 1 depending on the compare.
S32 openavbTimeTimespecCmp(struct timespec *pTime1, struct timespec *pTime2);
-// Microseconds until Time2 reaches Time1. Returns 0 if Time2 is already past Time1
+// Microseconds until Time1 reaches Time2. Returns 0 if Time1 is already past Time2
U64 openavbTimeUntilUSec(struct timespec *pTime1, struct timespec *pTime2);
-// Milliseconds until Time2 reaches Time1. Returns 0 if Time2 is already past Time1
+// Milliseconds until Time1 reaches Time2. Returns 0 if Time1 is already past Time2
U32 openavbTimeUntilMSec(struct timespec *pTime1, struct timespec *pTime2);
#endif // OPENAVB_TIME_H
diff --git a/lib/avtp_pipeline/util/openavb_timestamp.c b/lib/avtp_pipeline/util/openavb_timestamp.c
index 442fa82c..82790ce3 100644
--- a/lib/avtp_pipeline/util/openavb_timestamp.c
+++ b/lib/avtp_pipeline/util/openavb_timestamp.c
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/avtp_pipeline/util/openavb_timestamp.h b/lib/avtp_pipeline/util/openavb_timestamp.h
index 0b4d77b8..85745fac 100644
--- a/lib/avtp_pipeline/util/openavb_timestamp.h
+++ b/lib/avtp_pipeline/util/openavb_timestamp.h
@@ -1,5 +1,6 @@
/*************************************************************************************************************
Copyright (c) 2012-2015, Symphony Teleca Corporation, a Harman International Industries, Incorporated company
+Copyright (c) 2016-2017, Harman International Industries, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/lib/common/Makefile b/lib/common/Makefile
index 4621bbf2..5b50f708 100644
--- a/lib/common/Makefile
+++ b/lib/common/Makefile
@@ -1,12 +1,25 @@
+AVB_FEATURE_IGB ?= 1
+
+ifeq ($(AVB_FEATURE_IGB),1)
+AVB_IGB_OBJ = avb_igb.o
+EXTRA_CFLAGS = -DAVB_FEATURE_IGB=1
+endif
+
CC ?= gcc
OPT = -O2 -g
-CFLAGS = $(OPT) -Wall -Wextra -Wno-parentheses
+WARN = -Wall -Wextra -Wno-parentheses
+CFLAGS = $(OPT) $(WARN) $(EXTRA_CFLAGS)
+ALL_OBJS = avb_avtp.o avb_gptp.o $(AVB_IGB_OBJ)
+
+.PHONY: all clean
-all: avb.o
+all: $(ALL_OBJS)
-avb.o: avb.c avb.h
- $(CC) $(CFLAGS) -I../igb -c avb.c
+avb_igb.o: CPPFLAGS = -I../igb
+avb_igb.o: avb_igb.c avb_igb.h
+avb_avtp.o: avb_avtp.c avb_avtp.h
+avb_gptp.o: avb_gptp.c avb_gptp.h
clean:
- $(RM) avb.o talker_mrp_client.o listener_mrp_client.o
+ $(RM) $(ALL_OBJS)
$(RM) `find . -name "*~" -o -name "*.[oa]" -o -name "\#*\#" -o -name TAGS -o -name core -o -name "*.orig"`
diff --git a/lib/common/avb.h b/lib/common/avb.h
index 55ffc195..0cf2d4e7 100644
--- a/lib/common/avb.h
+++ b/lib/common/avb.h
@@ -16,194 +16,16 @@
*
*/
-#ifndef __AVBTP_H__
-#define __AVBTP_H__
-
-#include <inttypes.h>
-
-#include <igb.h>
-
-#define VALID 1
-#define INVALID 0
-
-#define MAC_ADDR_LEN 6
-
-#define IGB_BIND_NAMESZ 24
-
-#define SHM_SIZE (4*8 + sizeof(pthread_mutex_t)) /* 3 - 64 bit and 2 - 32 bits */
-#define SHM_NAME "/ptp"
-
-#define MAX_SAMPLE_VALUE ((1U << ((sizeof(int32_t)*8)-1))-1)
-
-#define IEEE_61883_IIDC_SUBTYPE 0x0
-
-#define MRPD_PORT_DEFAULT 7500
-
-#define STREAM_ID_SIZE 8
-
-#define ETHER_TYPE_AVTP 0x22f0
-
-typedef struct __attribute__ ((packed)) {
- uint64_t subtype:7;
- uint64_t cd_indicator:1;
- uint64_t timestamp_valid:1;
- uint64_t gateway_valid:1;
- uint64_t reserved0:1;
- uint64_t reset:1;
- uint64_t version:3;
- uint64_t sid_valid:1;
- uint64_t seq_number:8;
- uint64_t timestamp_uncertain:1;
- uint64_t reserved1:7;
- uint64_t stream_id;
- uint64_t timestamp:32;
- uint64_t gateway_info:32;
- uint64_t length:16;
-
-} seventeen22_header;
-
-/* 61883 CIP with SYT Field */
-typedef struct {
- uint16_t packet_channel:6;
- uint16_t format_tag:2;
- uint16_t app_control:4;
- uint16_t packet_tcode:4;
- uint16_t source_id:6;
- uint16_t reserved0:2;
- uint16_t data_block_size:8;
- uint16_t reserved1:2;
- uint16_t source_packet_header:1;
- uint16_t quadlet_padding_count:3;
- uint16_t fraction_number:2;
- uint16_t data_block_continuity:8;
- uint16_t format_id:6;
- uint16_t eoh:2;
- uint16_t format_dependent_field:8;
- uint16_t syt;
-} six1883_header;
-
-typedef struct {
- uint8_t label;
- uint8_t value[3];
-} six1883_sample;
-
-#define ETH_ALEN 6 /* Size of Ethernet address */
-
-typedef struct __attribute__ ((packed)) {
- /* Destination MAC address. */
- uint8_t h_dest [ETH_ALEN];
- /* Destination MAC address. */
- uint8_t h_source [ETH_ALEN];
- /* Protocol ID. */
- uint8_t h_protocol[2];
-} eth_header;
-
-typedef long double FrequencyRatio;
-
-typedef struct {
- int64_t ml_phoffset;
- int64_t ls_phoffset;
- FrequencyRatio ml_freqoffset;
- FrequencyRatio ls_freqoffset;
- uint64_t local_time;
-} gPtpTimeData;
-
-/*TODO fix this*/
-#ifndef false
-typedef enum { false = 0, true = 1 } bool;
+#ifndef __AVB_H__
+#define __AVB_H__
+
+#include "avb_gptp.h"
+#include "avb_srp.h"
+#include "avb_avtp.h"
+#ifndef AVB_FEATURE_IGB
+/* IGB has not been disabled, so assume it is enabled. */
+#define AVB_FEATURE_IGB 1
+#include "avb_igb.h"
#endif
-int pci_connect(device_t * igb_dev);
-
-int gptpinit(int *shm_fd, char **shm_map);
-int gptpdeinit(int *shm_fd, char **shm_map);
-int gptpgetdata(char *shm_mmap, gPtpTimeData *td);
-int gptpscaling(char *shm_mmap, gPtpTimeData *td);
-bool gptplocaltime(const gPtpTimeData * td, uint64_t* now_local);
-
-void avb_set_1722_cd_indicator(seventeen22_header *h1722, uint64_t cd_indicator);
-uint64_t avb_get_1722_cd_indicator(seventeen22_header *h1722);
-void avb_set_1722_subtype(seventeen22_header *h1722, uint64_t subtype);
-uint64_t avb_get_1722_subtype(seventeen22_header *h1722);
-void avb_set_1722_sid_valid(seventeen22_header *h1722, uint64_t sid_valid);
-uint64_t avb_get_1722_sid_valid(seventeen22_header *h1722);
-void avb_set_1722_version(seventeen22_header *h1722, uint64_t version);
-uint64_t avb_get_1722_version(seventeen22_header *h1722);
-void avb_set_1722_reset(seventeen22_header *h1722, uint64_t reset);
-uint64_t avb_get_1722_reset(seventeen22_header *h1722);
-void avb_set_1722_reserved0(seventeen22_header *h1722, uint64_t reserved0);
-uint64_t avb_get_1722_reserved0(seventeen22_header *h1722);
-void avb_set_1722_reserved1(seventeen22_header *h1722, uint64_t reserved1);
-uint64_t avb_get_1722_reserved1(seventeen22_header *h1722);
-void avb_set_1722_timestamp_uncertain(seventeen22_header *h1722, uint64_t timestamp_uncertain);
-uint64_t avb_get_1722_timestamp_uncertain(seventeen22_header *h1722);
-void avb_set_1722_timestamp(seventeen22_header *h1722, uint64_t timestamp);
-uint64_t avb_get_1722_reset(seventeen22_header *h1722);
-void avb_set_1722_reserved0(seventeen22_header *h1722, uint64_t reserved0);
-uint64_t avb_get_1722_reserved0(seventeen22_header *h1722);
-void avb_set_1722_gateway_valid(seventeen22_header *h1722, uint64_t gateway_valid);
-uint64_t avb_get_1722_gateway_valid(seventeen22_header *h1722);
-void avb_set_1722_timestamp_valid(seventeen22_header *h1722, uint64_t timestamp_valid);
-uint64_t avb_get_1722_timestamp_valid(seventeen22_header *h1722);
-void avb_set_1722_reserved1(seventeen22_header *h1722, uint64_t reserved1);
-uint64_t avb_get_1722_reserved1(seventeen22_header *h1722);
-void avb_set_1722_timestamp_uncertain(seventeen22_header *h1722, uint64_t timestamp_uncertain);
-uint64_t avb_get_1722_timestamp_uncertain(seventeen22_header *h1722);
-void avb_set_1722_timestamp(seventeen22_header *h1722, uint64_t timestamp);
-uint64_t avb_get_1722_timestamp(seventeen22_header *h1722);
-void avb_set_1722_gateway_info(seventeen22_header *h1722, uint64_t gateway_info);
-uint64_t avb_get_1722_gateway_info(seventeen22_header *h1722);
-void avb_set_1722_length(seventeen22_header *h1722, uint64_t length);
-uint64_t avb_get_1722_length(seventeen22_header *h1722);
-void avb_set_1722_stream_id(seventeen22_header *h1722, uint64_t stream_id);
-uint64_t avb_get_1722_stream_id(seventeen22_header *h1722);
-void avb_set_1722_seq_number(seventeen22_header *h1722, uint64_t seq_number);
-uint64_t avb_get_1722_seq_number(seventeen22_header *h1722);
-
-void avb_set_61883_packet_channel(six1883_header *h61883, uint16_t packet_channel);
-uint16_t avb_get_61883_length(six1883_header *h61883);
-void avb_set_61883_format_tag(six1883_header *h61883, uint16_t format_tag);
-uint16_t avb_get_61883_format_tag(six1883_header *h61883);
-void avb_set_61883_app_control(six1883_header *h61883, uint16_t app_control);
-uint16_t avb_get_61883_app_control(six1883_header *h61883);
-void avb_set_61883_packet_tcode(six1883_header *h61883, uint16_t packet_tcode);
-uint16_t avb_get_61883_packet_tcode(six1883_header *h61883);
-void avb_set_61883_source_id(six1883_header *h61883, uint16_t source_id);
-uint16_t avb_get_61883_source_id(six1883_header *h61883);
-void avb_set_61883_reserved0(six1883_header *h61883, uint16_t reserved0);
-uint16_t avb_get_61883_reserved0(six1883_header *h61883);
-void avb_set_61883_data_block_size(six1883_header *h61883, uint16_t data_block_size);
-uint16_t avb_get_61883_data_block_size(six1883_header *h61883);
-void avb_set_61883_reserved1(six1883_header *h61883, uint16_t reserved1);
-uint16_t avb_get_61883_reserved1(six1883_header *h61883);
-void avb_set_61883_source_packet_header(six1883_header *h61883, uint16_t source_packet_header);
-uint16_t avb_get_61883_source_packet_header(six1883_header *h61883);
-void avb_set_61883_quadlet_padding_count(six1883_header *h61883, uint16_t quadlet_padding_count);
-uint16_t avb_get_61883_quadlet_padding_count(six1883_header *h61883);
-void avb_set_61883_fraction_number(six1883_header *h61883, uint16_t fraction_number);
-uint16_t avb_get_61883_fraction_number(six1883_header *h61883);
-void avb_set_61883_data_block_continuity(six1883_header *h61883, uint16_t data_block_continuity);
-uint16_t avb_get_61883_data_block_continuity(six1883_header *h61883);
-void avb_set_61883_format_id(six1883_header *h61883, uint16_t format_id);
-uint16_t avb_get_61883_format_id(six1883_header *h61883);
-void avb_set_61883_eoh(six1883_header *h61883, uint16_t eoh);
-uint16_t avb_get_61883_eoh(six1883_header *h61883);
-void avb_set_61883_format_dependent_field(six1883_header *h61883, uint16_t format_dependent_field);
-uint16_t avb_get_61883_format_dependent_field(six1883_header *h61883);
-void avb_set_61883_syt(six1883_header *h61883, uint16_t syt);
-uint16_t avb_get_61883_syt(six1883_header *h61883);
-
-void * avb_create_packet(uint32_t payload_len);
-
-void avb_initialize_h1722_to_defaults(seventeen22_header *h1722);
-
-void avb_initialize_61883_to_defaults(six1883_header *h61883);
-
-int32_t avb_get_iface_mac_address(int8_t *iface, uint8_t *addr);
-
-int32_t
-avb_eth_header_set_mac(eth_header *ethernet_header, uint8_t *addr, int8_t *iface);
-
-void avb_1722_set_eth_type(eth_header *eth_header);
-
-#endif /* __AVBTP_H__ */
+#endif /* __AVB_H__ */
diff --git a/lib/common/avb.c b/lib/common/avb_avtp.c
index 4cdf56de..c8749d29 100644
--- a/lib/common/avb.c
+++ b/lib/common/avb_avtp.c
@@ -1,220 +1,96 @@
- /*
- * Copyright (c) <2013>, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU Lesser General Public License,
- * version 2.1, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
- * more details.
- *
- * You should have received a copy of the GNU Lesser General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
+/*
+ * Copyright (c) <2013>, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include "avb_avtp.h"
-#include <errno.h>
-#include <fcntl.h>
-#include <math.h>
-#include <pthread.h>
-#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
-
#include <linux/if.h>
-
-#include <netinet/in.h>
-
-#include <pci/pci.h>
-
#include <sys/ioctl.h>
-#include <sys/mman.h>
#include <sys/socket.h>
-#include <sys/stat.h>
-#include "avb.h"
+int32_t avb_get_iface_mac_address(int8_t *iface, uint8_t *addr)
+{
+ struct ifreq ifreq;
+ int fd, ret;
-/**
- * @brief Connect to the network card
- * @param igb_dev [inout] Device handle
- * @return 0 for success, ENXIO for failure
- */
+ /* Create a socket */
+ fd = socket(PF_PACKET, SOCK_RAW, htons(0x800));
+ if (fd < 0)
+ return -1;
-int pci_connect(device_t *igb_dev)
-{
- char devpath[IGB_BIND_NAMESZ];
- struct pci_access *pacc;
- struct pci_dev *dev;
- int err;
-
- memset(igb_dev, 0, sizeof(device_t));
- pacc = pci_alloc();
- pci_init(pacc);
- pci_scan_bus(pacc);
-
- for (dev = pacc->devices; dev; dev = dev->next) {
- pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS);
- igb_dev->pci_vendor_id = dev->vendor_id;
- igb_dev->pci_device_id = dev->device_id;
- igb_dev->domain = dev->domain;
- igb_dev->bus = dev->bus;
- igb_dev->dev = dev->dev;
- igb_dev->func = dev->func;
- snprintf(devpath, IGB_BIND_NAMESZ, "%04x:%02x:%02x.%d",
- dev->domain, dev->bus, dev->dev, dev->func);
- err = igb_probe(igb_dev);
- if (err) {
- continue;
- }
- printf("attaching to %s\n", devpath);
- err = igb_attach(devpath, igb_dev);
- if (err) {
- printf("attach failed! (%s)\n", strerror(err));
- continue;
- }
- err = igb_attach_tx(igb_dev);
- if (err) {
- printf("attach_tx failed! (%s)\n", strerror(err));
- igb_detach(igb_dev);
- continue;
- }
- goto out;
- }
- pci_cleanup(pacc);
- return ENXIO;
-out:
- pci_cleanup(pacc);
- return 0;
-}
+ memset(&ifreq, 0, sizeof(ifreq));
-/**
- * @brief Open the memory mapping used for IPC
- * @param shm_fd [inout] File descriptor for mapping
- * @param shm_map [inout] Pointer to mapping
- * @return 0 for success, negative for failure
- */
-
-int gptpinit(int *shm_fd, char **shm_map)
-{
- if (NULL == shm_fd || NULL == shm_map) {
- return -1;
- }
- *shm_fd = shm_open(SHM_NAME, O_RDWR, 0);
- if (*shm_fd == -1) {
- perror("shm_open()");
- return -1;
- }
- *shm_map = (char *)mmap(NULL, SHM_SIZE, PROT_READ | PROT_WRITE,
- MAP_SHARED, *shm_fd, 0);
- if ((char*)-1 == *shm_map) {
- perror("mmap()");
- *shm_map = NULL;
- shm_unlink(SHM_NAME);
+ strncpy(ifreq.ifr_name, (const char*)iface, sizeof(ifreq.ifr_name));
+ ret = ioctl(fd, SIOCGIFHWADDR, &ifreq);
+ if (ret < 0) {
+ close(fd);
return -1;
}
+
+ memcpy(addr, ifreq.ifr_hwaddr.sa_data, ETH_ALEN);
+ close(fd);
+
return 0;
}
-/**
- * @brief Free the memory mapping used for IPC
- * @param shm_fd [in] File descriptor for mapping
- * @param shm_map [in] Pointer to mapping
- * @return 0 for success, negative for failure
- * -1 = close failed
- * -2 = munmap failed
- * -3 = close and munmap failed
- */
-
-int gptpdeinit(int *shm_fd, char **shm_map)
+void *avb_create_packet(uint32_t payload_len)
{
- int ret = 0;
- if (NULL == shm_fd || -1 == *shm_fd) {
- ret -= 1;
- } else {
- if(close(*shm_fd) == -1) {
- ret -= 1;
- }
- *shm_fd = -1;
- }
- if (NULL == shm_map || NULL == *shm_map) {
- ret -= 2;
- } else {
- if (munmap(*shm_map, SHM_SIZE) == -1) {
- ret -= 2;
- }
- *shm_map = NULL;
- }
- return ret;
-}
+ void *avb_packet = NULL;
+ uint32_t size;
-/**
- * @brief Read the ptp data from IPC memory
- * @param shm_map [in] Pointer to mapping
- * @param td [inout] Struct to read the data into
- * @return 0 for success, negative for failure
- */
+ size = sizeof(six1883_header);
+ size += sizeof(eth_header) + sizeof(seventeen22_header) + payload_len;
-int gptpgetdata(char *shm_map, gPtpTimeData *td)
-{
- if (NULL == shm_map || NULL == td) {
- return -1;
- }
- pthread_mutex_lock((pthread_mutex_t *) shm_map);
- memcpy(td, shm_map + sizeof(pthread_mutex_t), sizeof(*td));
- pthread_mutex_unlock((pthread_mutex_t *) shm_map);
+ avb_packet = calloc(size, sizeof(uint8_t));
+ if (!avb_packet)
+ return NULL;
- return 0;
+ return avb_packet;
}
-/**
- * @brief Read the ptp data from IPC memory and print its contents
- * @param shm_map [in] Pointer to mapping
- * @param td [inout] Struct to read the data into
- * @return 0 for success, negative for failure
- */
+void avb_1722_set_eth_type(eth_header *eth_header) {
-int gptpscaling(char *shm_map, gPtpTimeData *td) //change this function name ??
-{
- int i;
- if ((i = gptpgetdata(shm_map, td)) < 0) {
- return i;
- }
- fprintf(stderr, "ml_phoffset = %" PRId64 ", ls_phoffset = %" PRId64 "\n",
- td->ml_phoffset, td->ls_phoffset);
- fprintf(stderr, "ml_freqffset = %Lf, ls_freqoffset = %Lf\n",
- td->ml_freqoffset, td->ls_freqoffset);
+ eth_header->h_protocol[0] = 0x22;
+ eth_header->h_protocol[1] = 0xf0;
- return 0;
+ return;
}
-bool gptplocaltime(const gPtpTimeData * td, uint64_t* now_local)
+int32_t
+avb_eth_header_set_mac(eth_header *ethernet_header, uint8_t *addr, int8_t *iface)
{
- struct timespec sys_time;
- uint64_t now_system;
- uint64_t system_time;
- int64_t delta_local;
- int64_t delta_system;
-
- if (!td || !now_local)
- return false;
+ uint8_t source_mac[ETH_ALEN];
- if (clock_gettime(CLOCK_REALTIME, &sys_time) != 0)
- return false;
+ if (!addr || !iface)
+ return -EINVAL;
- now_system = (uint64_t)sys_time.tv_sec * 1000000000ULL + (uint64_t)sys_time.tv_nsec;
+ if (avb_get_iface_mac_address(iface, source_mac))
+ return -EINVAL;
- system_time = td->local_time + td->ls_phoffset;
- delta_system = now_system - system_time;
- delta_local = td->ls_freqoffset * delta_system;
- *now_local = td->local_time + delta_local;
+ memcpy(ethernet_header->h_dest, addr, ETH_ALEN);
+ memcpy(ethernet_header->h_source, source_mac, ETH_ALEN);
- return true;
+ return 0;
}
/* setters & getters for seventeen22_header */
@@ -368,6 +244,24 @@ uint64_t avb_get_1722_length(seventeen22_header *h1722)
return h1722->length;
}
+void avb_initialize_h1722_to_defaults(seventeen22_header *h1722)
+{
+ avb_set_1722_subtype(h1722, 0x0);
+ avb_set_1722_cd_indicator(h1722, 0x0);
+ avb_set_1722_timestamp_valid(h1722, 0x0);
+ avb_set_1722_gateway_valid(h1722, 0x0);
+ avb_set_1722_reserved0(h1722, 0x0);
+ avb_set_1722_sid_valid(h1722, 0x0);
+ avb_set_1722_reset(h1722, 0x0);
+ avb_set_1722_version(h1722, 0x0);
+ avb_set_1722_seq_number(h1722, 0x0);
+ avb_set_1722_timestamp_uncertain(h1722, 0x0);
+ avb_set_1722_reserved1(h1722, 0x0);
+ avb_set_1722_timestamp(h1722, 0x0);
+ avb_set_1722_gateway_info(h1722, 0x0);
+ avb_set_1722_length(h1722, 0x0);
+}
+
/* setters & getters for six1883_header */
void avb_set_61883_packet_channel(six1883_header *h61883, uint16_t packet_channel)
@@ -530,39 +424,6 @@ uint16_t avb_get_61883_syt(six1883_header *h61883)
return h61883->syt;
}
-void * avb_create_packet(uint32_t payload_len)
-{
- void *avb_packet = NULL;
- uint32_t size;
-
- size = sizeof(six1883_header);
- size += sizeof(eth_header) + sizeof(seventeen22_header) + payload_len;
-
- avb_packet = calloc(size, sizeof(uint8_t));
- if (!avb_packet)
- return NULL;
-
- return avb_packet;
-}
-
-void avb_initialize_h1722_to_defaults(seventeen22_header *h1722)
-{
- avb_set_1722_subtype(h1722, 0x0);
- avb_set_1722_cd_indicator(h1722, 0x0);
- avb_set_1722_timestamp_valid(h1722, 0x0);
- avb_set_1722_gateway_valid(h1722, 0x0);
- avb_set_1722_reserved0(h1722, 0x0);
- avb_set_1722_sid_valid(h1722, 0x0);
- avb_set_1722_reset(h1722, 0x0);
- avb_set_1722_version(h1722, 0x0);
- avb_set_1722_sid_valid(h1722, 0x0);
- avb_set_1722_timestamp_uncertain(h1722, 0x0);
- avb_set_1722_reserved1(h1722, 0x0);
- avb_set_1722_timestamp(h1722, 0x0);
- avb_set_1722_gateway_info(h1722, 0x0);
- avb_set_1722_length(h1722, 0x0);
-}
-
void avb_initialize_61883_to_defaults(six1883_header *h61883)
{
avb_set_61883_packet_channel(h61883, 0x0);
@@ -582,53 +443,3 @@ void avb_initialize_61883_to_defaults(six1883_header *h61883)
avb_set_61883_format_dependent_field(h61883, 0x0);
avb_set_61883_syt(h61883, 0x0);
}
-
-int32_t avb_get_iface_mac_address(int8_t *iface, uint8_t *addr)
-{
- struct ifreq ifreq;
- int fd, ret;
-
- /* Create a socket */
- fd = socket(PF_PACKET, SOCK_RAW, htons(0x800));
- if (fd < 0)
- return -1;
-
- memset(&ifreq, 0, sizeof(ifreq));
-
- strncpy(ifreq.ifr_name, (const char*)iface, sizeof(ifreq.ifr_name));
- ret = ioctl(fd, SIOCGIFHWADDR, &ifreq);
- if (ret < 0) {
- close(fd);
- return -1;
- }
-
- memcpy(addr, ifreq.ifr_hwaddr.sa_data, ETH_ALEN);
- close(fd);
-
- return 0;
-}
-
-void avb_1722_set_eth_type(eth_header *eth_header) {
-
- eth_header->h_protocol[0] = 0x22;
- eth_header->h_protocol[1] = 0xf0;
-
- return;
-}
-
-int32_t
-avb_eth_header_set_mac(eth_header *ethernet_header, uint8_t *addr, int8_t *iface)
-{
- uint8_t source_mac[ETH_ALEN];
-
- if (!addr || !iface)
- return -EINVAL;
-
- if (avb_get_iface_mac_address(iface, source_mac))
- return -EINVAL;
-
- memcpy(ethernet_header->h_dest, addr, ETH_ALEN);
- memcpy(ethernet_header->h_source, source_mac, ETH_ALEN);
-
- return 0;
-}
diff --git a/lib/common/avb_avtp.h b/lib/common/avb_avtp.h
new file mode 100644
index 00000000..23ceab2b
--- /dev/null
+++ b/lib/common/avb_avtp.h
@@ -0,0 +1,151 @@
+#ifndef __AVB_AVTP_H__
+#define __AVB_AVTP_H__
+
+#include <inttypes.h>
+
+#define MAX_SAMPLE_VALUE ((1U << ((sizeof(int32_t)*8)-1))-1)
+
+#define IEEE_61883_IIDC_SUBTYPE 0x0
+
+#define ETHER_TYPE_AVTP 0x22f0
+
+#define ETH_ALEN 6 /* Size of Ethernet address */
+
+typedef struct __attribute__ ((packed)) {
+ /* Destination MAC address. */
+ uint8_t h_dest [ETH_ALEN];
+ /* Destination MAC address. */
+ uint8_t h_source [ETH_ALEN];
+ /* Protocol ID. */
+ uint8_t h_protocol[2];
+} eth_header;
+
+typedef struct __attribute__ ((packed)) {
+ uint64_t subtype:7;
+ uint64_t cd_indicator:1;
+ uint64_t timestamp_valid:1;
+ uint64_t gateway_valid:1;
+ uint64_t reserved0:1;
+ uint64_t reset:1;
+ uint64_t version:3;
+ uint64_t sid_valid:1;
+ uint64_t seq_number:8;
+ uint64_t timestamp_uncertain:1;
+ uint64_t reserved1:7;
+ uint64_t stream_id;
+ uint64_t timestamp:32;
+ uint64_t gateway_info:32;
+ uint64_t length:16;
+} seventeen22_header;
+
+/* 61883 CIP with SYT Field */
+typedef struct {
+ uint16_t packet_channel:6;
+ uint16_t format_tag:2;
+ uint16_t app_control:4;
+ uint16_t packet_tcode:4;
+ uint16_t source_id:6;
+ uint16_t reserved0:2;
+ uint16_t data_block_size:8;
+ uint16_t reserved1:2;
+ uint16_t source_packet_header:1;
+ uint16_t quadlet_padding_count:3;
+ uint16_t fraction_number:2;
+ uint16_t data_block_continuity:8;
+ uint16_t format_id:6;
+ uint16_t eoh:2;
+ uint16_t format_dependent_field:8;
+ uint16_t syt;
+} six1883_header;
+
+typedef struct {
+ uint8_t label;
+ uint8_t value[3];
+} six1883_sample;
+
+void avb_set_1722_cd_indicator(seventeen22_header *h1722, uint64_t cd_indicator);
+uint64_t avb_get_1722_cd_indicator(seventeen22_header *h1722);
+void avb_set_1722_subtype(seventeen22_header *h1722, uint64_t subtype);
+uint64_t avb_get_1722_subtype(seventeen22_header *h1722);
+void avb_set_1722_sid_valid(seventeen22_header *h1722, uint64_t sid_valid);
+uint64_t avb_get_1722_sid_valid(seventeen22_header *h1722);
+void avb_set_1722_version(seventeen22_header *h1722, uint64_t version);
+uint64_t avb_get_1722_version(seventeen22_header *h1722);
+void avb_set_1722_reset(seventeen22_header *h1722, uint64_t reset);
+uint64_t avb_get_1722_reset(seventeen22_header *h1722);
+void avb_set_1722_reserved0(seventeen22_header *h1722, uint64_t reserved0);
+uint64_t avb_get_1722_reserved0(seventeen22_header *h1722);
+void avb_set_1722_reserved1(seventeen22_header *h1722, uint64_t reserved1);
+uint64_t avb_get_1722_reserved1(seventeen22_header *h1722);
+void avb_set_1722_timestamp_uncertain(seventeen22_header *h1722, uint64_t timestamp_uncertain);
+uint64_t avb_get_1722_timestamp_uncertain(seventeen22_header *h1722);
+void avb_set_1722_timestamp(seventeen22_header *h1722, uint64_t timestamp);
+uint64_t avb_get_1722_reset(seventeen22_header *h1722);
+void avb_set_1722_reserved0(seventeen22_header *h1722, uint64_t reserved0);
+uint64_t avb_get_1722_reserved0(seventeen22_header *h1722);
+void avb_set_1722_gateway_valid(seventeen22_header *h1722, uint64_t gateway_valid);
+uint64_t avb_get_1722_gateway_valid(seventeen22_header *h1722);
+void avb_set_1722_timestamp_valid(seventeen22_header *h1722, uint64_t timestamp_valid);
+uint64_t avb_get_1722_timestamp_valid(seventeen22_header *h1722);
+void avb_set_1722_reserved1(seventeen22_header *h1722, uint64_t reserved1);
+uint64_t avb_get_1722_reserved1(seventeen22_header *h1722);
+void avb_set_1722_timestamp_uncertain(seventeen22_header *h1722, uint64_t timestamp_uncertain);
+uint64_t avb_get_1722_timestamp_uncertain(seventeen22_header *h1722);
+void avb_set_1722_timestamp(seventeen22_header *h1722, uint64_t timestamp);
+uint64_t avb_get_1722_timestamp(seventeen22_header *h1722);
+void avb_set_1722_gateway_info(seventeen22_header *h1722, uint64_t gateway_info);
+uint64_t avb_get_1722_gateway_info(seventeen22_header *h1722);
+void avb_set_1722_length(seventeen22_header *h1722, uint64_t length);
+uint64_t avb_get_1722_length(seventeen22_header *h1722);
+void avb_set_1722_stream_id(seventeen22_header *h1722, uint64_t stream_id);
+uint64_t avb_get_1722_stream_id(seventeen22_header *h1722);
+void avb_set_1722_seq_number(seventeen22_header *h1722, uint64_t seq_number);
+uint64_t avb_get_1722_seq_number(seventeen22_header *h1722);
+
+void avb_set_61883_packet_channel(six1883_header *h61883, uint16_t packet_channel);
+uint16_t avb_get_61883_length(six1883_header *h61883);
+void avb_set_61883_format_tag(six1883_header *h61883, uint16_t format_tag);
+uint16_t avb_get_61883_format_tag(six1883_header *h61883);
+void avb_set_61883_app_control(six1883_header *h61883, uint16_t app_control);
+uint16_t avb_get_61883_app_control(six1883_header *h61883);
+void avb_set_61883_packet_tcode(six1883_header *h61883, uint16_t packet_tcode);
+uint16_t avb_get_61883_packet_tcode(six1883_header *h61883);
+void avb_set_61883_source_id(six1883_header *h61883, uint16_t source_id);
+uint16_t avb_get_61883_source_id(six1883_header *h61883);
+void avb_set_61883_reserved0(six1883_header *h61883, uint16_t reserved0);
+uint16_t avb_get_61883_reserved0(six1883_header *h61883);
+void avb_set_61883_data_block_size(six1883_header *h61883, uint16_t data_block_size);
+uint16_t avb_get_61883_data_block_size(six1883_header *h61883);
+void avb_set_61883_reserved1(six1883_header *h61883, uint16_t reserved1);
+uint16_t avb_get_61883_reserved1(six1883_header *h61883);
+void avb_set_61883_source_packet_header(six1883_header *h61883, uint16_t source_packet_header);
+uint16_t avb_get_61883_source_packet_header(six1883_header *h61883);
+void avb_set_61883_quadlet_padding_count(six1883_header *h61883, uint16_t quadlet_padding_count);
+uint16_t avb_get_61883_quadlet_padding_count(six1883_header *h61883);
+void avb_set_61883_fraction_number(six1883_header *h61883, uint16_t fraction_number);
+uint16_t avb_get_61883_fraction_number(six1883_header *h61883);
+void avb_set_61883_data_block_continuity(six1883_header *h61883, uint16_t data_block_continuity);
+uint16_t avb_get_61883_data_block_continuity(six1883_header *h61883);
+void avb_set_61883_format_id(six1883_header *h61883, uint16_t format_id);
+uint16_t avb_get_61883_format_id(six1883_header *h61883);
+void avb_set_61883_eoh(six1883_header *h61883, uint16_t eoh);
+uint16_t avb_get_61883_eoh(six1883_header *h61883);
+void avb_set_61883_format_dependent_field(six1883_header *h61883, uint16_t format_dependent_field);
+uint16_t avb_get_61883_format_dependent_field(six1883_header *h61883);
+void avb_set_61883_syt(six1883_header *h61883, uint16_t syt);
+uint16_t avb_get_61883_syt(six1883_header *h61883);
+
+void * avb_create_packet(uint32_t payload_len);
+
+void avb_initialize_h1722_to_defaults(seventeen22_header *h1722);
+
+void avb_initialize_61883_to_defaults(six1883_header *h61883);
+
+int32_t avb_get_iface_mac_address(int8_t *iface, uint8_t *addr);
+
+int32_t
+avb_eth_header_set_mac(eth_header *ethernet_header, uint8_t *addr, int8_t *iface);
+
+void avb_1722_set_eth_type(eth_header *eth_header);
+
+#endif
diff --git a/lib/common/avb_gptp.c b/lib/common/avb_gptp.c
new file mode 100644
index 00000000..fddf97f5
--- /dev/null
+++ b/lib/common/avb_gptp.c
@@ -0,0 +1,149 @@
+#include "avb_gptp.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <pthread.h>
+
+/**
+ * @brief Open the memory mapping used for IPC
+ * @param shm_fd [inout] File descriptor for mapping
+ * @param shm_map [inout] Pointer to mapping
+ * @return 0 for success, negative for failure
+ */
+
+int gptpinit(int *shm_fd, char **shm_map)
+{
+ if (NULL == shm_fd || NULL == shm_map) {
+ return -1;
+ }
+ *shm_fd = shm_open(SHM_NAME, O_RDWR, 0);
+ if (*shm_fd == -1) {
+ perror("shm_open()");
+ return -1;
+ }
+ *shm_map = (char *)mmap(NULL, SHM_SIZE, PROT_READ | PROT_WRITE,
+ MAP_SHARED, *shm_fd, 0);
+ if ((char*)-1 == *shm_map) {
+ perror("mmap()");
+ *shm_map = NULL;
+ shm_unlink(SHM_NAME);
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * @brief Free the memory mapping used for IPC
+ * @param shm_fd [in] File descriptor for mapping
+ * @param shm_map [in] Pointer to mapping
+ * @return 0 for success, negative for failure
+ * -1 = close failed
+ * -2 = munmap failed
+ * -3 = close and munmap failed
+ */
+
+int gptpdeinit(int *shm_fd, char **shm_map)
+{
+ int ret = 0;
+ if (NULL == shm_fd || -1 == *shm_fd) {
+ ret -= 1;
+ } else {
+ if(close(*shm_fd) == -1) {
+ ret -= 1;
+ }
+ *shm_fd = -1;
+ }
+ if (NULL == shm_map || NULL == *shm_map) {
+ ret -= 2;
+ } else {
+ if (munmap(*shm_map, SHM_SIZE) == -1) {
+ ret -= 2;
+ }
+ *shm_map = NULL;
+ }
+ return ret;
+}
+
+/**
+ * @brief Read the ptp data from IPC memory
+ * @param shm_map [in] Pointer to mapping
+ * @param td [inout] Struct to read the data into
+ * @return 0 for success, negative for failure
+ */
+
+int gptpgetdata(char *shm_map, gPtpTimeData *td)
+{
+ if (NULL == shm_map || NULL == td) {
+ return -1;
+ }
+ pthread_mutex_lock((pthread_mutex_t *) shm_map);
+ memcpy(td, shm_map + sizeof(pthread_mutex_t), sizeof(*td));
+ pthread_mutex_unlock((pthread_mutex_t *) shm_map);
+
+ return 0;
+}
+
+/**
+ * @brief Read the ptp data from IPC memory and print its contents
+ * @param shm_map [in] Pointer to mapping
+ * @param td [inout] Struct to read the data into
+ * @return 0 for success, negative for failure
+ */
+
+int gptpscaling(char *shm_map, gPtpTimeData *td) //change this function name ??
+{
+ int i;
+ if ((i = gptpgetdata(shm_map, td)) < 0) {
+ return i;
+ }
+ fprintf(stderr, "ml_phoffset = %" PRId64 ", ls_phoffset = %" PRId64 "\n",
+ td->ml_phoffset, td->ls_phoffset);
+ fprintf(stderr, "ml_freqffset = %Lf, ls_freqoffset = %Lf\n",
+ td->ml_freqoffset, td->ls_freqoffset);
+
+ return 0;
+}
+
+bool gptplocaltime(const gPtpTimeData * td, uint64_t* now_local)
+{
+ struct timespec sys_time;
+ uint64_t now_system;
+ uint64_t system_time;
+ int64_t delta_local;
+ int64_t delta_system;
+
+ if (!td || !now_local)
+ return false;
+
+ if (clock_gettime(CLOCK_REALTIME, &sys_time) != 0)
+ return false;
+
+ now_system = (uint64_t)sys_time.tv_sec * 1000000000ULL + (uint64_t)sys_time.tv_nsec;
+
+ system_time = td->local_time + td->ls_phoffset;
+ delta_system = now_system - system_time;
+ delta_local = td->ls_freqoffset * delta_system;
+ *now_local = td->local_time + delta_local;
+
+ return true;
+}
+
+bool gptpmaster2local(const gPtpTimeData *td, const uint64_t master, uint64_t *local)
+{
+ int64_t delta_8021as;
+ int64_t delta_local;
+
+ if (!td || !local)
+ return false;
+
+ delta_8021as = master - td->local_time + td->ml_phoffset;
+ delta_local = delta_8021as / td->ml_freqoffset;
+ *local = td->local_time + delta_local;
+
+ return true;
+}
diff --git a/lib/common/avb_gptp.h b/lib/common/avb_gptp.h
new file mode 100644
index 00000000..9652a5a1
--- /dev/null
+++ b/lib/common/avb_gptp.h
@@ -0,0 +1,50 @@
+#ifndef __AVB_GPTP_H__
+#define __AVB_GPTP_H__
+
+#include <inttypes.h>
+
+#define SHM_SIZE (4*8 + sizeof(pthread_mutex_t)) /* 3 - 64 bit and 2 - 32 bits */
+#define SHM_NAME "/ptp"
+
+typedef long double FrequencyRatio;
+
+typedef struct {
+ int64_t ml_phoffset;
+ int64_t ls_phoffset;
+ FrequencyRatio ml_freqoffset;
+ FrequencyRatio ls_freqoffset;
+ uint64_t local_time;
+
+ /* Current grandmaster information */
+ /* Referenced by the IEEE Std 1722.1-2013 AVDECC Discovery Protocol Data Unit (ADPDU) */
+ uint8_t gptp_grandmaster_id[8]; /* Current grandmaster id (all 0's if no grandmaster selected) */
+ uint8_t gptp_domain_number; /* gPTP domain number */
+
+ /* Grandmaster support for the network interface */
+ /* Referenced by the IEEE Std 1722.1-2013 AVDECC AVB_INTERFACE descriptor */
+ uint8_t clock_identity[8]; /* The clock identity of the interface */
+ uint8_t priority1; /* The priority1 field of the grandmaster functionality of the interface, or 0xFF if not supported */
+ uint8_t clock_class; /* The clockClass field of the grandmaster functionality of the interface, or 0xFF if not supported */
+ int16_t offset_scaled_log_variance; /* The offsetScaledLogVariance field of the grandmaster functionality of the interface, or 0x0000 if not supported */
+ uint8_t clock_accuracy; /* The clockAccuracy field of the grandmaster functionality of the interface, or 0xFF if not supported */
+ uint8_t priority2; /* The priority2 field of the grandmaster functionality of the interface, or 0xFF if not supported */
+ uint8_t domain_number; /* The domainNumber field of the grandmaster functionality of the interface, or 0 if not supported */
+ int8_t log_sync_interval; /* The currentLogSyncInterval field of the grandmaster functionality of the interface, or 0 if not supported */
+ int8_t log_announce_interval; /* The currentLogAnnounceInterval field of the grandmaster functionality of the interface, or 0 if not supported */
+ int8_t log_pdelay_interval; /* The currentLogPDelayReqInterval field of the grandmaster functionality of the interface, or 0 if not supported */
+ uint16_t port_number; /* The portNumber field of the interface, or 0x0000 if not supported */
+} gPtpTimeData;
+
+/*TODO fix this*/
+#ifndef false
+typedef enum { false = 0, true = 1 } bool;
+#endif
+
+int gptpinit(int *shm_fd, char **shm_map);
+int gptpdeinit(int *shm_fd, char **shm_map);
+int gptpgetdata(char *shm_mmap, gPtpTimeData *td);
+int gptpscaling(char *shm_mmap, gPtpTimeData *td);
+bool gptplocaltime(const gPtpTimeData * td, uint64_t* now_local);
+bool gptpmaster2local(const gPtpTimeData *td, const uint64_t master, uint64_t *local);
+
+#endif
diff --git a/lib/common/avb_igb.c b/lib/common/avb_igb.c
new file mode 100644
index 00000000..e83ab411
--- /dev/null
+++ b/lib/common/avb_igb.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) <2013>, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include "avb_igb.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <pci/pci.h>
+
+/**
+ * @brief Connect to the network card
+ * @param igb_dev [inout] Device handle
+ * @return 0 for success, ENXIO for failure
+ */
+
+int pci_connect(device_t *igb_dev)
+{
+ char devpath[IGB_BIND_NAMESZ];
+ struct pci_access *pacc;
+ struct pci_dev *dev;
+ int err;
+
+ memset(igb_dev, 0, sizeof(device_t));
+ pacc = pci_alloc();
+ pci_init(pacc);
+ pci_scan_bus(pacc);
+
+ for (dev = pacc->devices; dev; dev = dev->next) {
+ pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS);
+ igb_dev->pci_vendor_id = dev->vendor_id;
+ igb_dev->pci_device_id = dev->device_id;
+ igb_dev->domain = dev->domain;
+ igb_dev->bus = dev->bus;
+ igb_dev->dev = dev->dev;
+ igb_dev->func = dev->func;
+ snprintf(devpath, IGB_BIND_NAMESZ, "%04x:%02x:%02x.%d",
+ dev->domain, dev->bus, dev->dev, dev->func);
+ err = igb_probe(igb_dev);
+ if (err) {
+ continue;
+ }
+ printf("attaching to %s\n", devpath);
+ err = igb_attach(devpath, igb_dev);
+ if (err) {
+ printf("attach failed! (%s)\n", strerror(err));
+ continue;
+ }
+ err = igb_attach_tx(igb_dev);
+ if (err) {
+ printf("attach_tx failed! (%s)\n", strerror(err));
+ igb_detach(igb_dev);
+ continue;
+ }
+ goto out;
+ }
+ pci_cleanup(pacc);
+ return ENXIO;
+out:
+ pci_cleanup(pacc);
+ return 0;
+}
diff --git a/lib/common/avb_igb.h b/lib/common/avb_igb.h
new file mode 100644
index 00000000..1de3fa69
--- /dev/null
+++ b/lib/common/avb_igb.h
@@ -0,0 +1,10 @@
+#ifndef __AVB_IGB_H__
+#define __AVB_IGB_H__
+
+#include <igb.h>
+
+#define IGB_BIND_NAMESZ 24
+
+int pci_connect(device_t * igb_dev);
+
+#endif
diff --git a/lib/common/avb_srp.h b/lib/common/avb_srp.h
new file mode 100644
index 00000000..f4e4ab08
--- /dev/null
+++ b/lib/common/avb_srp.h
@@ -0,0 +1,6 @@
+#ifndef __AVB_SRP_H__
+#define __AVB_SRP_H__
+
+#define MRPD_PORT_DEFAULT 7500
+
+#endif
diff --git a/lib/igb/igb.c b/lib/igb/igb.c
index 30885862..d59a0fcb 100644
--- a/lib/igb/igb.c
+++ b/lib/igb/igb.c
@@ -1,6 +1,6 @@
/******************************************************************************
- Copyright (c) 2001-2016, Intel Corporation
+ Copyright (c) 2001-2017, Intel Corporation
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -46,8 +46,10 @@
#include <sys/resource.h>
#include <sys/mman.h>
#include <sys/user.h>
+#include <sys/stat.h>
#include <stdint.h>
#include <semaphore.h>
+#include <pthread.h>
#include "e1000_hw.h"
#include "e1000_82575.h"
@@ -99,6 +101,7 @@ static void igb_free_transmit_structures(struct adapter *adapter);
static void igb_free_receive_structures(struct adapter *adapter);
static void igb_tx_ctx_setup(struct tx_ring *txr, struct igb_packet *packet);
static void igb_free_receive_buffers(struct rx_ring *rxr);
+static int igb_create_lock(struct adapter *adapter);
int igb_probe(device_t *dev)
{
@@ -123,13 +126,14 @@ int igb_probe(device_t *dev)
return -ENXIO;
}
-#define IGB_SEM "igb_sem"
+#define IGB_SEM "/igb_sem"
int igb_attach(char *dev_path, device_t *pdev)
{
struct adapter *adapter;
- struct igb_bind_cmd bind;
+ struct igb_bind_cmd bind = {0};
int error = 0;
+ bool locked = false;
if (pdev == NULL)
return -EINVAL;
@@ -155,22 +159,20 @@ int igb_attach(char *dev_path, device_t *pdev)
goto err_prebind;
}
- adapter->memlock =
- sem_open(IGB_SEM, O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, 1);
-
- if (adapter->memlock == ((sem_t *)SEM_FAILED)) {
- error = errno;
- close(adapter->ldev);
- goto err_prebind;
+ if (igb_create_lock(adapter) != 0) {
+ error = -errno;
+ goto err_bind;
}
- if (sem_wait(adapter->memlock) != 0) {
- error = errno;
- close(adapter->ldev);
- sem_close(adapter->memlock);
- goto err_prebind;
+ adapter->active = 1;
+
+ if (igb_lock(pdev) != 0) {
+ error = -errno;
+ goto err_bind;
}
+ locked = true;
+
/*
* dev_path should look something "0000:01:00.0"
*/
@@ -215,7 +217,7 @@ int igb_attach(char *dev_path, device_t *pdev)
goto err_late;
}
- if (sem_post(adapter->memlock) != 0) {
+ if (igb_unlock(pdev) != 0) {
error = -errno;
goto err_gen;
}
@@ -226,8 +228,12 @@ err_late:
err_pci:
igb_free_pci_resources(adapter);
err_bind:
- sem_post(adapter->memlock);
- sem_close(adapter->memlock);
+ if (locked)
+ (void) igb_unlock(pdev);
+ if (adapter && adapter->memlock) {
+ (void) munmap(adapter->memlock, sizeof(pthread_mutex_t));
+ adapter->memlock = NULL;
+ }
close(adapter->ldev);
err_prebind:
free(pdev->private_data);
@@ -250,7 +256,7 @@ int igb_attach_tx(device_t *pdev)
if (adapter == NULL)
return -EINVAL;
- if (sem_wait(adapter->memlock) != 0)
+ if (igb_lock(pdev) != 0)
return -errno;
/* Allocate and Setup Queues */
@@ -269,7 +275,7 @@ int igb_attach_tx(device_t *pdev)
igb_reset(adapter);
release:
- if (sem_post(adapter->memlock) != 0)
+ if (igb_unlock(pdev) != 0)
return -errno;
return error;
@@ -288,7 +294,7 @@ int igb_attach_rx(device_t *pdev)
if (adapter == NULL)
return -EINVAL;
- if (sem_wait(adapter->memlock) != 0)
+ if (igb_lock(pdev) != 0)
return errno;
/*
@@ -302,7 +308,7 @@ int igb_attach_rx(device_t *pdev)
}
release:
- if (sem_post(adapter->memlock) != 0)
+ if (igb_unlock(pdev) != 0)
return errno;
return error;
@@ -318,12 +324,19 @@ int igb_detach(device_t *dev)
if (adapter == NULL)
return -ENXIO;
- if (sem_wait(adapter->memlock) != 0)
+ if (igb_lock(dev) != 0)
goto err_nolock;
+ /*
+ * Prevent access to device after calling igb_detach since associated
+ * resources will be freed up from here thus in particular multi-thread
+ * application other thread must not access device if this flag is off.
+ */
+ adapter->active = 0;
+
igb_reset(adapter);
- sem_post(adapter->memlock);
+ igb_unlock(dev);
igb_free_pci_resources(adapter);
@@ -334,7 +347,24 @@ int igb_detach(device_t *dev)
igb_free_receive_structures(adapter);
err_nolock:
- sem_close(adapter->memlock);
+ if (adapter->memlock) {
+ /*
+ * Do not unmap the shared memory region holding the pthread mutex.
+ *
+ * (void) munmap(adapter->memlock, sizeof(pthread_mutex_t));
+ *
+ * The pthread mutex is configured as a robust type mutex so that
+ * it can automatically be unlocked on process termination if needed.
+ * In order to complete the cleanup, the memory region holding the
+ * mutex instance must be accessible until that cleanup timing.
+ * Therefore we should not unmap the memory region here, otherwise
+ * the cleanup may fail.
+ *
+ * The mapped regions will automatically be unmapped at the end of
+ * the process termination.
+ */
+ adapter->memlock = NULL;
+ }
close(adapter->ldev);
@@ -364,7 +394,7 @@ int igb_suspend(device_t *dev)
txdctl = 0;
- if (sem_wait(adapter->memlock) != 0)
+ if (igb_lock(dev) != 0)
return errno;
/* stop but don't reset the Tx Descriptor Rings */
@@ -401,7 +431,7 @@ int igb_suspend(device_t *dev)
E1000_WRITE_REG(hw, E1000_RXDCTL(i), rxdctl);
}
- if (sem_post(adapter->memlock) != 0)
+ if (igb_unlock(dev) != 0)
return errno;
return 0;
@@ -428,7 +458,7 @@ int igb_resume(device_t *dev)
txdctl = 0;
- if (sem_wait(adapter->memlock) != 0)
+ if (igb_lock(dev) != 0)
return errno;
/* resume but don't reset the Tx Descriptor Rings */
@@ -468,7 +498,7 @@ int igb_resume(device_t *dev)
E1000_WRITE_REG(hw, E1000_RXDCTL(i), rxdctl);
}
- if (sem_post(adapter->memlock) != 0)
+ if (igb_unlock(dev) != 0)
return errno;
return 0;
@@ -484,7 +514,7 @@ int igb_init(device_t *dev)
if (adapter == NULL)
return -ENXIO;
- if (sem_wait(adapter->memlock) != 0)
+ if (igb_lock(dev) != 0)
return errno;
igb_reset(adapter);
@@ -500,7 +530,7 @@ int igb_init(device_t *dev)
igb_initialize_receive_units(adapter);
}
- if (sem_post(adapter->memlock) != 0)
+ if (igb_unlock(dev) != 0)
return errno;
return 0;
@@ -636,7 +666,7 @@ int igb_dma_malloc_page(device_t *dev, struct igb_dma_alloc *dma)
{
struct adapter *adapter;
int error = 0;
- struct igb_buf_cmd ubuf;
+ struct igb_buf_cmd ubuf = {0};
if (dev == NULL)
return -EINVAL;
@@ -647,12 +677,12 @@ int igb_dma_malloc_page(device_t *dev, struct igb_dma_alloc *dma)
if (adapter == NULL)
return -ENXIO;
- if (sem_wait(adapter->memlock) != 0) {
+ if (igb_lock(dev) != 0) {
error = errno;
goto err;
}
error = ioctl(adapter->ldev, IGB_MAPBUF, &ubuf);
- if (sem_post(adapter->memlock) != 0) {
+ if (igb_unlock(dev) != 0) {
error = errno;
goto err;
}
@@ -696,11 +726,11 @@ void igb_dma_free_page(device_t *dev, struct igb_dma_alloc *dma)
ubuf.physaddr = dma->dma_paddr;
- if (sem_wait(adapter->memlock) != 0)
+ if (igb_lock(dev) != 0)
goto err;
ioctl(adapter->ldev, IGB_UNMAPBUF, &ubuf);
- if (sem_post(adapter->memlock) != 0)
+ if (igb_unlock(dev) != 0)
goto err;
dma->dma_paddr = 0;
@@ -719,7 +749,7 @@ err:
**********************************************************************/
static int igb_allocate_queues(struct adapter *adapter)
{
- struct igb_buf_cmd ubuf;
+ struct igb_buf_cmd ubuf = {0};
int dev = adapter->ldev;
int i, error = 0;
@@ -742,6 +772,11 @@ static int igb_allocate_queues(struct adapter *adapter)
error = EBUSY;
goto tx_desc;
}
+
+ if (ubuf.physaddr % 128)
+ printf("warning: tx ring addr (0x%lx) is not a 128 byte-aligned\n",
+ ubuf.physaddr);
+
adapter->tx_rings[i].txdma.paddr = ubuf.physaddr;
adapter->tx_rings[i].txdma.mmap_size = ubuf.mmap_size;
adapter->tx_rings[i].tx_base = NULL;
@@ -762,6 +797,14 @@ static int igb_allocate_queues(struct adapter *adapter)
adapter->num_tx_desc = ubuf.mmap_size /
sizeof(union e1000_adv_tx_desc);
+ /*
+ * num_tx_desc must be always a multiple of 8 because the value of
+ * TDLEN must be a multipe of 128 and each descriptor has 16 bytes.
+ */
+ if (adapter->num_tx_desc % 8)
+ printf("warning: num_tx_desc(%d) is not a multiple of 8\n",
+ adapter->num_tx_desc);
+
memset((void *)adapter->tx_rings[i].tx_base, 0, ubuf.mmap_size);
adapter->tx_rings[i].tx_buffers =
(struct igb_tx_buffer *)
@@ -858,7 +901,7 @@ static void igb_initialize_transmit_units(struct adapter *adapter)
static void igb_free_transmit_structures(struct adapter *adapter)
{
int i;
- struct igb_buf_cmd ubuf;
+ struct igb_buf_cmd ubuf = {0};
for (i = 0; i < adapter->num_queues; i++) {
if (adapter->tx_rings[i].tx_base)
@@ -952,7 +995,7 @@ int igb_xmit(device_t *dev, unsigned int queue_index, struct igb_packet *packet)
if (packet == NULL)
return -EINVAL;
- if (sem_wait(adapter->memlock) != 0)
+ if (igb_lock(dev) != 0)
return errno;
packet->next = NULL; /* used for cleanup */
@@ -1044,7 +1087,7 @@ int igb_xmit(device_t *dev, unsigned int queue_index, struct igb_packet *packet)
++txr->tx_packets;
unlock:
- if (sem_post(adapter->memlock) != 0)
+ if (igb_unlock(dev) != 0)
return errno;
return error;
@@ -1061,11 +1104,11 @@ void igb_trigger(device_t *dev, u_int32_t data)
if (adapter == NULL)
return;
- if (sem_wait(adapter->memlock) != 0)
+ if (igb_lock(dev) != 0)
return;
E1000_WRITE_REG(&(adapter->hw), E1000_WUS, data);
- if (sem_post(adapter->memlock) != 0)
+ if (igb_unlock(dev) != 0)
return;
}
@@ -1103,6 +1146,7 @@ void igb_readreg(device_t *dev, u_int32_t reg, u_int32_t *data)
int igb_lock(device_t *dev)
{
struct adapter *adapter;
+ int error = -1;
if (dev == NULL)
return -ENODEV;
@@ -1111,7 +1155,32 @@ int igb_lock(device_t *dev)
if (adapter == NULL)
return -ENXIO;
- return sem_wait(adapter->memlock);
+ if (adapter->active != 1) // detach in progress
+ return -ENXIO;
+
+ if (!adapter->memlock)
+ return -ENXIO;
+
+ error = pthread_mutex_lock(adapter->memlock);
+ switch (error) {
+ case 0:
+ break;
+ case EOWNERDEAD:
+ // some process terminated without unlocking the mutex
+ if (pthread_mutex_consistent(adapter->memlock) != 0)
+ return -errno;
+ break;
+ default:
+ return -errno;
+ break;
+ }
+
+ if (adapter->active != 1) {
+ (void) pthread_mutex_unlock(adapter->memlock);
+ return -ENXIO;
+ }
+
+ return 0;
}
int igb_unlock(device_t *dev)
@@ -1125,7 +1194,10 @@ int igb_unlock(device_t *dev)
if (adapter == NULL)
return -ENXIO;
- return sem_post(adapter->memlock);
+ if (!adapter->memlock)
+ return -ENXIO;
+
+ return pthread_mutex_unlock(adapter->memlock);
}
/**********************************************************************
@@ -1155,7 +1227,7 @@ void igb_clean(device_t *dev, struct igb_packet **cleaned_packets)
*cleaned_packets = NULL; /* nothing reclaimed yet */
- if (sem_wait(adapter->memlock) != 0)
+ if (igb_lock(dev) != 0)
return;
for (i = 0; i < adapter->num_queues; i++) {
@@ -1240,7 +1312,7 @@ void igb_clean(device_t *dev, struct igb_packet **cleaned_packets)
if (txr->tx_avail >= IGB_QUEUE_THRESHOLD)
txr->queue_status &= ~IGB_QUEUE_DEPLETED;
}
- sem_post(adapter->memlock);
+ igb_unlock(dev);
}
/*********************************************************************
@@ -1285,6 +1357,11 @@ static int igb_allocate_rx_queues(struct adapter *adapter)
error = EBUSY;
goto rx_desc;
}
+
+ if (ubuf.physaddr % 128)
+ printf("warning: rx ring addr (0x%lx) is not a 128 byte-aligned\n",
+ ubuf.physaddr);
+
adapter->rx_rings[i].rxdma.paddr = ubuf.physaddr;
adapter->rx_rings[i].rxdma.mmap_size = ubuf.mmap_size;
adapter->rx_rings[i].rx_base = NULL;
@@ -1303,6 +1380,14 @@ static int igb_allocate_rx_queues(struct adapter *adapter)
adapter->num_rx_desc = ubuf.mmap_size /
sizeof(union e1000_adv_rx_desc);
+ /*
+ * num_rx_desc must be always a multiple of 8 because the value of
+ * RDLEN must be a multipe of 128 and each descriptor has 16 bytes.
+ */
+ if (adapter->num_rx_desc % 8)
+ printf("num_rx_desc(%d) is not a multiple of 8\n",
+ adapter->num_rx_desc);
+
memset((void *)adapter->rx_rings[i].rx_base, 0, ubuf.mmap_size);
adapter->rx_rings[i].rx_buffers =
(struct igb_rx_buffer *)
@@ -1542,6 +1627,9 @@ int igb_refresh_buffers(device_t *dev, u_int32_t idx,
if (adapter == NULL)
return -EINVAL;
+ if (adapter->active != 1) // detach in progress
+ return -ENXIO;
+
if (rxbuf_packets == NULL)
return -EINVAL;
@@ -1555,6 +1643,11 @@ int igb_refresh_buffers(device_t *dev, u_int32_t idx,
if (sem_trywait(&rxr->lock) != 0)
return errno; /* EAGAIN */
+ if (adapter->active != 1) {
+ sem_post(&rxr->lock);
+ return -ENXIO;
+ }
+
i = j = rxr->next_to_refresh;
cur_pkt = *rxbuf_packets;
@@ -1602,7 +1695,7 @@ int igb_refresh_buffers(device_t *dev, u_int32_t idx,
* processing the packet then return the linked list of associated resources.
*
**********************************************************************/
-int igb_receive(device_t *dev, unsigned int queue_index,
+int igb_receive(device_t *dev, unsigned int queue_index,
struct igb_packet **received_packets, u_int32_t *count)
{
struct adapter *adapter;
@@ -1622,6 +1715,9 @@ int igb_receive(device_t *dev, unsigned int queue_index,
if (adapter == NULL)
return -ENXIO;
+ if (adapter->active != 1) // detach in progress
+ return -ENXIO;
+
if (queue_index > adapter->num_queues)
return -EINVAL;
@@ -1643,6 +1739,11 @@ int igb_receive(device_t *dev, unsigned int queue_index,
if (sem_trywait(&rxr->lock) != 0)
return errno; /* EAGAIN */
+ if (adapter->active != 1) {
+ sem_post(&rxr->lock);
+ return -ENXIO;
+ }
+
/* Main clean loop - receive packets until no more
* received_packets[]
*/
@@ -1652,10 +1753,10 @@ int igb_receive(device_t *dev, unsigned int queue_index,
if (i%2)
printf("\033[2A");
- printf("desc.status_error=%x desc.length=%x desc.vlan=%x desc.rss=%x desc.pkt_info=%x desc.hdr_info=%x\n",
- cur->wb.upper.status_error,
- cur->wb.upper.length,
- cur->wb.upper.vlan,
+ printf("desc.status_error=%x desc.length=%x desc.vlan=%x desc.rss=%x desc.pkt_info=%x desc.hdr_info=%x\n",
+ cur->wb.upper.status_error,
+ cur->wb.upper.length,
+ cur->wb.upper.vlan,
cur->wb.lower.hi_dword.rss,
cur->wb.lower.lo_dword.hs_rss.pkt_info,
cur->wb.lower.lo_dword.hs_rss.hdr_info);
@@ -1770,7 +1871,7 @@ int igb_get_wallclock(device_t *dev, u_int64_t *curtime, u_int64_t *rdtsc)
hw = &adapter->hw;
- if (sem_wait(adapter->memlock) != 0)
+ if (igb_lock(dev) != 0)
return errno;
/* sample the timestamp bracketed by the RDTSC */
@@ -1799,7 +1900,7 @@ int igb_get_wallclock(device_t *dev, u_int64_t *curtime, u_int64_t *rdtsc)
}
}
- if (sem_post(adapter->memlock) != 0) {
+ if (igb_unlock(dev) != 0) {
error = errno;
goto err;
}
@@ -1837,7 +1938,10 @@ struct timespec timespec_addns(struct timespec *a, unsigned long addns)
return *a;
}
-#define TS2NS(ts) (((ts).tv_sec*1000000000)+(ts).tv_nsec)
+static inline u_int32_t TS2NS(struct timespec ts)
+{
+ return ((ts.tv_sec*1000000000)+ts.tv_nsec);
+}
int igb_gettime(device_t *dev, clockid_t clk_id, u_int64_t *curtime,
struct timespec *system_time)
@@ -1858,7 +1962,7 @@ int igb_gettime(device_t *dev, clockid_t clk_id, u_int64_t *curtime,
hw = &adapter->hw;
- if (sem_wait(adapter->memlock) != 0)
+ if (igb_lock(dev) != 0)
return errno;
/* sample the timestamp bracketed by the clock_gettime() */
@@ -1892,7 +1996,7 @@ int igb_gettime(device_t *dev, clockid_t clk_id, u_int64_t *curtime,
}
}
- if (sem_post(adapter->memlock) != 0) {
+ if (igb_unlock(dev) != 0) {
error = errno;
goto err;
}
@@ -1913,7 +2017,7 @@ int igb_set_class_bandwidth(device_t *dev, u_int32_t class_a, u_int32_t class_b,
u_int32_t linkrate;
struct adapter *adapter;
struct e1000_hw *hw;
- struct igb_link_cmd link;
+ struct igb_link_cmd link = {0};
int err;
float class_a_percent, class_b_percent;
int error = 0;
@@ -1954,7 +2058,7 @@ int igb_set_class_bandwidth(device_t *dev, u_int32_t class_a, u_int32_t class_b,
if (tpktsz_b > 1500)
return -EINVAL;
- if (sem_wait(adapter->memlock) != 0)
+ if (igb_lock(dev) != 0)
return errno;
tqavctrl = E1000_READ_REG(hw, E1000_TQAVCTRL);
@@ -2048,7 +2152,7 @@ int igb_set_class_bandwidth(device_t *dev, u_int32_t class_a, u_int32_t class_b,
E1000_WRITE_REG(hw, E1000_TQAVCTRL, tqavctrl);
unlock:
- if (sem_post(adapter->memlock) != 0)
+ if (igb_unlock(dev) != 0)
error = errno;
return error;
@@ -2066,7 +2170,7 @@ int igb_set_class_bandwidth2(device_t *dev, u_int32_t class_a_bytes_per_second,
int temp;
struct adapter *adapter;
struct e1000_hw *hw;
- struct igb_link_cmd link;
+ struct igb_link_cmd link = {0};
int err;
float class_a_percent, class_b_percent;
int error = 0;
@@ -2096,7 +2200,7 @@ int igb_set_class_bandwidth2(device_t *dev, u_int32_t class_a_bytes_per_second,
if (link.duplex != FULL_DUPLEX)
return -EINVAL;
- if (sem_wait(adapter->memlock) != 0)
+ if (igb_lock(dev) != 0)
return errno;
tqavctrl = E1000_READ_REG(hw, E1000_TQAVCTRL);
@@ -2186,7 +2290,7 @@ int igb_set_class_bandwidth2(device_t *dev, u_int32_t class_a_bytes_per_second,
E1000_WRITE_REG(hw, E1000_TQAVCTRL, tqavctrl);
unlock:
- if (sem_post(adapter->memlock) != 0)
+ if (igb_unlock(dev) != 0)
error = errno;
return error;
@@ -2217,6 +2321,7 @@ int igb_setup_flex_filter(device_t *dev, unsigned int queue_id,
struct e1000_hw *hw;
u32 i = 0, j, k;
u32 fhft, wufc;
+ u_int8_t *filter_buf = filter;
if (dev == NULL)
return -EINVAL;
@@ -2234,6 +2339,20 @@ int igb_setup_flex_filter(device_t *dev, unsigned int queue_id,
if (filter_len > 128)
return -EINVAL;
+ if (filter_len % 8) {
+ unsigned int aligned_filter_len = ((filter_len + (8 - 1)) / 8) * 8;
+
+ printf ("warning: filter_len(%d) should be a 8 byte aligned value\n",
+ filter_len);
+
+ filter_buf = calloc(1, aligned_filter_len);
+ if (!filter_buf)
+ return -ENOMEM;
+
+ memcpy((void*)filter_buf, (void*)filter, (size_t)filter_len);
+ filter_len = aligned_filter_len;
+ }
+
hw = &adapter->hw;
/*
@@ -2280,7 +2399,7 @@ int igb_setup_flex_filter(device_t *dev, unsigned int queue_id,
for (j = 0; j < 8; j += 4) {
fhft = 0;
for (k = 0; k < 4; k++)
- fhft |= ((u32)(filter[i + j + k])) << (k * 8);
+ fhft |= ((u32)(filter_buf[i + j + k])) << (k * 8);
E1000_WRITE_REG_ARRAY(hw, E1000_FHFT(filter_id),
(i/2) + (j/4), fhft);
}
@@ -2298,6 +2417,9 @@ int igb_setup_flex_filter(device_t *dev, unsigned int queue_id,
wufc |= (E1000_WUFC_FLX0 << filter_id) | E1000_WUFC_FLEX_HQ;
E1000_WRITE_REG(hw, E1000_WUFC, wufc);
+ if (filter_buf && (filter_buf != filter))
+ free(filter_buf);
+
return 0;
}
@@ -2326,3 +2448,128 @@ int igb_clear_flex_filter(device_t *dev, unsigned int filter_id)
return 0;
}
+
+static int igb_create_lock(struct adapter *adapter)
+{
+ int error = -1;
+ int fd = -1;
+ bool locked = false;
+ struct flock fl;
+ struct stat stat;
+ mode_t fmode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP;
+
+ bool attr_allocated = false;
+ pthread_mutexattr_t attr;
+
+ if (!adapter) {
+ errno = EINVAL;
+ goto err;
+ }
+
+ if (adapter->memlock) { // already created
+ errno = EINVAL;
+ goto err;
+ }
+
+ /*
+ * inter-process syncronization
+ *
+ * Use a posix mutex for inter-process syncronization
+ *
+ * igb lib used a posix named semaphore to protect concurrent accesses
+ * from multiple processes. But since the posix semaphore cannot be
+ * automatically released on process termination, if some process holding
+ * the semaphore terminates without releasing it, other processes cannot
+ * acquire the semaphore afterward. This could potentially cause a denial
+ * of service condition.
+ */
+
+ fd = shm_open(IGB_SEM, O_RDWR|O_CREAT|O_CLOEXEC, fmode);
+ if (fd < 0)
+ goto err;
+
+ (void) fchmod(fd, fmode); // just to make sure fmode is applied
+
+ // shared memory holding the mutex instance
+ adapter->memlock = (pthread_mutex_t*) mmap(NULL, sizeof(pthread_mutex_t),
+ PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+ if (!adapter->memlock)
+ goto err;
+
+ /*
+ * Exclusive access lock
+ *
+ * At this moment the posix mutex in the shared memory might not be
+ * available yet and it needs initialization. We need to protect the
+ * initialization code otherwise multiple processes could concurrently
+ * do initialization. Create an exclusive access section by applying
+ * the file-lock against the shared memory file.
+ *
+ * By the way the file-lock itself could safely be used for inter-process
+ * synchronization because it also automatically gets unlocked on process
+ * termination. But it is slower than the posix-mutex. So we should use
+ * the posix-mutex once its initialization done.
+ */
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = 1;
+ fl.l_pid = getpid();
+
+ if (fcntl(fd, F_SETLKW, &fl) != 0)
+ goto err;
+
+ locked = true;
+
+ if (fstat(fd, &stat) != 0)
+ goto err;
+
+ if (stat.st_size == 0) { // file is empty, do initialization
+ /*
+ * file-size becomes non-zero and given that when other processes
+ * attach lib igb we can skip the initialization code for the mutex.
+ */
+ if (ftruncate(fd, sizeof(pthread_mutex_t)) != 0)
+ goto err;
+
+ if (pthread_mutexattr_init(&attr) != 0)
+ goto err;
+
+ attr_allocated = true;
+
+ // to be used for both inter-process and inter-thread synchronization
+ if (pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED) != 0)
+ goto err;
+
+ // to avoid dead lock due to a dead process holding the semaphore
+ if (pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST) != 0)
+ goto err;
+
+ if (pthread_mutex_init(adapter->memlock, &attr) != 0)
+ goto err;
+ }
+
+ error = 0;
+err:
+ // no actual effect but to avoid a warning from a static code analyzer
+ if (attr_allocated)
+ (void) pthread_mutexattr_destroy(&attr);
+
+ if (error != 0) {
+ error = -errno;
+ if (adapter && adapter->memlock) {
+ (void) munmap(adapter->memlock, sizeof(pthread_mutex_t));
+ adapter->memlock = NULL;
+ }
+ }
+
+ if (fd >= 0) {
+ if (locked) {
+ fl.l_type = F_UNLCK;
+ (void) fcntl(fd, F_SETLK, &fl);
+ }
+ (void) close(fd);
+ }
+
+ return error;
+}
diff --git a/lib/igb/igb_internal.h b/lib/igb/igb_internal.h
index ebf7d1d8..b99ee063 100644
--- a/lib/igb/igb_internal.h
+++ b/lib/igb/igb_internal.h
@@ -158,7 +158,7 @@ struct rx_ring {
struct adapter {
struct e1000_hw hw;
- sem_t *memlock;
+ pthread_mutex_t *memlock;
int ldev; /* file descriptor to igb */
@@ -185,6 +185,7 @@ struct adapter {
struct nettime_compare compare;
struct hwtstamp_ctrl hwtstamp;
#endif
+ int active;
};
/*
diff --git a/run_maap.sh b/run_maap.sh
new file mode 100755
index 00000000..740df758
--- /dev/null
+++ b/run_maap.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+# Simple script to run MAAP
+
+if [ "$#" -eq "0" ]; then
+ echo "please enter network interface name as parameter. For example:"
+ echo "sudo ./run_maap.sh eth1"
+ exit -1
+fi
+
+./daemons/maap/linux/build/maap_daemon -i $1
diff --git a/run_shaper.sh b/run_shaper.sh
new file mode 100755
index 00000000..2e7a5d69
--- /dev/null
+++ b/run_shaper.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+# Simple script to run the shaper daemon
+
+./daemons/shaper/shaper_daemon
diff --git a/run_srp.sh b/run_srp.sh
index f75c9c12..b45c5d4e 100755
--- a/run_srp.sh
+++ b/run_srp.sh
@@ -7,4 +7,4 @@ if [ "$#" -eq "0" ]; then
exit -1
fi
-daemons/mrpd/mrpd -s -i $1
+daemons/mrpd/mrpd -mvs -i $1
diff --git a/thirdparty/cpputest b/thirdparty/cpputest
-Subproject a4d25c2e676f78a25668df6f20d479f3a383879
+Subproject 69d1b24fa92fc8c3cf5542bf44293c3e05cfbf0
diff --git a/travis.sh b/travis.sh
index 54a2b78a..b10cc42c 100755
--- a/travis.sh
+++ b/travis.sh
@@ -5,6 +5,7 @@ make lib
make daemons_all
make examples_all
make avtp_pipeline
+make avtp_avdecc
mkdir build
cd build
cmake .. -G "Unix Makefiles"