|
TRX Host Driver
|
Breaks down a received packet and copies the HEADER, PAYLOAD, RSSI,
The TRX Host Driver is a simple API set for controlling the TRX over a SPI interface. The API supports initializing the TRX, scheduling RF commands, and several utility functions, including time synchronization.
Each command sent to the TRX must pass over a SPI interface and adhere to a specific TRX wire-interface protocol. This interface can have varying speeds and cause delays based on other events occurring in the system. For this reason, all TRX Host Driver API calls are non-blocking and require a callback, with the exception of initialization and closing of the driver.
See TRX Host API Interface for a detailed description of available functions and structures.
The TRX Host Driver APIs provide a simple interface for interacting with the TRX; effectively abstracting away many of the concepts described in this section. However, understanding the basics of the communication between a Host and the TRX can help users better understand the APIs provided and make use of them in the most efficient manner for their application.
The Host communicates with the TRX over a 4-wire SPI interface with an additional fifth input signal designated as "INT" or interrupt. The INT signal alerts the host when the TRX has data available to send on the POCI line, effectively requesting that the host start a SPI transaction to retrieve the data.
Data transmitted over the SPI interface conforms to a proprietary formatting protocol specific to the TRX.
Key characteristics of the protocol include:
The following data structures form the basis of communication between a Host and the TRX. Together they enable most operations including storing commands to the TRX, submitting them to the radio, and managing "streams" of payload data being transmitted and received.
The following is the basic flow for submitting a TX operation to the TRX. While this describes a high level overview of the process, much of this can be abstracted from users by using the TRX Host Driver APIs.
When processing radio packets, both in RX and TX direction, the TRX uses an internal packet format regardless of PHY used. This is done in order to keep information essential for processing the packet consistent across all PHYs.
Compared to frames received/transmitted on-air, internal packets:
the PHY payload (PSDU) is not changed between the internal packets and radio packets.
For FSK-modulated PHYs, where complete control over the header generation is required, it is possible to select the GenFSK header type.
In this mode, the header is completely pass-through and is not modified by the TRX coming or going. Instead the PHY configuration contains information that allows the TRX to parse the TX and RX headers as-is.
| Parameter | Description |
|---|---|
| Length index | Bit-position of the length field |
| Length size | Size in bits of the length field |
All other configurations than length are static, and it's not possible to dynamically change CRC or whitening depending on the incoming or outgoing header.
The PHY header formatting for an on-air packet depends on which PHY is used and the user should provide information to the modem on what these fields should be populated with, along with the lenght of the packet. The first 4 bytes of the payload sent over by the user to the TRX is hence, ear marked for this purpose and is refered to as the PHY internal header.
For example, for an OFDM PHY, the user should provide input on the length of the packet, modulation, rate etc. Similarly, for a SUNFSK PHY, the user should provide input on the length of the packet, modulation, whitening, fcs mode etc. Thus, the interpretation of these 4 bytes depends on the PHY used.
Also, When Wi-SUN MDR feature is being used, TRX may receive a packet on an alternate PHY different to what the TRX is initially configured to. The info on which PHY the packet is received on is populated in the internal PHY header by the TRX and sent over to the Host/ User.
The different fields of the internal PHY header for different PHYs and when Wi-SUN MDR feature is used are detailed below.
For OFDM PHYs, rate is set through parameter in the packet header. A rate enum helper is provided in TRX.h.
The TRX Host Driver APIs provide a simple interface for interacting with the TRX. The main goals of the driver include:
Many APIs provided by the TRX Host Driver enable users to subscribe to TRX_EVENTS and receive a callback when they occur. This model allows the developers to efficiently make use of all features on the TRX for their respective applications.
There exists only one prototype for callbacks from the host driver, enabling users to funnel multiple events to a single callback or split them into separate functions, each with a specific purpose.
The TRX Host Driver can be initialized with a blocking call to TRX_Host_open(), with a pointer to a TRX_Host_Params structure. During initialization of the TRX Host Driver, the TRX is reset and the PHY configurations stored in NV will be discovered. This involves sending a TRX_Request_ConfigList to the TRX and waiting until all the configs are received by the host via TRX_Request_ConfigListResponse.
## Example
RF settings for PHYs and front ends to use on the TRX must first be loaded from the Host using the TRX_Host_storeConfig API. These settings are often referred to as RCL (Radio Control Layer) settings or Configurations and can be generated using Smart RF Studio. The following parameters are required to load a configuration to the TRX:
The configuration id and reference tuple uniquely identify each configuration on the TRX.
The configuration id is a unique identifier for each configuration in the range [0, TRX_MAX_CONFIGURATIONS]. The application can arbitrarily select the value as long as it's within this range. Only one configuration can exist on the TRX for a given configuration id.
The 32-bit reference can be used by the application to tag any metadata with the configuration. During Configuration Discovery, both the configuration id and the reference tagged to a configuration are sent over to the Host.
For example, if application wishes to store different LORA PHYs on the TRX, the application can set the reference for each configuration to a value indicative of what the preamble length is. Thus, the reference acts as a way to quickly identify what this configuration is for.
Another example, a 32 bit hash of the configuration blob can be set as reference and may be used for integrity check at the application level during Configuration Discovery.
The application is free to set the reference to 0, if it does not want to associate any meta data with the configuration.
See also Configuration Discovery for more details.
Front end configurations are handled the same as PHY configurations, with one exception; they must always be stored using the configuration id TRX_CONFIG_ID_FRONTEND. Everything else regarding the generation, storing and erasing of front end configurations is identical to PHY configurations.
Each configuration is stored in RAM on the TRX but can optionally be persisted to non-volatile storage using the TRX_Host_persistConfig API. Persisting a configuration provides two key benefits:
It's recommended to persist configurations that your application is likely to load at every initialization.
The TRX_Host_eraseNv() can be used to erase all configs stored in non-volatile memory on the TRX. Executing this API will result in the host sending a TRX_Request_NvErase to the TRX and the provided callback will be executed with the TRX_EventNvEraseComplete event. On success, all of NV on the TRX will be erased, making it necessary to re-load the PHY configurations afterwards.
When TRX_Host_open() is called, the host driver will automatically start discovery of configurations stored in non-volatile memory on the TRX. The driver uses a combination of the following to uniquely map configurations:
When a configuration is discovered during initialization, it's details are added to an internal database and tracked. Subsequent calls to TRX_Host_storeConfig, with a matching configuration id and 32-bit reference will return a status of TRX_Host_Config_Exists unless the force argument is set to true. Also, subsequent calls to TRX_Host_storeConfig, with a matching configuration id but a different 32-bit reference, will cause the original configuration to be overwritten.
The code generated by Smart RF Studio includes an array containing a bundle of register settings. It is generated with user input and will usually contain all the settings necessary to send or receive RF packets on a characterized PHY.
It contains semi-compressed register values, and may also contain delta configurations that may alter the default PHY behavior. These delta configurations are also sometimes called subPhys.
A delta configuration is nothing more than tiny snippets of register values that are applied if the user-selected option mask matches the snippet header's identifier.
In this way, it is possible to store PHY variants very efficiently, as typically only a few registers vary between small variations of a PHY.
All RF commands can be submitted to the TRX via the TRX_Host_storeCmds() API but require the following to be loaded prior to command submission:
There is no requirement on the order in which these are stored on the TRX, only that they are stored prior to command submission. Finally, the command can be submitted to the radio using either the pCmdToSubmit argument to TRX_Host_storeCmds() or the TRX_Host_submitCmd() API.
Each command uses the TRX_Request_CommandStore structure for common parameters and is differentiated based on the TRX_Request_CommandStore.cmd_id and TRX_Request_CommandStore.params, which details command specific parameters. There is a high degree of flexibility when creating commands, including the ability to set frequency, power, chaining multiple commands, and interrupting ongoing radio operations.
Available commands as described in TRX_RadioCommands
| TRX_RadioCommands (Command ID) | TRX_RadioCommand_Params | Description |
|---|---|---|
| TRX_RadioCommand_Transmit | TRX_Request_CommandStore_Transmit_Params | Transmit command |
| TRX_RadioCommand_Receive | TRX_Request_CommandStore_Receive_Params | Receive command |
| TRX_RadioCommand_CarrierSense | TRX_Request_CommandStore_CarrierSense_Params | Carrier Sense command |
| TRX_RadioCommand_TransmitTest | TRX_Request_CommandStore_TransmitTest_Params | Transmit test command used to create a continuous wave |
| TRX_RadioCommand_ReceiveTest | TRX_Request_CommandStore_ReceiveTest_Params | Receive test command used to get immediate RSSI and test other RX functionality |
The frequency of a given command can be set in the command specific TRX_Request_CommandStore.params structure. When a command is provided to the TRX, a frequency calibration operation occurs prior to submission to the radio. The time required to calibrate is non-trivial and calibration is required only if the frequency changes more than +/- 2MHz compared to the last calibrated frequency.
For this reason, the TRX provides the ability to specify a command's frequency as a "delta" of the last calibrated frequency. This concept is central to supporting Wi-SUN MDR on the TRX and is used to reduce delay between time critical operations. An example of this can be seen below:
The transmit power can be set in the TRX_RadioCommand_Params.tx or TRX_RadioCommand_Params.txTest structure of the TRX_Request_CommandStore.params union.
The TRX_RadioCommand_Transmit provides the ability to set power in one of two ways:
The PHY configuration for a given command can be set in the command specific TRX_Request_CommandStore.params structure. Each PHY configuration has an accompanying 'option mask' used as a bit mask to enable various subPHYs. This be used to have one base configuration with an option mask that enables different preamble lengths, sync words, etc without consuming a new configuration slot on the TRX.
There may be up to TRX_MAX_CONFIGURATIONS different configuration arrays stored on the device at any time, but only up to 3 may be referenced by a command. Starting with phy0, each referenced PHY is then applied to the modem in a sequential order. This means that if phy2 contains a register value that differs from a value in phy0 or phy1, the setting from the array referenced in phy2 will take effect.
In this way, it is possible to have all configurations stored on the TRX in Flash, and make TRX apply small delta changes to the first configuration at runtime. The following is an example of setting these parameters for a TX command.
When storing commands to the TRX using TRX_Host_storeCmds(), the user can subscribe to events and provide a callback using the subscribedEvents and callback arguments respectively. The following events can be subscribed to for a command:
In addition, commands are automatically subscribed to the following events:
Commands can be configured to trigger based on the choice of TRX_Command_TriggerType and optional TRX_Command_ScheduleParam in the TRX_Request_CommandStore structure. The following table provides a description of each available trigger.
| TRX_Command_TriggerType | Description | Setting Time |
|---|---|---|
| Command_Trigger_Immediate | Start immediately | N/A |
| Command_Trigger_IoEdge 1 | Start on edge | N/A |
| Command_Trigger_Time_Absolute | Start on absolute time match | cmdTx.trigger_param = <ABSOLUTE_TIME> |
| Command_Trigger_Time_Relative_Previous_Start | Start relative to previous command start | cmdTx.trigger_param = <RELATIVE_TIME> |
| Command_Trigger_Time_Relative_Previous_End | Start relative to previous command end | cmdTx.trigger_param = <RELATIVE_TIME> |
1Application must enable GPIO triggering with TRX_Host_utilDioSetup() and assert the IO after the TRX_EventCmdSubmitComplete event is received from the TRX Host Driver
In order to use Command_Trigger_IoEdge the following must occur:
Note that when chaining commands, the TRX_Request_CommandStore.chain_trigger and TRX_Request_CommandStore.chain_trig_param elements must be set for all commands in the chain except the first command.
The TRX Host Driver allows for commands to be chained together, meaning that multiple commands can be submitted at the same time with a branching mechanism determining if the next command in the chain will be run by the TRX or not. There are three branching options for chaining:
Each command can have a different definition of True and False as defined in the following table.
| Command | True Condition | False Condition |
|---|---|---|
| TX | All cases where the radio completed a transmission | All other cases |
| RX | All cases where the radio completed a reception | All other cases |
| CS | If the channel is busy | If the channel is idle |
| TX Test | All cases where the command ends after a packet transmission is completed | All other cases |
| RX Test | All cases where the radio completed a reception | All other cases |
Below is an example of chaining a Carrier Sense, Transmit, and Receive command together (CS->TX->RX). This is a common use case when performing CCA prior to transmission then issuing an RX command to receive an acknowledgment. For more details on Carrier Sense command is setup refer to the section on Carrier Sense Command (Carrier Sense Command).
The TRX handles commands and their respective payloads (streams) as separate entities and the TRX Host Driver exposes this concept as well. Similar to commands, the application can subscribe to events on streams and receive callbacks when the TRX Host Driver observes such events. Streams intended for transmission over-the-air can be stored to the TRX using the TRX_Host_storeStream() API and streams intended for reception of data can be registered using TRX_Host_registerRxStream().
Prior to submitting a TX command to the radio, a stream containing the data must be stored to the TRX with a user specified identifier (ID of the stream) using TRX_Host_storeStream(). Then, when the TX command is submitted, the ID of the stream needs to be referenced within the command structure.
Streams stored on the TRX have an associated retention policy that defines its lifespan.
| TRX_Stream_Retention | Lifespan | Description |
|---|---|---|
| Stream_Retention_Flush_Never | Indefinite or until a stream is stored with the same ID | The stream will not be flushed from the TRX after being transmitted. This will consume RAM indefinitely but can be useful for short packets that don't change and will be sent multiple times. |
| Stream_Retention_Flush_On_Success | Flushed when a TX command sending the stream succeeds | The stream is removed on success of a corresponding TX command. |
| Stream_Retention_Flush_Streaming | Flushed when a TX command sending the stream ends | The most recommended approach to TX streams. A small portion of the stream is loaded to the TRX, then when a TX command referencing the stream is submitted to the radio, the rest of the data is streamed and immediately sent over-the-air. |
The recommended retention policy in most use cases is Stream_Retention_Flush_Streaming, especially when sending large payloads. This approach provides several benefits including:
Below is an example showing how to store a stream on the TRX and send it using a TX command.
Prior to submitting an RX command to the radio, a stream to store the received data must be registered with the TRX Host Driver with a user specified identifier (ID) using TRX_Host_registerRxStream(). Then, when the RX command is submitted, the ID of the stream needs to be referenced within the command structure.
When an RX command is created the application can decide whether to stream the data from the TRX to the Host as it's received or buffer it on the TRX until reception has completed. It's recommended to stream the data as it's received by setting cmdRx.params.rx.stream_early = true for several reasons:
On reception and depending on events subscribed to when registering the RX stream, a callback is issued to the application where data can be parsed. Each received packet consists of the following structure:
Below is an example showing how to register an rx stream and parse the data once received.
A stored stream can be explicitly discarded from the TRX using TRX_Host_flushStream(). This sends a TRX_Request_StreamFlush to the TRX, removing all fragments of the stream identified by id. A success status returned from the function only indicates the request began sending; the provided callback is executed with one of the following events:
On TRX_EventStreamFlushComplete the local stream slot for id is released, so the same identifier can be reused in a subsequent TRX_Host_storeStream() call. This is useful for reclaiming a stream slot without transmitting its contents, or for abandoning a stream that is no longer needed.
The Carrier Sense (CS) command on the TRX can be used to determine if a frequency/channel is busy or idle with a high degree of flexibility using RSSI threshold, mode, exit condition, sample count, sample window, and timeout. The process of constructing a CS command is application specific and often dictated by a specification requiring a channel to be free for a certain duration. Below is an example of configuration of CS command for a Wi-SUN FSK #2b PHY. Details related to each parameter of the CS command are provided after the below example.
The exit condition, combined with a timeout, determines when the carrier sense operation should finish and report a result:
| TRX_CarrierSenseExitCondition | Description |
|---|---|
| TRX_CarrierSense_ExitCondition_WaitForIdle | Carrier sense is finished once idle channel is detected or timeout |
| TRX_CarrierSense_ExitCondition_WaitForBusy | Carrier sense is finished once busy channel is detected or timeout |
| TRX_CarrierSense_ExitCondition_Fast | Carrier sense is finished as soon as any result can be obtained (timeout is N/A) |
In the case of TRX_CarrierSense_ExitCondition_WaitForIdle or TRX_CarrierSense_ExitCondition_WaitForBusy, if timeout is non-zero, the CS command will finish and return the state of the channel once that timeout is reached.
For TRX_CarrierSense_ExitCondition_Fast, the CS command finishes immediately upon receiving first valid result and the timeout is not used.
This effectively results in 3 different cases:
Wait for idle/busy without timeout - carrier sense will only finish once specific state is reached
Wait for idle/busy with timeout - carrier sense will finish once specific state is reached. If it's not reached before the timeout occurs, the opposite of that state will be reported
Fast evaluation - carrier sense will finish as soon as all required (rssi/correlation) results can be obtained. This happens once rssi_window and/or correlation_window number of samples are gathered, depending on the mode.
The TRX_CarrierSenseMode determines what type of measurements should be performed to determine whether the channel is busy or idle:
| TRX_CarrierSenseMode | Description |
|---|---|
| TRX_CarrierSense_Mode_Energy | Channel busy if energy above threshold. RSSI based CS. |
| TRX_CarrierSense_Mode_Preamble 1 | Channel busy if preamble detected. Preamble based CS. |
| TRX_CarrierSense_Mode_And 1 | Channel busy if energy above threshold and preamble detected |
| TRX_CarrierSense_Mode_Or 1 | Channel busy if energy above threshold or preamble detected |
1Preamble based CS is not supported for OFDM PHYs
In case of TRX_CarrierSense_Mode_And or TRX_CarrierSense_Mode_Or, both sub-results have to be obtained for the carrier sense operation to finish, so timing of the command will be dependent on the longer of the two.
The behavior for TRX_CarrierSense_Mode_Energy based CS is described in the diagram below.
The behavior for TRX_CarrierSense_Mode_Preamble based CS is described in the diagram below.
The decision to report a channel busy or idle is dependent on the window and count:
This concept is illustrated in the diagram below along with the phy specific settling delay and default 6 samples discarded at the beginning of each CS operation.
The above example shows a CS command using the Wi-SUN FSK #2B PHY with the following settings:
As illustrated, the command senses the channel as idle for 10 sliding windows then detects 5 samples above the RSSI threshold within window #10 and reports the channel as busy.
The total duration of a window is dependent on the PHY specific sampling rate. This is the amount of time it takes for the TRX to receive one sample from the modem.
For all OFDM rates, the sample time is 6 us. For FSK PHYs, the modem sends 5 samples over every 8 symbols. Thus, in the above example, for Wi-SUN FSK #2B PHY, the sample rate is 62.5 KHz.
The minimum timeout value of the CS command is: MIN_CS_TIMEOUT = T_SETTLING_US + T_DISCARD + T_WINDOW_SETTLING
Where:
Depending on the PHY you are using, these values may vary. Defines are provided in the RCL settings alongside a PHY configuration for the:
With these values the minimum timeout can be calculated as: MIN_CS_TIMEOUT = T_SETTLING_US + (6 * T_SAMPLE_US) + (N * T_SAMPLE_US)
Where N is the user selected window value of the CS command.
Ongoing RF commands can either be explicitly stopped using TRX_Host_stopCmd() or interrupted with a new command using the TRX_ConflictPolicy in a command's TRX_Request_CommandStore.conflict_policy field. It's recommended to use the conflict policy instead of explicit stops as it will significantly reduce the delay from issuing a new command to submission to the radio.
If another command is running when the wanted command should start executing, the choice of TRX_ConflictPolicy in TRX_Request_CommandStore.conflict_policy field determines which of the following takes place:
| TRX_ConflictPolicy | Action |
|---|---|
| TRX_ConflictPolicy_AlwaysInterrupt | The newer command will always cause a HardStop to be invoked on the current running command, and execution is guaranteed |
| TRX_ConflictPolicy_Polite | The newer command causes GracefulStop to be issued. If the running command is in communication, either having received sync-word or is transmitting, then it will not terminate until complete. If allow_delay is not enabled, the newer command will be rejected and a command status will be issued with TRX_CommandStatus_RejectedStart |
| TRX_ConflictPolicy_NeverInterrupt | The newer command will only take precedence if the currently scheduled command has not yet been triggered; else, the newer command will be rejected and a command status will be issued with TRX_CommandStatus_RejectedStart |
A command may be stopped manually using TRX_Host_stopCmd() with a choice of TRX_Command_StopType that mirrors the conflict resolution options:
| TRX_Command_StopType | Action |
|---|---|
| TRX_Command_StopType_None | No stop requested |
| TRX_Command_StopType_DescheduleOnly | Stop the command if it has not started executing |
| TRX_Command_StopType_Graceful | Stop the command gracefully causing a GracefulStop, that is finish a packet or transaction in progress before ending |
| TRX_Command_StopType_Hard | Stop the command as soon as possible causing a HardStop |
If another command is currently active at the time the wanted command should start executing, the allow_delay parameter in TRX_Request_CommandStore determines whether the command will be rejected, or will pend completion of the ongoing command.
The TRX Host RF Driver provides a mechanism for synchronizing the timebase of the TRX with that of the Host via the TRX_Host_startTimeSync() API. The synchronization is driven by a common IO edge event on the SPI interface where both the TRX and the Host can capture a timestamp. These timestamps then correspond to the same event and can be used to establish a synchronized timebase between the two devices. When TRX_Host_startTimeSync() is executed, two events will be generated:
| Event | Description |
|---|---|
| TRX_EventCaptureHostTime | Signals that the common IO edge event between the TRX and Host just occurred and the host may take a timestamp |
| TRX_EventReceivedTrxTime | Signals the Host has received the timestamp from the TRX for the common IO edge event |
The TRX Host Driver can optionally be configured to assert an IO when a Sync Frame is Detected (SFD) using the TRX_Host_utilDioSetup() API. The application can then setup an interrupt on this IO to get notified when an SFD event occurs on the TRX. An example of this can be seen in the rfMdrRx example.
The TRX Host Driver provides APIs to manage the power state of the TRX.
TRX_Host_utilSetPowerMode() configures whether the TRX may automatically enter standby when idle, and the dwell time to wait after the SPI chip select is deasserted before doing so. The configuration is provided as a TRX_PowerMode structure:
powerPolicy - TRX_PowerPolicy_StandbyAllow to permit automatic standby, or TRX_PowerPolicy_StandbyDisallow to keep the TRX activedwellTimeUs - microseconds to remain awake after CS deassert before entering standbyThe provided callback is executed with the TRX_EventPowerModeComplete event.
When automatic standby is enabled, the TRX wakes on the next SPI chip select assertion. TRX_Host_utilWakeTrx() proactively wakes the TRX and blocks until it is ready. Unlike most APIs it is blocking and subscribes to no events.
TRX_Host_utilShutdown() transitions the TRX into shutdown via a TRX_Request_UtilShutdown request. After a successful shutdown the TRX automatically returns to the active state when the host next asserts the SPI chip select. The provided callback is executed with the TRX_EventShutdownComplete event.
The TRX Host Driver can be configured and used to send and receive Wi-SUN MDR packets on FSK and OFDM. For more information and examples of usage of these features, take a look at the TRX Host RF Driver Wi-SUN MDR documentation .
The TRX Host Driver can be closed using the TRX_Host_close(), This API is blocking, but there may be higher priority SPI events that trigger callbacks to the application while TRX_Host_close() is being executed. The application must be prepared to handle these events appropriately before issuing the close.