1Attaching External Custom Decoders {#custom_decoders} 2================================== 3 4@brief A description of the C API external decoder interface. 5 6Introduction 7------------ 8 9An external custom decoder is one which decodes a CoreSight trace byte stream from a source other 10than an ARM core which cannot be decoded by the standard built-in decoders within the library. 11 12An example of this may be a trace stream from a DSP device. 13 14The external decoder API allows a suitable decoder to be attached to the library and used in the 15same way as the built-in decoders. This means that the external decoder can be created and destroyed 16using the decode tree API, and will integrate seamlessly with any ARM processor decoders that are part 17of the same tree. 18 19An external decoder will be required to use three standard structures:- 20 21- `ocsd_extern_dcd_fact_t` : This is a decoder "factory" that allows the creation of the custom decoders. 22- `ocsd_extern_dcd_inst_t` : This structure provides decoder data to the library for a single decoder instance. 23- `ocsd_extern_dcd_cb_fns` : This structure provides a set of callback functions allowing the decoder to use library functionality in the same way as built-in decoders. 24 25These structures consist of data and function pointers to allow integration with the library infrastructure. 26 27Registering A Decoder 28--------------------- 29 30A single API function is provided to allow a decoder to be registered with the library by name. 31 32 ocsd_err_t ocsd_register_custom_decoder(const char *name, ocsd_extern_dcd_fact_t *p_dcd_fact); 33 34This registers the custom decoder with the library using the supplied name and factory structure. 35As part of the registration function the custom decoder will be assigned a protocol ID which may be used in 36API functions requiring this parameter. 37 38Once registered, the standard API functions used with the built-in decoders will work with the custom decoder. 39 40The Factory Structure 41--------------------- 42This structure contains the interface that is registered with the library to allow the creation of custom decoder instances. 43 44The mandatory functions that must be provided include: 45- `fnCreateCustomDecoder` : Creates a decoder. This function will fill in a `ocsd_extern_dcd_inst_t` structure for the decoder instance. 46- `fnDestroyCustomDecoder` : Destroys the decoder. Takes the `decoder_handle` attribute of the instance structure. 47- `fnGetCSIDFromConfig` : Extracts the CoreSight Trace ID from the decoder configuration structure. 48 May be called before the create function. The CSID is used as part of the creation process to 49 attach the decoder to the correct trace byte stream. 50 51`fnPacketToString` : This optional function will provide a human readable string from a protocol specific packet structure. 52 53`protocol_id` : This is filled in when the decoder type is registered with the library. Used in some API 54 calls to specify the decoder protocol type. 55 56 57 58Creating a Custom Decoder Instance 59---------------------------------- 60 61Once the custom decoder factory has been registered with the library then using the decoder uses the standard creation API:- 62 63`ocsd_dt_create_decoder(const dcd_tree_handle_t handle, const char *decoder_name, const int create_flags, 64 const void *decoder_cfg, unsigned char *pCSID)` 65 66 67This creates a decoder by type name in the current decode tree and attaches it to the trace data stream associated with a CoreSight trace ID extracted from 68the trace configuration. 69 70To create a custom decoder instance simply use the custom name and a pointer to the custom configuration structure. 71 72Calling this on a custom decoder name will result in a call to the factor function `fnCreateCustomDecoder` function:- 73`ocsd_err_t CreateCustomDecoder(const int create_flags, const void *decoder_cfg, const ocsd_extern_dcd_cb_fns *p_lib_callbacks, ocsd_extern_dcd_inst_t *p_decoder_inst)` 74 75This will first require that the `ocsd_extern_dcd_inst_t` structure is populated. 76 77There is are two mandatory function calls in this structure that may be called by the library 78 79 `fnTraceDataIn` : the decoder must provide this as this is called by the library to provide the 80 raw trace data to the decoder. 81 82 `fn_update_pkt_mon` : Allows the library to communicate when packet sink / packet monitor interfaces are attached to the decoder and in use. 83 84The decoder creation process will also fill in the additional information to allow the library to correctly call back into the custom decoder using the `decoder_handle` parameter. 85 86Secondly the library will provide a structure of callback functions - `ocsd_extern_dcd_cb_fns` - that the decoder can use to access standard library functionality. 87This includes the standard error and message logging functions, the memory access and ARM instruction decode functions, plus the current output sink for generic 88trace elements generated by the decoder. The decoder is not required to use these functions - indeed the ARM instruction decode will not be useful to none ARM 89architecture decoders, but should where possible use these functions if being used as part of a combined ARM / custom decoder tree. This will simplify client 90use of the external decoders. 91 92The `create_flags` parameter will describe the expected operational mode for the decoder. The flags are:- 93- `OCSD_CREATE_FLG_PACKET_PROC` : Packet processing only - the decoder will split the incoming stream into protocol trace packets and output these. 94- `OCSD_CREATE_FLG_FULL_DECODER` : Full decode - the decoder will split the incoming stream into protocol trace packets and further decode and analyse these to produce generic trace output which may describe the program flow. 95 96Finally the decoder creation function will interpret the custom configuration (`decoder_cfg`) and fill in the CoreSight Trace ID parameter `pCSID` 97for this decoder instance. Decoder configuration structures describe registers and parameters used in programming up the trace source. The only 98minimum requirement is that it is possible to extract a CoreSight trace ID from the configuration to allow the library to attach the correct byte 99stream to the decoder. 100 101 102Example : The echo_test decoder 103-------------------------------- 104 105The echo_test decoder is provided to both test the C-API interfaces provided for using custom decoders and as a worked example for using these interfaces. 106 107This decoder is initialised and created by the `c_api_pkt_print_test` program when the `-extern` command line option is used. 108 109In order to use a custom decoder, the header files for that decoder must be included by the client as they are not part of the built-in provided by the standard library includes. 110 111 #include "ext_dcd_echo_test_fact.h" // provides the ext_echo_get_dcd_fact() fn 112 #include "ext_dcd_echo_test.h" // provides the echo_dcd_cfg_t config structure. 113 114The `register_extern_decoder()` function in the test shows how simple the API is to use. 115 116The implementation of the decoder provides an external function to get a factory structure. 117 118 p_ext_fact = ext_echo_get_dcd_fact(); 119 120Assuming this returns a structure then the decoder is registered by name. 121 122 if (p_ext_fact) 123 { 124 err = ocsd_register_custom_decoder(EXT_DCD_NAME, p_ext_fact); 125 } 126 127After this the test uses the same code path as the built in decoders when testing the custom decoder. 128The test function `ocsd_err_t create_decoder_extern(dcd_tree_handle_t dcd_tree_h)` is called if the test parameters indicate a custom decoder is needed. 129This populates the custom configuration structure specific to the echo_test decoder (`echo_dcd_cfg_t`), then passes this plus the decoder name to the same `create_generic_decoder()` function used when testing the built in decoders. 130 131 132 static ocsd_err_t create_decoder_extern(dcd_tree_handle_t dcd_tree_h) 133 { 134 echo_dcd_cfg_t trace_cfg_ext; 135 136 /* setup the custom configuration */ 137 trace_cfg_ext.cs_id = 0x010; 138 if (test_trc_id_override != 0) 139 { 140 trace_cfg_ext.cs_id = (uint32_t)test_trc_id_override; 141 } 142 143 /* create an external decoder - no context needed as we have a single stream to a single handler. */ 144 return create_generic_decoder(dcd_tree_h, EXT_DCD_NAME, (void *)&trace_cfg_ext, 0); 145 } 146 147From the test program perspective, these are the only changes made to the test program to test this decoder. 148The `create_generic_decoder()` then uses the normal C-API calls such as `ocsd_dt_create_decoder()` and `ocsd_dt_attach_packet_callback()` to hook the decoder into the decode tree infrastructure. 149