this is using the mbed os version 5-13-1

Dependencies:   mbed-http

Committer:
ocomeni
Date:
Thu Feb 28 18:13:48 2019 +0000
Revision:
73:6f5021cbe752
Parent:
44:df8adb3bc797
Child:
79:a2187bbfa407
commit current application code

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mbed_official 2:864ddfb70a9c 1 /* mbed Microcontroller Library
mbed_official 2:864ddfb70a9c 2 * Copyright (c) 2006-2013 ARM Limited
mbed_official 2:864ddfb70a9c 3 *
mbed_official 2:864ddfb70a9c 4 * Licensed under the Apache License, Version 2.0 (the "License");
mbed_official 2:864ddfb70a9c 5 * you may not use this file except in compliance with the License.
mbed_official 2:864ddfb70a9c 6 * You may obtain a copy of the License at
mbed_official 2:864ddfb70a9c 7 *
mbed_official 2:864ddfb70a9c 8 * http://www.apache.org/licenses/LICENSE-2.0
mbed_official 2:864ddfb70a9c 9 *
mbed_official 2:864ddfb70a9c 10 * Unless required by applicable law or agreed to in writing, software
mbed_official 2:864ddfb70a9c 11 * distributed under the License is distributed on an "AS IS" BASIS,
mbed_official 2:864ddfb70a9c 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
mbed_official 2:864ddfb70a9c 13 * See the License for the specific language governing permissions and
mbed_official 2:864ddfb70a9c 14 * limitations under the License.
mbed_official 2:864ddfb70a9c 15 */
ocomeni 73:6f5021cbe752 16 #ifdef false
mbed_official 11:7404978b24e7 17 #include <events/mbed_events.h>
mbed_official 2:864ddfb70a9c 18 #include <mbed.h>
mbed_official 2:864ddfb70a9c 19 #include "ble/BLE.h"
mbed_official 2:864ddfb70a9c 20 #include "LEDService.h"
ocomeni 73:6f5021cbe752 21 #include "ble/services/UARTService.h"
ocomeni 73:6f5021cbe752 22
ocomeni 73:6f5021cbe752 23 UARTService *uart;
mbed_official 2:864ddfb70a9c 24
mbed_official 2:864ddfb70a9c 25 DigitalOut alivenessLED(LED1, 0);
mbed_official 2:864ddfb70a9c 26 DigitalOut actuatedLED(LED2, 0);
ocomeni 73:6f5021cbe752 27 RawSerial pc(USBTX, USBRX); // tx, rx
ocomeni 73:6f5021cbe752 28 const static char DEVICE_NAME[] = "BLE-UART";
mbed_official 2:864ddfb70a9c 29 static const uint16_t uuid16_list[] = {LEDService::LED_SERVICE_UUID};
ocomeni 73:6f5021cbe752 30 #define BUFFER_LEN 256
ocomeni 73:6f5021cbe752 31 #define TX_BUFFER_LEN 4*256
ocomeni 73:6f5021cbe752 32 #define RX_BUFFER_LEN 4*256
ocomeni 73:6f5021cbe752 33 char buffer[BUFFER_LEN];
ocomeni 73:6f5021cbe752 34 uint8_t TxBuffer[TX_BUFFER_LEN];
ocomeni 73:6f5021cbe752 35 uint8_t RxBuffer[RX_BUFFER_LEN];
mbed_official 27:ff1fb7b5f9ee 36 static EventQueue eventQueue(/* event count */ 10 * EVENTS_EVENT_SIZE);
mbed_official 2:864ddfb70a9c 37
mbed_official 2:864ddfb70a9c 38 LEDService *ledServicePtr;
mbed_official 2:864ddfb70a9c 39
mbed_official 2:864ddfb70a9c 40 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
mbed_official 2:864ddfb70a9c 41 {
mbed_official 2:864ddfb70a9c 42 (void) params;
mbed_official 2:864ddfb70a9c 43 BLE::Instance().gap().startAdvertising();
mbed_official 2:864ddfb70a9c 44 }
mbed_official 2:864ddfb70a9c 45
mbed_official 2:864ddfb70a9c 46 void blinkCallback(void)
mbed_official 2:864ddfb70a9c 47 {
mbed_official 2:864ddfb70a9c 48 alivenessLED = !alivenessLED; /* Do blinky on LED1 to indicate system aliveness. */
mbed_official 2:864ddfb70a9c 49 }
mbed_official 2:864ddfb70a9c 50
ocomeni 73:6f5021cbe752 51 void EchoBleUartReceived()
ocomeni 73:6f5021cbe752 52 {
ocomeni 73:6f5021cbe752 53 uart->writeString(buffer);
ocomeni 73:6f5021cbe752 54 uart->writeString("\n"); //flushes uart output buffer and sends data
ocomeni 73:6f5021cbe752 55 }
ocomeni 73:6f5021cbe752 56
ocomeni 73:6f5021cbe752 57
mbed_official 2:864ddfb70a9c 58 /**
mbed_official 2:864ddfb70a9c 59 * This callback allows the LEDService to receive updates to the ledState Characteristic.
mbed_official 2:864ddfb70a9c 60 *
mbed_official 2:864ddfb70a9c 61 * @param[in] params
mbed_official 2:864ddfb70a9c 62 * Information about the characterisitc being updated.
mbed_official 2:864ddfb70a9c 63 */
mbed_official 2:864ddfb70a9c 64 void onDataWrittenCallback(const GattWriteCallbackParams *params) {
mbed_official 2:864ddfb70a9c 65 if ((params->handle == ledServicePtr->getValueHandle()) && (params->len == 1)) {
mbed_official 2:864ddfb70a9c 66 actuatedLED = *(params->data);
mbed_official 2:864ddfb70a9c 67 }
ocomeni 73:6f5021cbe752 68 else if ((uart != NULL) && (params->handle == uart->getTXCharacteristicHandle())) {
ocomeni 73:6f5021cbe752 69 uint16_t bytesRead = params->len;
ocomeni 73:6f5021cbe752 70
ocomeni 73:6f5021cbe752 71 pc.printf("received %u bytes\n\r ", bytesRead);
ocomeni 73:6f5021cbe752 72
ocomeni 73:6f5021cbe752 73 if(bytesRead >= 255){
ocomeni 73:6f5021cbe752 74 pc.printf("Overflow command %u n\r ", bytesRead);
ocomeni 73:6f5021cbe752 75 bytesRead = 255;
ocomeni 73:6f5021cbe752 76 }
ocomeni 73:6f5021cbe752 77
ocomeni 73:6f5021cbe752 78 unsigned index = 0;
ocomeni 73:6f5021cbe752 79 for (; index < bytesRead; index++) {
ocomeni 73:6f5021cbe752 80 buffer[index] = params->data[index];
ocomeni 73:6f5021cbe752 81 }
ocomeni 73:6f5021cbe752 82
ocomeni 73:6f5021cbe752 83 buffer[index++] = 0;
ocomeni 73:6f5021cbe752 84
ocomeni 73:6f5021cbe752 85 pc.printf("Data : %s ",buffer);
ocomeni 73:6f5021cbe752 86 pc.printf("\r\n");
ocomeni 73:6f5021cbe752 87 eventQueue.call(EchoBleUartReceived);
ocomeni 73:6f5021cbe752 88
ocomeni 73:6f5021cbe752 89 }
mbed_official 2:864ddfb70a9c 90 }
mbed_official 2:864ddfb70a9c 91
ocomeni 73:6f5021cbe752 92
mbed_official 2:864ddfb70a9c 93 /**
mbed_official 2:864ddfb70a9c 94 * This function is called when the ble initialization process has failled
mbed_official 2:864ddfb70a9c 95 */
mbed_official 2:864ddfb70a9c 96 void onBleInitError(BLE &ble, ble_error_t error)
mbed_official 2:864ddfb70a9c 97 {
mbed_official 2:864ddfb70a9c 98 /* Initialization error handling should go here */
mbed_official 2:864ddfb70a9c 99 }
mbed_official 2:864ddfb70a9c 100
mbed_official 44:df8adb3bc797 101 void printMacAddress()
mbed_official 44:df8adb3bc797 102 {
mbed_official 44:df8adb3bc797 103 /* Print out device MAC address to the console*/
mbed_official 44:df8adb3bc797 104 Gap::AddressType_t addr_type;
mbed_official 44:df8adb3bc797 105 Gap::Address_t address;
mbed_official 44:df8adb3bc797 106 BLE::Instance().gap().getAddress(&addr_type, address);
ocomeni 73:6f5021cbe752 107 pc.printf("DEVICE MAC ADDRESS: ");
mbed_official 44:df8adb3bc797 108 for (int i = 5; i >= 1; i--){
ocomeni 73:6f5021cbe752 109 pc.printf("%02x:", address[i]);
mbed_official 44:df8adb3bc797 110 }
ocomeni 73:6f5021cbe752 111 pc.printf("%02x\r\n", address[0]);
mbed_official 44:df8adb3bc797 112 }
mbed_official 44:df8adb3bc797 113
mbed_official 2:864ddfb70a9c 114 /**
mbed_official 2:864ddfb70a9c 115 * Callback triggered when the ble initialization process has finished
mbed_official 2:864ddfb70a9c 116 */
mbed_official 2:864ddfb70a9c 117 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
mbed_official 2:864ddfb70a9c 118 {
mbed_official 2:864ddfb70a9c 119 BLE& ble = params->ble;
mbed_official 2:864ddfb70a9c 120 ble_error_t error = params->error;
mbed_official 2:864ddfb70a9c 121 if (error != BLE_ERROR_NONE) {
mbed_official 2:864ddfb70a9c 122 /* In case of error, forward the error handling to onBleInitError */
mbed_official 2:864ddfb70a9c 123 onBleInitError(ble, error);
mbed_official 2:864ddfb70a9c 124 return;
mbed_official 2:864ddfb70a9c 125 }
mbed_official 2:864ddfb70a9c 126
mbed_official 2:864ddfb70a9c 127 /* Ensure that it is the default instance of BLE */
mbed_official 2:864ddfb70a9c 128 if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
mbed_official 2:864ddfb70a9c 129 return;
mbed_official 2:864ddfb70a9c 130 }
mbed_official 2:864ddfb70a9c 131
mbed_official 2:864ddfb70a9c 132 ble.gap().onDisconnection(disconnectionCallback);
mbed_official 2:864ddfb70a9c 133 ble.gattServer().onDataWritten(onDataWrittenCallback);
mbed_official 2:864ddfb70a9c 134
mbed_official 2:864ddfb70a9c 135 bool initialValueForLEDCharacteristic = false;
mbed_official 2:864ddfb70a9c 136 ledServicePtr = new LEDService(ble, initialValueForLEDCharacteristic);
ocomeni 73:6f5021cbe752 137 /* Setup primary service */
ocomeni 73:6f5021cbe752 138 uart = new UARTService(ble);
mbed_official 2:864ddfb70a9c 139
ocomeni 73:6f5021cbe752 140 /* setup security */
ocomeni 73:6f5021cbe752 141 error = ble.securityManager().init();
ocomeni 73:6f5021cbe752 142 if(error != BLE_ERROR_NONE)
ocomeni 73:6f5021cbe752 143 {
ocomeni 73:6f5021cbe752 144 pc.printf("\nBLE Security manager initialization failed!!\n");
ocomeni 73:6f5021cbe752 145 }
mbed_official 2:864ddfb70a9c 146 /* setup advertising */
mbed_official 2:864ddfb70a9c 147 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
ocomeni 73:6f5021cbe752 148 //ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
mbed_official 2:864ddfb70a9c 149 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
ocomeni 73:6f5021cbe752 150 /* set up the services that can be discovered */
ocomeni 73:6f5021cbe752 151 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,(const uint8_t *)UARTServiceUUID_reversed, sizeof(UARTServiceUUID_reversed));
mbed_official 2:864ddfb70a9c 152 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
mbed_official 2:864ddfb70a9c 153 ble.gap().setAdvertisingInterval(1000); /* 1000ms. */
mbed_official 2:864ddfb70a9c 154 ble.gap().startAdvertising();
mbed_official 44:df8adb3bc797 155
mbed_official 44:df8adb3bc797 156 printMacAddress();
mbed_official 2:864ddfb70a9c 157 }
mbed_official 2:864ddfb70a9c 158
mbed_official 2:864ddfb70a9c 159 void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) {
mbed_official 2:864ddfb70a9c 160 BLE &ble = BLE::Instance();
mbed_official 11:7404978b24e7 161 eventQueue.call(Callback<void()>(&ble, &BLE::processEvents));
mbed_official 2:864ddfb70a9c 162 }
mbed_official 2:864ddfb70a9c 163
ocomeni 73:6f5021cbe752 164 static int uartExpectedRcvCount = 0;
ocomeni 73:6f5021cbe752 165 static int uartCharRcvCount = 0;
ocomeni 73:6f5021cbe752 166 static bool UartBusy = false;
ocomeni 73:6f5021cbe752 167 int WriteUartBytes(const uint8_t * txBuffer, size_t bufSize, int txLen)
ocomeni 73:6f5021cbe752 168 {
ocomeni 73:6f5021cbe752 169 if(txLen > bufSize)
ocomeni 73:6f5021cbe752 170 {
ocomeni 73:6f5021cbe752 171 txLen = bufSize;
ocomeni 73:6f5021cbe752 172 }
ocomeni 73:6f5021cbe752 173 for(int i=0;i<txLen;i++)
ocomeni 73:6f5021cbe752 174 {
ocomeni 73:6f5021cbe752 175 pc.putc(txBuffer[i]);
ocomeni 73:6f5021cbe752 176 }
ocomeni 73:6f5021cbe752 177 // return number of bytes written to UART
ocomeni 73:6f5021cbe752 178 return txLen;
ocomeni 73:6f5021cbe752 179 }
ocomeni 73:6f5021cbe752 180
ocomeni 73:6f5021cbe752 181 void UartRxcallback_ex() {
ocomeni 73:6f5021cbe752 182 if(uartCharRcvCount >= uartExpectedRcvCount)
ocomeni 73:6f5021cbe752 183 {
ocomeni 73:6f5021cbe752 184 int x = pc.getc();
ocomeni 73:6f5021cbe752 185 return;
ocomeni 73:6f5021cbe752 186 }
ocomeni 73:6f5021cbe752 187 if(uartCharRcvCount == 0)
ocomeni 73:6f5021cbe752 188 {
ocomeni 73:6f5021cbe752 189 pc.printf("\nFirst Call to UART attach callback!!\n");
ocomeni 73:6f5021cbe752 190 }
ocomeni 73:6f5021cbe752 191 // Note: you need to actually read from the serial to clear the RX interrupt
ocomeni 73:6f5021cbe752 192 RxBuffer[uartCharRcvCount] = (uint8_t) pc.getc();
ocomeni 73:6f5021cbe752 193 uartCharRcvCount++;
ocomeni 73:6f5021cbe752 194 if(uartCharRcvCount >= uartExpectedRcvCount)
ocomeni 73:6f5021cbe752 195 {
ocomeni 73:6f5021cbe752 196 alivenessLED = !alivenessLED; /* Do blinky on LED1 to indicate system aliveness. */
ocomeni 73:6f5021cbe752 197 pc.printf("\nNumber of Received Bytes = %d\n\n", uartCharRcvCount);
ocomeni 73:6f5021cbe752 198 pc.printf("--- Writing back received bytes --- \n");
ocomeni 73:6f5021cbe752 199 int n;
ocomeni 73:6f5021cbe752 200 n = WriteUartBytes(RxBuffer, TX_BUFFER_LEN, uartCharRcvCount);
ocomeni 73:6f5021cbe752 201 UartBusy = false;
ocomeni 73:6f5021cbe752 202 }
ocomeni 73:6f5021cbe752 203 }
ocomeni 73:6f5021cbe752 204
ocomeni 73:6f5021cbe752 205 void BackGndUartRead(uint8_t * rxBuffer, size_t bufSize, int rxLen)
ocomeni 73:6f5021cbe752 206 {
ocomeni 73:6f5021cbe752 207 UartBusy = true;
ocomeni 73:6f5021cbe752 208 pc.printf("Setting up background UART read - rxLen = %d\n", rxLen);
ocomeni 73:6f5021cbe752 209 uartCharRcvCount = 0;
ocomeni 73:6f5021cbe752 210 if(rxLen > bufSize)
ocomeni 73:6f5021cbe752 211 {
ocomeni 73:6f5021cbe752 212 rxLen = bufSize;
ocomeni 73:6f5021cbe752 213 }
ocomeni 73:6f5021cbe752 214 uartExpectedRcvCount = rxLen;
ocomeni 73:6f5021cbe752 215 pc.attach(&UartRxcallback_ex);
ocomeni 73:6f5021cbe752 216 pc.printf("\nBackground UART read setup completed\n\n");
ocomeni 73:6f5021cbe752 217 //for(int i=0;i<rxLen;i++)
ocomeni 73:6f5021cbe752 218 //{
ocomeni 73:6f5021cbe752 219 // rxBuffer[i] = (uint8_t) pc.getc();
ocomeni 73:6f5021cbe752 220 //}
ocomeni 73:6f5021cbe752 221 // return number of bytes written to UART
ocomeni 73:6f5021cbe752 222 //return rxLen;
ocomeni 73:6f5021cbe752 223 }
ocomeni 73:6f5021cbe752 224
ocomeni 73:6f5021cbe752 225 int ReadUartBytes(uint8_t * rxBuffer, size_t bufSize, int rxLen, bool echo)
ocomeni 73:6f5021cbe752 226 {
ocomeni 73:6f5021cbe752 227 UartBusy = true;
ocomeni 73:6f5021cbe752 228 if(rxLen > bufSize)
ocomeni 73:6f5021cbe752 229 {
ocomeni 73:6f5021cbe752 230 rxLen = bufSize;
ocomeni 73:6f5021cbe752 231 }
ocomeni 73:6f5021cbe752 232 for(int i=0;i<rxLen;i++)
ocomeni 73:6f5021cbe752 233 {
ocomeni 73:6f5021cbe752 234 rxBuffer[i] = (uint8_t) pc.getc();
ocomeni 73:6f5021cbe752 235 if(echo)pc.putc(rxBuffer[i]);
ocomeni 73:6f5021cbe752 236 }
ocomeni 73:6f5021cbe752 237 UartBusy = false;
ocomeni 73:6f5021cbe752 238 //return number of bytes written to UART
ocomeni 73:6f5021cbe752 239 return rxLen;
ocomeni 73:6f5021cbe752 240 }
ocomeni 73:6f5021cbe752 241
ocomeni 73:6f5021cbe752 242
ocomeni 73:6f5021cbe752 243 void checkUartReceive()
ocomeni 73:6f5021cbe752 244 {
ocomeni 73:6f5021cbe752 245 //pc.printf("Hello World!\n\r");
ocomeni 73:6f5021cbe752 246 char cbuf[100];
ocomeni 73:6f5021cbe752 247 int rxCnt=0;
ocomeni 73:6f5021cbe752 248 while(pc.readable()) {
ocomeni 73:6f5021cbe752 249 //pc.printf("uartCharRcvCount = %d\n\r", uartCharRcvCount++);
ocomeni 73:6f5021cbe752 250 cbuf[rxCnt++] = pc.getc();
ocomeni 73:6f5021cbe752 251 //pc.putc(pc.getc() + 1); // echo input back to terminal
ocomeni 73:6f5021cbe752 252 }
ocomeni 73:6f5021cbe752 253 cbuf[rxCnt] = NULL;
ocomeni 73:6f5021cbe752 254 if(rxCnt > 0)
ocomeni 73:6f5021cbe752 255 {
ocomeni 73:6f5021cbe752 256 pc.printf("received %d chars\n", rxCnt);
ocomeni 73:6f5021cbe752 257 pc.printf("%s\n", cbuf);
ocomeni 73:6f5021cbe752 258 }
ocomeni 73:6f5021cbe752 259
ocomeni 73:6f5021cbe752 260 }
ocomeni 73:6f5021cbe752 261 uint64_t lastTime = 0;
ocomeni 73:6f5021cbe752 262 uint64_t now = 0;
ocomeni 73:6f5021cbe752 263 uint32_t callCount = 0;
ocomeni 73:6f5021cbe752 264 void HelloUart()
ocomeni 73:6f5021cbe752 265 {
ocomeni 73:6f5021cbe752 266 //if(UartBusy)return;
ocomeni 73:6f5021cbe752 267 // 64-bit time doesn't wrap for half a billion years, at least
ocomeni 73:6f5021cbe752 268 lastTime = now;
ocomeni 73:6f5021cbe752 269 now = Kernel::get_ms_count();
ocomeni 73:6f5021cbe752 270 callCount++;
ocomeni 73:6f5021cbe752 271 pc.printf("\nHello : %d secs elapsed : CallCount = %d \n", uint32_t(now - lastTime), callCount);
ocomeni 73:6f5021cbe752 272 }
ocomeni 73:6f5021cbe752 273
ocomeni 73:6f5021cbe752 274 Thread t;
mbed_official 2:864ddfb70a9c 275 int main()
mbed_official 2:864ddfb70a9c 276 {
ocomeni 73:6f5021cbe752 277 pc.baud(115200);
mbed_official 11:7404978b24e7 278 eventQueue.call_every(500, blinkCallback);
ocomeni 73:6f5021cbe752 279 eventQueue.call_every(60000, HelloUart);
ocomeni 73:6f5021cbe752 280 //eventQueue.call_every(1000, checkUartReceive);
mbed_official 2:864ddfb70a9c 281
mbed_official 2:864ddfb70a9c 282 BLE &ble = BLE::Instance();
mbed_official 2:864ddfb70a9c 283 ble.onEventsToProcess(scheduleBleEventsProcessing);
mbed_official 2:864ddfb70a9c 284 ble.init(bleInitComplete);
ocomeni 73:6f5021cbe752 285 for(int i=0;i<255;i++)
ocomeni 73:6f5021cbe752 286 {
ocomeni 73:6f5021cbe752 287 pc.putc(i);
ocomeni 73:6f5021cbe752 288 }
ocomeni 73:6f5021cbe752 289 int n;
ocomeni 73:6f5021cbe752 290 //ReadUartBytes(RxBuffer, RX_BUFFER_LEN, 4);
ocomeni 73:6f5021cbe752 291 pc.printf("\n\n\nEnter # of expected bytes: ");
ocomeni 73:6f5021cbe752 292 n = ReadUartBytes(RxBuffer, RX_BUFFER_LEN, 4, true);
ocomeni 73:6f5021cbe752 293 int rxLen = (int) 100*(RxBuffer[0]-'0') + 10*(RxBuffer[1]-'0') + (RxBuffer[0]-'0');
ocomeni 73:6f5021cbe752 294 pc.printf("\n\nExpected # of Received Bytes = %d\n", rxLen);
ocomeni 73:6f5021cbe752 295 BackGndUartRead(RxBuffer, RX_BUFFER_LEN, rxLen);
ocomeni 73:6f5021cbe752 296 //pc.printf("--- Writing back received data --- \n\n");
ocomeni 73:6f5021cbe752 297 //n = WriteUartBytes(RxBuffer, TX_BUFFER_LEN, rxLen);
ocomeni 73:6f5021cbe752 298 //pc.write("\n\ntesting Serial Write\n", 40); //, checkUartReceive, SERIAL_EVENT_TX_COMPLETE);
ocomeni 73:6f5021cbe752 299 //eventQueue.dispatch_forever();
ocomeni 73:6f5021cbe752 300 t.start(callback(&eventQueue, &EventQueue::dispatch_forever));
mbed_official 2:864ddfb70a9c 301 return 0;
mbed_official 2:864ddfb70a9c 302 }
ocomeni 73:6f5021cbe752 303 #endif