EEP fORK
Dependencies: BLE_API mbed nRF51822
Fork of MCS_LRF by
main.cpp
- Committer:
- Farshad
- Date:
- 2017-07-18
- Revision:
- 18:08184949ab30
- Parent:
- 17:229d78f063fb
- Child:
- 19:b576835175e2
File content as of revision 18:08184949ab30:
/* mbed Microcontroller Library * Copyright (c) 2006-2013 ARM Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mbed.h" #include "Serial.h" #include "BLE.h" #include "DeviceInformationService.h" #include "UARTService.h" #include "bleHelper.h" #include "laser.h" /* Set this if you need debug messages on the console; * it will have an impact on code-size and power consumption. */ #define NEED_CONSOLE_OUTPUT 0 // only used for parsing tag data- will not work if parse function is called from within serial interrupt #define NEED_PARSE_TRACE 0 Serial pc(USBTX, USBRX); #if NEED_CONSOLE_OUTPUT #define DEBUG(...) { pc.printf(__VA_ARGS__); } #else #define DEBUG(...) /* nothing */ #endif /* #if NEED_CONSOLE_OUTPUT */ #if NEED_PARSE_TRACE #define TRACE(...) { pc.printf(__VA_ARGS__); } #else #define TRACE(...) #endif /* #if NEED_TRACE */ #define SET_PARAM_CMD_MASK 0x8000 // commands with MSB set to 0 are to get the parameter and MSB of 1 to set the parameter #define READER_BAUD_RATE 115200 #define PB_DEBUNCE_TIME 100 #define PB_HOLD_TIME 1000 // ms- Holding the push button longer than this will turn the laser dot off if it is on #define BATT_VALUE_THRESHOLD 0.5360f // values by experiment 3.6V //#define BATT_VALUE_HYSTERYSIS 0.0200f // about 0.05 volt #define ACTIVITY_TIMEOUT_SEC 60 // default value- turn laser off if no measurement for more than this many seconds #undef NORDIC // is board nordic DK? #ifdef NORDIC DigitalOut connectionLed(p21); DigitalOut triggerLed(p22); Serial serial(p13, p17); // tx, rx === NOTE tx port pin needs to be wired and verified (for nordic DK) Laser laser(serial); InterruptIn triggerButton(p18); // Button 2 #else DigitalOut connectionLed(p23); //PwmOut connectionLed(p23); // good idea using PwmOut but it seems that period can't be set to longer than about 1s DigitalOut redLed(p24); InterruptIn triggerButton(p22); DigitalOut disableLRF(p28); DigitalOut enableBattVoltSense (p29); AnalogIn battVoltage (p1); DigitalOut nReset(p30); DigitalIn LRF_BOOT(p25, PullNone); DigitalIn LRF_CAL(p0, PullNone); #endif Serial* serialPtr; Laser* laserPtr; BLEDevice ble; UARTService *uartServicePtr; BLEHelper* bleHelper; static uint8_t isConnected = 0; Timer timer; Ticker batteryChecker; Ticker activityChecker; Ticker connectionLedBlinker; uint16_t activityTimeout = ACTIVITY_TIMEOUT_SEC; // settings for blinking the connection LED- Blink to save power uint16_t connectionLedOffCount = 0; #define CONNECTION_LED_OFF_TIME_MS 2000 #define CONNECTION_LED_ON_TIME_MS 20 #define CONNECTION_LED_OFF_COUNT (CONNECTION_LED_OFF_TIME_MS / CONNECTION_LED_ON_TIME_MS) const static char DEVICE_NAME[] = "MCS_LRF"; const static char MANUFACTURER[] = "MCS"; const static char MODEL[] = "Model 2"; const static char SERIAL_NO[] = "SN 1234"; const static char HARDWARE_REV[] = "hw-rev 1.1"; const static char FIRMWARE_REV[] = "fw-rev 1.5"; const static char SOFTWARE_REV[] = "soft-rev 1.5"; // these values must macth definitions in the XML file accompanying this device const static uint16_t distanceCmd = 0x0001; const static uint16_t triggerCmd = 0x0002; const static uint16_t redDotCmd = 0x0003; const static uint16_t resetCmd = 0x0004; const static uint16_t nSamplesCmd = 0x0005; const static uint16_t activityTimeoutCmd = 0x0006; void activityCheckerTask(); void resetActivityCheckerTask(); void turnLaserPowerOff(); void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) { DEBUG("Disconnected!\n\r"); DEBUG("Restarting the advertising process\n\r"); ble.startAdvertising(); isConnected = 0; // connectionLed = isConnected; // turn off blinking LED // connectionLed.pulsewidth_ms(0); } void connectionCallback(const Gap::ConnectionCallbackParams_t *params) { DEBUG("Connected!\n\r"); isConnected = 1; //connectionLed = isConnected; // connectionLed.pulsewidth_ms(25); } static void processData(const GattWriteCallbackParams *params) { if(params->len >= 2) { uint16_t command = params->data[0] + (params->data[1] << 8); bool isSetCmd = (command & SET_PARAM_CMD_MASK) == SET_PARAM_CMD_MASK; DEBUG("command: %d \r\n", command); switch(command & ~SET_PARAM_CMD_MASK) { case distanceCmd: if(!isSetCmd && params->len == 2) { // form the reply to send DEBUG("CMD is GET distance\n\r"); laserPtr->triggerDistanceMeasurement(); } break; // TODO not needed really- can just use the distance command case triggerCmd: if(isSetCmd && params->len == 3) { // form the reply to send DEBUG("CMD is SET trigger\n\r"); laserPtr->triggerDistanceMeasurement(); } break; case redDotCmd: if(isSetCmd && params->len == 3) { DEBUG("CMD is SET redDot\n\r"); laserPtr->setRedDot(params->data[2]); } break; case resetCmd: if(isSetCmd && params->len == 3) { DEBUG("CMD is reset\n\r"); nReset = 0; wait_ms(100); nReset = 1; wait_ms(1000); laserPtr->enableMeasurement(true); } break; case nSamplesCmd: if(isSetCmd && params->len == 4) { DEBUG("CMD is nSample\n\r"); int16_t nSamples = params->data[2] + (params->data[3] << 8); laserPtr->setNumberOfSamples(nSamples); } break; case activityTimeoutCmd: if(isSetCmd && params->len == 4) { DEBUG("CMD is nSample\n\r"); activityTimeout = params->data[2] + (params->data[3] << 8); } break; default: break; } } } // Serial driver seems to be buggy and allocate p8 and p10 for flow control // by default- Need to manually disable flow control since the function for // disabling Serail.set_flow_control(Serial::Disabled) is not recognised by // the compiler either! Could be something to do with the target processor?? static void disableFlowControl() { uint32_t base = 0x40002000; uint32_t ctsOffset = 0x510; uint32_t rtsOffset = 0x508; uint32_t cts = base + ctsOffset; uint32_t rts = base + rtsOffset; uint32_t* pcts = (uint32_t*)cts; uint32_t* prts = (uint32_t*)rts; // no pin allocated for CTS and RTS *pcts = 0xffffffff; *prts = 0xffffffff; } void resetActivityCheckerTask() { activityChecker.detach(); activityChecker.attach(activityCheckerTask, activityTimeout); } void onDataWritten(const GattWriteCallbackParams *params) { if ((uartServicePtr != NULL) && (params->handle == uartServicePtr->getTXCharacteristicHandle())) { uint16_t bytesRead = params->len; DEBUG("received %u bytes\n\r", bytesRead); for(int i = 0; i < bytesRead; i++) { DEBUG("0x%X ", params->data[i]); } DEBUG("\n\r", bytesRead); // echo? // ble.updateCharacteristicValue(uartServicePtr->getRXCharacteristicHandle(), params->data, bytesRead); // make sure the laser is not powered off due to inactivity resetActivityCheckerTask(); laserPtr->turnLaserPowerOn(); processData(params); } } // this is an ISR, so do not spend too much time here and be careful with printing debug info void readerCallback() { //if(serial.readable()) { // laserPtr->processRxData(serial.getc()); // } } /* This method is called when a distance measurement is ready to be sent to the client. send distance measurement to the connected BLE client */ void distanceCallcack(float distance, float elapsedTime) { uint8_t buf[10]; uint16_t arrayLen = 2; memcpy(&buf[0], &arrayLen, sizeof(uint16_t)); memcpy(&buf[2], &distance, sizeof(float)); memcpy(&buf[6], &elapsedTime, sizeof(float)); bleHelper->sendPacketOverBLE(distanceCmd, buf, sizeof(buf)); } void notifyActivityTimeout(){ uint8_t buf[1]; bleHelper->sendPacketOverBLE(activityTimeoutCmd, buf, 0); } void connectionLedBlinkerTask() { if(isConnected) { if(connectionLed) { connectionLed = 0; connectionLedOffCount = 0; } else if(++connectionLedOffCount > CONNECTION_LED_OFF_COUNT) { connectionLed = 1; } } else { connectionLed = 0; } } void batteryCheckerTask(void) { enableBattVoltSense = 1; wait_ms(20); // wait for the circuit to settle float batt = battVoltage.read(); enableBattVoltSense = 0; if(redLed == 0 && batt < BATT_VALUE_THRESHOLD) { redLed = 1; } } /* processor for the hardware trigger button */ void triggerFall() { resetActivityCheckerTask(); laserPtr->turnLaserPowerOn(); laserPtr->triggerDistanceMeasurement(); timer.reset(); timer.start(); } void turnLaserPowerOff() { laserPtr->turnLaserPowerOff(); notifyActivityTimeout(); } /* interrupt processor for when the button is released. If it has been pushed and held, turn the red dot off on release, otherwise debunce and make a measurement */ void triggerRise() { int elapsed = timer.read_ms(); timer.stop(); if(elapsed > PB_HOLD_TIME) { turnLaserPowerOff(); } //else if(elapsed > PB_DEBUNCE_TIME) { // laserPtr->triggerDistanceMeasurement(); // } } void activityCheckerTask() { // too long with no activity- turn pwer off from laser to preserve power turnLaserPowerOff(); } int main(void) { connectionLed = 0; // turn laser on and reset and wait for it to settle disableLRF = 0; nReset = 1; wait_ms(1000); DEBUG("Initialising the nRF51822\n\r"); ble.init(); ble.onDisconnection(disconnectionCallback); ble.onConnection(connectionCallback); ble.onDataWritten(onDataWritten); /* setup advertising */ ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME, (const uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME) - 1); ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,(const uint8_t *)UARTServiceUUID_reversed, sizeof(UARTServiceUUID_reversed)); ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)GattService::UUID_DEVICE_INFORMATION_SERVICE, sizeof(GattService::UUID_DEVICE_INFORMATION_SERVICE)); ble.setAdvertisingInterval(GapAdvertisingParams::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(1000)); ble.startAdvertising(); // check battery level now and every minute afterwards batteryCheckerTask(); batteryChecker.attach(batteryCheckerTask, 60); // check acticity once every 3 minutes activityChecker.attach(activityCheckerTask, activityTimeout); /* Setup uart service */ UARTService uartService(ble); uartServicePtr = &uartService; /* Setup auxiliary service. */ DeviceInformationService deviceInfo(ble, MANUFACTURER, MODEL, SERIAL_NO,HARDWARE_REV, FIRMWARE_REV, SOFTWARE_REV); /* Setup bleHelper */ BLEHelper helper(&ble, uartServicePtr); bleHelper = &helper; // setup serial port to LRF serialPtr = new Serial(p27, p26); disableFlowControl(); serialPtr->baud(READER_BAUD_RATE); // serial.attach(&readerCallback); // processors for the trigger button triggerButton.fall(&triggerFall); triggerButton.rise(&triggerRise); // setup laser laserPtr = new Laser(*serialPtr); laserPtr->enableMeasurement(true); laserPtr->setDistaceCallback(&distanceCallcack); laserPtr->turnLaserPowerOn(); // setup blinking connectionLed // connectionLed.period(2.0f); connectionLedBlinker.attach(connectionLedBlinkerTask, CONNECTION_LED_ON_TIME_MS / 1000.0f); while (true) { ble.waitForEvent(); } }