EEP fORK
Dependencies: BLE_API mbed nRF51822
Fork of MCS_LRF by
main.cpp
- Committer:
- Farshad
- Date:
- 2016-10-17
- Revision:
- 12:cf8af0b4e0d2
- Parent:
- 10:d37cd13dd529
- Child:
- 13:a051da83a849
File content as of revision 12:cf8af0b4e0d2:
/* 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 #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); DigitalOut redLed(p24); //Serial serial(p27, p26); // tx, rx === for adafruit BLE UART board (small blue board with red BLE module) //Laser laser(serial); 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; bool powerOffState = true; 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.1"; const static char SOFTWARE_REV[] = "soft-rev 1"; // 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; 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; } void connectionCallback(const Gap::ConnectionCallbackParams_t *params) { DEBUG("Connected!\n\r"); isConnected = 1; connectionLed = isConnected; } 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; 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 turnLaserPowerOn() { if(powerOffState == true) { powerOffState = false; // disableLRF = 0; // wait_ms(100); // nReset = 1; // wait_ms(100); // trun power back on and reinstate serial and laser //DigitalIn rx(p26, PullUp); // serialPtr = new Serial(p27, p26); // serialPtr->baud(READER_BAUD_RATE); // disableFlowControl(); // laserPtr = new Laser(*serialPtr); laserPtr->enableMeasurement(true); laserPtr->setRedDot(1); // TODO remove this- just for debuging //redLed = 1; } } void turnLaserPowerOff() { if(powerOffState == false) { powerOffState = true; laserPtr->setRedDot(0); // this disables measurements // also take power off the Laser, but first ensure io pins are not powered // if(serialPtr != NULL) delete serialPtr; // serialPtr = new Serial(NC, p26); // DigitalOut rx(p26); // DigitalOut tx(p27); // rx = 0; // tx = 0; // if(laserPtr != NULL) delete laserPtr; // laserPtr = new Laser(*serialPtr); // nReset = 0; // disableLRF = 1; // TODO remove this- just for debuging // redLed = 0; } } void resetActivityCheckerTask() { activityChecker.detach(); activityChecker.attach(activityCheckerTask, ACTIVITY_TIMEOUT_SEC); } 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(); 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 batteryCheckerTask(void) { enableBattVoltSense = 1; wait_ms(20); // wait for the circuit to settle float batt = battVoltage.read(); enableBattVoltSense = 0; // TODO need to convert act on the batt value- define threshold and hysterysis values if(redLed == 0 && batt < BATT_VALUE_THRESHOLD) { redLed = 1; } //else if(redLed == 1 && batt >= BATT_VALUE_THRESHOLD + BATT_VALUE_HYSTERYSIS) // { // redLed = 0; // } } /* processor for the hardware trigger button */ void triggerFall() { resetActivityCheckerTask(); turnLaserPowerOn(); laserPtr->triggerDistanceMeasurement(); timer.reset(); timer.start(); } /* 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, 1); // check acticity once every 3 minutes activityChecker.attach(activityCheckerTask, ACTIVITY_TIMEOUT_SEC); /* 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); turnLaserPowerOn(); while (true) { ble.waitForEvent(); } }