1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016-2017 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 /*! \file control.c
10 \brief Defines control sub-system
11
12 This file contains a UART implementation of the control subsystem. The
13 command interpreter and streaming functions are contained in two separate
14 files. So you can easily swap those out with only minor changes here.
15 */
16 #include "fsl_debug_console.h"
17 #include "board.h"
18 #include "pin_mux.h"
19 #include "fsl_uart.h"
20 #include "fsl_port.h"
21 #include "sensor_fusion.h"
22 #include "control.h"
23
24 #ifndef F_USE_WIRELESS_UART
25 #define F_USE_WIRELESS_UART 0x0001 ///< 0x0001 to include, 0x0000 otherwise
26 #endif
27 #ifndef F_USE_WIRED_UART
28 #define F_USE_WIRED_UART 0x0002 ///< 0x0002 to include, 0x0000 otherwise
29 #endif
30
31 #define CONTROL_BAUDRATE 115200 ///< Baudrate to be used for serial communications
32
33 uart_handle_t wired_uartHandle;
34 uart_handle_t wireless_uartHandle;
35
36 // global structures
37 uint8_t sUARTOutputBuffer[256]; // larger than the nominal 124 byte size for outgoing packets
38
39 // direct access to sfg here is the only place in the entire library where we cannot simply
40 // pass a pointer. This is because it is needed by the UART interrupt handlers. Since this
41 // only occurs here, in a subsystem which is defined to be application dependent, that is
42 // considered acceptable.
43 extern SensorFusionGlobals sfg;
44
45 // Blocking function to write a single byte to a specified UART
myUART_WriteByte(UART_Type * base,uint8_t data)46 void myUART_WriteByte(UART_Type *base, uint8_t data)
47 {
48 uint8_t flag = 0;
49 while (!flag)
50 {
51 flag = base->S1 & 0x80;
52 }
53 UART_WriteByte(base, data);
54 }
55
56 // Blocking function pipes specified buffer to both output UARTS
writeControlPort(ControlSubsystem * pComm,uint8_t buffer[],uint16_t nbytes)57 int8_t writeControlPort(ControlSubsystem *pComm, uint8_t buffer[], uint16_t nbytes)
58 {
59 uint16_t i;
60 for (i = 0; i < nbytes; i++)
61 {
62 #if F_USE_WIRED_UART
63 myUART_WriteByte(WIRED_UART, buffer[i]);
64 #endif
65 #if F_USE_WIRELESS_UART
66 myUART_WriteByte(WIRELESS_UART, buffer[i]);
67 #endif
68 }
69
70 return (0);
71 }
72
73 #if F_USE_WIRELESS_UART
74 // writeWirelessPort() is called from BlueRadios_Init(), which is used to
75 // initialize the Bluetooth module on NXP sensor shields. That function will
76 // obviously need to be replaced for alternate hardware.
writeWirelessPort(uint8_t buffer[],uint16_t nbytes)77 int8_t writeWirelessPort(uint8_t buffer[], uint16_t nbytes)
78 {
79 uint16_t i;
80 for (i = 0; i < nbytes; i++)
81 {
82 myUART_WriteByte(WIRELESS_UART, buffer[i]);
83 }
84
85 return (0);
86 }
87 // Wired and Wireless UART interrupt handlers are essentially identical.
WIRELESS_UART_IRQHandler(void)88 void WIRELESS_UART_IRQHandler(void)
89 {
90 uint8_t data;
91 status_t sts;
92 uint32_t nbytes; // number of bytes received
93 uint32_t flags;
94 static char iCommandBuffer_B[5] = "~~~~"; // 5 bytes long to include the unused terminating \0
95 sfg.setStatus(&sfg, RECEIVING_WIRELESS);
96 flags = UART_GetStatusFlags(WIRELESS_UART);
97 /* If new data arrived. */
98 if ((kUART_RxDataRegFullFlag | kUART_RxOverrunFlag) & flags)
99 {
100 sts = UART_TransferGetReceiveCount(WIRELESS_UART, &wireless_uartHandle, &nbytes);
101 if (sts == kStatus_Success)
102 {
103 data = UART_ReadByte(WIRELESS_UART);
104 DecodeCommandBytes(&sfg, iCommandBuffer_B, &data, 1);
105 }
106 }
107 }
108 // initialize BlueRadios BR-LE4.0-D2A Bluetooth module
109 // This is required for NXP FRDM-FXS-MULT2-B boards.
BlueRadios_Init(void)110 void BlueRadios_Init(void)
111 {
112 uint16_t ilen; // command string length
113
114 // transmit "ATSRM,2,0\r" to minimize traffic from the module
115 // command "ATSRM": sets the module response mode which configures how verbose the module will be
116 // 2: response mode at to minimal
117 // 0: disconnected mode is command mode
118 // \r: carriage return escape sequence
119 strcpy((char *)sUARTOutputBuffer, "ATSRM,2,0\r");
120 ilen = strlen((char *)sUARTOutputBuffer);
121 writeWirelessPort(sUARTOutputBuffer, ilen);
122 return;
123 }
124 #endif
125
126 #if F_USE_WIRED_UART
echo(uint8_t data)127 void echo(uint8_t data) // only used for comms debug
128 {
129 /* Send data only when UART TX register is empty and ring buffer has data to send out. */
130 if (kUART_TxDataRegEmptyFlag & UART_GetStatusFlags(WIRED_UART))
131 {
132 UART_WriteByte(WIRED_UART, data);
133 }
134 }
135 // Wired and Wireless UART interrupt handlers are essentially identical.
WIRED_UART_IRQHandler(void)136 void WIRED_UART_IRQHandler(void)
137 {
138 uint8_t data;
139 status_t sts;
140 uint32_t nbytes; // number of bytes received
141 uint32_t flags;
142 static char iCommandBuffer_A[5] = "~~~~"; // 5 bytes long to include the unused terminating \0
143
144 sfg.setStatus(&sfg, RECEIVING_WIRED);
145 flags = UART_GetStatusFlags(WIRED_UART);
146 /* If new data arrived. */
147 if ((kUART_RxDataRegFullFlag | kUART_RxOverrunFlag) & flags)
148 {
149 sts = UART_TransferGetReceiveCount(WIRED_UART, &wired_uartHandle, &nbytes);
150 if (sts == kStatus_Success)
151 {
152 data = UART_ReadByte(WIRED_UART);
153 DecodeCommandBytes(&sfg, iCommandBuffer_A, &data, 1);
154 }
155 }
156 }
157 #endif
158
159 /// Initialize the control subsystem and all related hardware
initializeControlPort(ControlSubsystem * pComm)160 int8_t initializeControlPort(
161 ControlSubsystem *pComm ///< pointer to the control subystem structure
162 )
163 {
164 uart_config_t config;
165 if (pComm)
166 {
167 pComm->DefaultQuaternionPacketType = Q3; // default to simplest algorithm
168 pComm->QuaternionPacketType = Q3; // default to simplest algorithm
169 pComm->AngularVelocityPacketOn = true; // transmit angular velocity packet
170 pComm->DebugPacketOn = true; // transmit debug packet
171 pComm->RPCPacketOn = true; // transmit roll, pitch, compass packet
172 pComm->AltPacketOn = true; // Altitude packet
173 pComm->AccelCalPacketOn = 0;
174 pComm->write = writeControlPort;
175 pComm->stream = CreateAndSendPackets;
176
177 #if F_USE_WIRED_UART
178 /* Initialize WIRED UART pins below - currently duplicates code in pin_mux.c */
179 CLOCK_EnableClock(WIRED_UART_PORT_CLKEN);
180 PORT_SetPinMux(WIRED_UART_PORT, WIRED_UART_RX_PIN, WIRED_UART_MUX);
181 PORT_SetPinMux(WIRED_UART_PORT, WIRED_UART_TX_PIN, WIRED_UART_MUX);
182 UART_GetDefaultConfig(&config);
183
184 config.baudRate_Bps = CONTROL_BAUDRATE;
185 config.enableTx = true;
186 config.enableRx = true;
187 config.rxFifoWatermark = 1;
188 UART_Init(WIRED_UART, &config, CLOCK_GetFreq(WIRED_UART_CLKSRC));
189
190 /* Enable RX interrupt. */
191 UART_EnableInterrupts(WIRED_UART, kUART_RxDataRegFullInterruptEnable |
192 kUART_RxOverrunInterruptEnable);
193 EnableIRQ(WIRED_UART_IRQn);
194 #endif
195 #if F_USE_WIRELESS_UART
196 /* Initialize WIRELESS UART pins below */
197 CLOCK_EnableClock(WIRELESS_UART_PORT_CLKEN);
198 PORT_SetPinMux(WIRELESS_UART_PORT, WIRELESS_UART_RX_PIN,
199 WIRELESS_UART_MUX);
200 PORT_SetPinMux(WIRELESS_UART_PORT, WIRELESS_UART_TX_PIN,
201 WIRELESS_UART_MUX);
202
203 UART_Init(WIRELESS_UART, &config, CLOCK_GetFreq(WIRELESS_UART_CLKSRC));
204 BlueRadios_Init();
205
206 /* Enable RX interrupt. */
207 UART_EnableInterrupts(WIRELESS_UART, kUART_RxDataRegFullInterruptEnable |
208 kUART_RxOverrunInterruptEnable);
209 EnableIRQ(WIRELESS_UART_IRQn);
210 #endif
211
212 return (0);
213 }
214 else
215 {
216 return (1);
217 }
218 }
219