1. Finally all the software part is completed. It is obvious that PWM is most tricky part, since I do not know when it starts without and clear entry point.
2. The Software in mbed.org first the flyservice.h
#ifndef __BLE_FLY_SERVICE_H__ #define __BLE_FLY_SERVICE_H__ class FLYService { public: const static uint16_t FLY_SERVICE_UUID = 0xA000; const static uint16_t FLY_STATE_CHARACTERISTIC_UUID = 0xA001; FLYService(BLEDevice &_ble, bool initialValueForFLYCharacteristic) : ble(_ble), flyState(FLY_STATE_CHARACTERISTIC_UUID, &initialValueForFLYCharacteristic) { GattCharacteristic *charTable[] = {&flyState}; GattService flyService(FLY_SERVICE_UUID, charTable, sizeof(charTable) / sizeof(GattCharacteristic *)); ble.addService(flyService); } GattAttribute::Handle_t getValueHandle() const { return flyState.getValueHandle(); } private: BLEDevice &ble; ReadWriteGattCharacteristic flyState; }; #endif /* #ifndef __BLE_FLY_SERVICE_H__ */
Then the main.c
#include "mbed.h" #include "ble/BLE.h" #include "FlyService.h" #define MOTOR_PERIOD 1 // 1ms in PWM period #define PWM_FLY 50 // PWM start fly value in DC% #define PWM_DELTA 1 // PWM Delta value in DC% void initFlyWheels(void); void flyWheelsInstance(int flycontrol); PwmOut motorl(PA_0); PwmOut motorr(PA_1); uint16_t pwml,pwmr; // PWM value in DC% ranging 0~100 DigitalOut actuatedLED(LED1, 0); Serial pc(USBTX, USBRX); const static char DEVICE_NAME[] = "FLY"; static const uint16_t uuid16_list[] = {FLYService::FLY_SERVICE_UUID}; FLYService *flyServicePtr; void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) { (void)params; BLE::Instance().gap().startAdvertising(); // restart advertising } /** * This callback allows the FLYService to receive updates to the ledState Characteristic. * * @param[in] params * Information about the characterisitc being updated. */ void onDataWrittenCallback(const GattWriteCallbackParams *params) { if ((params->handle == flyServicePtr->getValueHandle()) && (params->len == 1)) { actuatedLED = *(params->data); //pc.printf("\r\n%d\r\n",*(params->data)); flyWheelsInstance(*(params->data)); } } /** * This function is called when the ble initialization process has failled */ void onBleInitError(BLE &ble, ble_error_t error) { /* Initialization error handling should go here */ } /** * Callback triggered when the ble initialization process has finished */ void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) { BLE& ble = params->ble; ble_error_t error = params->error; initFlyWheels(); pc.printf("\r\nStarting ... ...\r\n"); if (error != BLE_ERROR_NONE) { /* In case of error, forward the error handling to onBleInitError */ onBleInitError(ble, error); return; } /* Ensure that it is the default instance of BLE */ if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) { return; } ble.gap().onDisconnection(disconnectionCallback); ble.gattServer().onDataWritten(onDataWrittenCallback); bool initialValueForFLYCharacteristic = true; flyServicePtr = new FLYService(ble, initialValueForFLYCharacteristic); /* setup advertising */ ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); ble.gap().setAdvertisingInterval(1000); /* 1000ms. */ ble.gap().startAdvertising(); while (true) { ble.waitForEvent(); } } void initFlyWheels() { motorl.period_ms(MOTOR_PERIOD ); motorr.period_ms(MOTOR_PERIOD ); // Stop the motor as DC=0 pwml=0; pwmr=0; motorl=pwml/100; motorr=pwmr/100; } void flyWheelsInstance(int flycontrol) { //flycontrol = 1; pc.printf("\r\nflycontrol starting =%d\r\n",flycontrol); switch (flycontrol) { case 0: // Stop pwml=0; pwmr=0; pc.printf("\r\nflycontrol=%d\r\n",flycontrol); break; case 1: //Fly pwml=PWM_FLY; pwmr=PWM_FLY; pc.printf("\r\nflycontrol=%d\r\n",flycontrol); break; case 2: //turn left pwml=pwml-PWM_DELTA; pwmr=pwmr+PWM_DELTA; pc.printf("\r\nflycontrol=%d\r\n",flycontrol); break; case '3': //turn right pwml=pwml+PWM_DELTA; pwmr=pwmr-PWM_DELTA; pc.printf("\r\nflycontrol=%d\r\n",flycontrol); break; case 4: //Speed up pwml=pwml+PWM_DELTA; pwmr=pwmr+PWM_DELTA; pc.printf("\r\nflycontrol=%d\r\n",flycontrol); break; case 6: //Speed down pwml=pwml-PWM_DELTA; pwmr=pwmr-PWM_DELTA; pc.printf("\r\nflycontrol=%d\r\n",flycontrol); break; default: // Nothing change if not 1~6 pwml=pwml; pwmr=pwmr; break; } // Setting the pwm control for left motor and right motor in DC% pc.printf("\r\npwml=%d--pwmr=%d\r\n",pwml,pwmr); motorl=pwml/100; motorr=pwmr/100; } int main(void) { BLE &ble = BLE::Instance(); ble.init(bleInitComplete); }
The instance response to number 1 to 6 for different reaction, led to PWM duty cycle variation in pwml and pwmr. While these is still some flaw, the number shall be limited to 0-100. I can fix later with if-then or just simple math function.
3. Here is screenshot for test result .
I used standard Serial communication in 9600bps. Code like printf() can be remarked in final version.
It work well with each number.
5. Another part is APP control, codes as attached zip files. I can not upload the barecode. So check it in whole. Also, android apk file build by cordova is the zip file too.
Screen shot as follows,
Optional, you can try text input directly. Same like button press.
Here is the output for cordova build process
6. Hopefully, next bolg shall be the last one, when I install the boards on board. Funny part of the design.
I have made with packing box from Element14 instead of the demo toy at hand.