1 /***************************************************************************//**
2  * @file
3  * @brief The MFM specific header file for the RAIL library.
4  *******************************************************************************
5  * # License
6  * <b>Copyright 2020 Silicon Laboratories Inc. www.silabs.com</b>
7  *******************************************************************************
8  *
9  * SPDX-License-Identifier: Zlib
10  *
11  * The licensor of this software is Silicon Laboratories Inc.
12  *
13  * This software is provided 'as-is', without any express or implied
14  * warranty. In no event will the authors be held liable for any damages
15  * arising from the use of this software.
16  *
17  * Permission is granted to anyone to use this software for any purpose,
18  * including commercial applications, and to alter it and redistribute it
19  * freely, subject to the following restrictions:
20  *
21  * 1. The origin of this software must not be misrepresented; you must not
22  *    claim that you wrote the original software. If you use this software
23  *    in a product, an acknowledgment in the product documentation would be
24  *    appreciated but is not required.
25  * 2. Altered source versions must be plainly marked as such, and must not be
26  *    misrepresented as being the original software.
27  * 3. This notice may not be removed or altered from any source distribution.
28  *
29  ******************************************************************************/
30 
31 #ifndef __RAIL_MFM_H__
32 #define __RAIL_MFM_H__
33 
34 #include "rail_types.h"
35 
36 #ifdef __cplusplus
37 extern "C" {
38 #endif
39 
40 /// @addtogroup MFM Multi-Level Frequency Modulation
41 /// @ingroup Protocol_Specific
42 /// @brief MFM configuration routines
43 /// Note that this feature is only supported on EFR32xG23 devices.
44 ///
45 /// This feature can be used to directly control the TX interpolation filter
46 /// input to allow for a more flexible frequency modulation scheme than the
47 /// standard MODEM. When doing this, the MFM buffer is treated as an array
48 /// of 8-bit signed data used as normalized frequency deviation to the SYNTH
49 /// frequency to directly control the interpolation filter input.
50 /// No support for frame handling, coding, nor shaping is supported.
51 /// Only compatible with FSK modulations.
52 ///
53 /// The functions in this group configure RAIL Multi-Level Frequency Modulation (MFM)
54 /// hardware acceleration features.
55 ///
56 /// To configure MFM functionality, the application must first set up
57 /// a RAIL instance with \ref RAIL_Init() and other setup functions.
58 /// Before enabling MFM, a ping-pong buffer (called buffer0 and buffer1
59 /// below) must be configured via \ref RAIL_SetMfmPingPongFifo() and
60 /// populated with the initial buffer content.
61 /// MFM is enabled by setting \ref RAIL_TxDataSource_t::TX_MFM_DATA using
62 /// \ref RAIL_ConfigData() and is activated when transmit is started by
63 /// \ref RAIL_StartTx(). Once transmitting the data in the ping-pong buffers,
64 /// RAIL will manage them so it looks like a continuous transmission to the
65 /// receiver. Every time one of the ping-ping buffers has been transmitted,
66 /// \ref RAIL_EVENT_MFM_TX_BUFFER_DONE is triggered so the application can
67 /// update the data in that buffer without the need to start/stop the
68 /// transmission. \ref RAIL_EVENT_MFM_TX_BUFFER_DONE can be enable with \ref
69 /// RAIL_ConfigEvents().
70 /// Use \ref RAIL_StopTx() to finish transmitting.
71 ///
72 /// @code{.c}
73 ///
74 /// uint8_t txCount = 0;
75 ///
76 /// typedef struct RAIL_MFM_Config_App {
77 ///   RAIL_MFM_PingPongBufferConfig_t buffer;
78 ///   RAIL_StateTiming_t timings;
79 /// } RAIL_MFM_Config_App_t;
80 ///
81 /// // Main RAIL_EVENT callback
82 /// static void RAILCb_Event(RAIL_Handle_t railHandle, RAIL_Events_t events)
83 /// {
84 ///   // Increment TX counter
85 ///   if (events & RAIL_EVENT_MFM_BUF_DONE) {
86 ///       txCount++;
87 ///       return;
88 ///     }
89 ///   }
90 /// }
91 ///
92 /// static const RAIL_MFM_Config_App_t mfmConfig = {
93 ///   .buffer = {
94 ///     .pBuffer0 = (&channelHoppingBufferSpace[0]),
95 ///     .pBuffer1 = (&channelHoppingBufferSpace[MFM_RAW_BUF_SZ_BYTES / 4]),
96 ///     .bufferSizeWords = (MFM_RAW_BUF_SZ_BYTES / 4)
97 ///   },
98 ///   .timings = {
99 ///     .idleToTx = 100,
100 ///     .idleToRx = 0,
101 ///     .rxToTx = 0,
102 ///     .txToRx = 0,
103 ///     .rxSearchTimeout = 0,
104 ///     .txToRxSearchTimeout = 0
105 /// };
106 ///
107 /// RAIL_Status_t mfmInit(void)
108 /// {
109 ///   // initialize MFM
110 ///   uint32_t idx;
111 ///   uint32_t *pDst0 = mfmConfig.pBuffer0;
112 ///   uint32_t *pDst1 = mfmConfig.pBuffer1;
113 ///   RAIL_Status_t status;
114 ///   for (idx = 0; idx < (MFM_RAW_BUF_SZ_BYTES / 16); idx++) {
115 ///     pDst0[4 * idx + 0] = 0x755A3100;
116 ///     pDst1[4 * idx + 0] = 0x755A3100;
117 ///     pDst0[4 * idx + 1] = 0x315A757F;
118 ///     pDst1[4 * idx + 1] = 0x315A757F;
119 ///     pDst0[4 * idx + 2] = 0x8BA6CF00;
120 ///     pDst1[4 * idx + 2] = 0x8BA6CF00;
121 ///     pDst0[4 * idx + 3] = 0xCFA68B81;
122 ///     pDst1[4 * idx + 3] = 0xCFA68B81;
123 ///   }
124 ///
125 ///   RAIL_Status_t status;
126 ///   railDataConfig.txSource = TX_MFM_DATA;
127 ///   status = RAIL_SetMfmPingPongFifo(railHandle,
128 ///                                    &(config->buffer));
129 ///   if (status != RAIL_STATUS_NO_ERROR) {
130 ///     return (status);
131 ///   }
132 ///
133 ///
134 ///   status = RAIL_ConfigData(railHandle, &railDataConfig);
135 ///   if (status != RAIL_STATUS_NO_ERROR) {
136 ///     return (status);
137 ///   }
138 ///
139 ///   status = RAIL_SetStateTiming(railHandle, &(config->timings));
140 ///   if (status != RAIL_STATUS_NO_ERROR) {
141 ///     return (status);
142 ///   }
143 ///
144 ///   // start transmitting
145 ///   return (RAIL_StartTx(railHandle, 0, 0, &schedulerInfo));
146 /// }
147 ///
148 /// RAIL_Status_t mfmDeInit(void)
149 /// {
150 ///   RAIL_Status_t status;
151 ///   status = RAIL_StopTx(railHandle, RAIL_STOP_MODES_ALL);
152 ///   if (status != RAIL_STATUS_NO_ERROR) {
153 ///     return (status);
154 ///   }
155 ///
156 ///   railDataConfig.txSource = TX_PACKET_DATA;
157 ///   return (RAIL_ConfigData(railHandle, &railDataConfig));
158 /// }
159 /// @endcode
160 ///
161 /// @{
162 
163 /**
164  * @struct RAIL_MFM_PingPongBufferConfig_t
165  * @brief A configuration structure for MFM Ping-pong buffer in RAIL.
166  */
167 typedef struct RAIL_MFM_PingPongBufferConfig {
168   /** pointer to buffer0. Must be 32-bit aligned. */
169   uint32_t *pBuffer0;
170   /** pointer to buffer1. Must be 32-bit aligned. */
171   uint32_t *pBuffer1;
172   /** size of each buffer A and B in 32-bit words. */
173   uint32_t bufferSizeWords;
174 } RAIL_MFM_PingPongBufferConfig_t;
175 
176 /**
177  * Set MFM ping-pong buffer.
178  *
179  * @param[in] railHandle A handle of RAIL instance.
180  * @param[in] config A MFM ping-pong buffer configuration structure.
181  * @return A status code indicating success of the function call.
182  *
183  */
184 RAIL_Status_t RAIL_SetMfmPingPongFifo(RAIL_Handle_t railHandle,
185                                       const RAIL_MFM_PingPongBufferConfig_t *config);
186 
187 /** @} */ // end of MFM
188 
189 #ifdef __cplusplus
190 }
191 #endif
192 
193 #endif // __RAIL_MFM_H__
194