Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: BME280 TextLCD nRF51_Vdd
Fork of TYBLE16_mbedlized_os5_BASE by
Revision 1:9011c83e4178, committed 2018-04-14
- Comitter:
- kenjiArai
- Date:
- Sat Apr 14 04:56:34 2018 +0000
- Parent:
- 0:6eea047171a3
- Child:
- 2:47ad8c48224e
- Commit message:
- added samples
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/0_Blinky_LED/main.cpp Sat Apr 14 04:56:34 2018 +0000
@@ -0,0 +1,50 @@
+/*
+ * Mbed Application program / Blinky
+ *
+ * Copyright (c) 2018 Kenji Arai / JH1PJL
+ * http://www.page.sannet.ne.jp/kenjia/index.html
+ * https://os.mbed.com/users/kenjiArai/
+ * Created: April 10th, 2018
+ * Revised: April 14th, 2018
+ */
+
+//#define EXAMPLE_0_BLINKY_LED
+#ifdef EXAMPLE_0_BLINKY_LED
+
+// Include --------------------------------------------------------------------
+#include "mbed.h"
+#include "TYBLE16_BASE.h"
+
+// Definition -----------------------------------------------------------------
+
+// Constructor ----------------------------------------------------------------
+DigitalOut my_led(LED1);
+Serial pc(USBTX, USBRX);
+
+// RAM ------------------------------------------------------------------------
+
+// ROM / Constant data --------------------------------------------------------
+char *const opngmsg =
+ "\x1b[2J\x1b[H"__FILE__ "\r\n"__DATE__ " " __TIME__ " (UTC)\r\n""\r\n";
+
+// Function prototypes --------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// Control Program
+//------------------------------------------------------------------------------
+int main()
+{
+ uint32_t count = 0;
+
+ pc.puts(opngmsg);
+ // Check TYBLE-16 configuration
+ cpu_sys();
+ compile_condition();
+ while(true) {
+ my_led = !my_led;
+ pc.printf("%8u\r\n", count++);
+ Thread::wait(1000);
+ }
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/1_Check_RTC/main.cpp Sat Apr 14 04:56:34 2018 +0000
@@ -0,0 +1,237 @@
+/*
+ * Mbed Application program / check RTC (Real Time Clock)
+ *
+ * Copyright (c) 2017,'18 Kenji Arai / JH1PJL
+ * http://www.page.sannet.ne.jp/kenjia/index.html
+ * https://os.mbed.com/users/kenjiArai/
+ * Created: August 11th, 2017
+ * Revised: April 14th, 2018
+ */
+
+//#define EXAMPLE_1_CHECK_RTC
+#ifdef EXAMPLE_1_CHECK_RTC
+
+// Include --------------------------------------------------------------------
+#include "mbed.h"
+#include "TYBLE16_BASE.h"
+
+// Definition -----------------------------------------------------------------
+
+// Constructor ----------------------------------------------------------------
+DigitalIn userSW(BUTTON1);
+DigitalOut myled(LED1); // Indicate the sampling period
+Serial pc(USBTX, USBRX);
+
+// RAM ------------------------------------------------------------------------
+
+// ROM / Constant data --------------------------------------------------------
+char *const msg0 = "Is a time correct? If no, please hit any key. ";
+char *const msg1 = "<Push USER SW then enter sleep mode> ";
+char *const msg2 = "\r\nEnter Standby Mode, please push RESET to wake-up\r\n";
+char *const opngmsg =
+ "\x1b[2J\x1b[H"__FILE__ "\r\n"__DATE__ " " __TIME__ " (UTC)\r\n""\r\n";
+
+// Function prototypes --------------------------------------------------------
+static void time_enter_mode(void);
+static void chk_and_set_time(char *ptr);
+static void goto_standby(void);
+static int xatoi (char **str, unsigned long *res);
+static void get_line (char *buff, int len);
+
+//------------------------------------------------------------------------------
+// Control Program
+//------------------------------------------------------------------------------
+int main()
+{
+ char buf[64]; // data buffer for text
+ time_t seconds;
+ uint8_t wait_counter = 0;
+
+ pc.puts(opngmsg);
+ // Check TYBLE-16 configuration
+ cpu_sys();
+ compile_condition();
+ myled = !myled;
+ wait(1.0);
+ myled = !myled;
+ wait(1.0);
+ while(1) {
+ seconds = time(NULL);
+ strftime(buf, 50, " %B %d,'%y, %H:%M:%S\r\n", localtime(&seconds));
+ pc.printf("[Time] %s", buf);
+ pc.printf(msg0);
+ pc.printf("%s\r", msg1);
+ wait_counter = 0;
+ while (seconds == time(NULL)) {
+ if (pc.readable() == 1) {
+ buf[0] = pc.getc(); // dummy read
+ time_enter_mode();
+ }
+ if (userSW == 0) {
+ pc.printf(msg2);
+ wait(1.0);
+ myled = 0;
+ goto_standby();
+ }
+ wait(0.05);
+ if (++wait_counter > (2000 / 50)) {
+ break;
+ }
+ }
+ uint8_t n = strlen(msg0) + strlen(msg1);
+ for (uint8_t i = 0; i < n; i++) {
+ pc.putc(' ');
+ }
+ pc.printf(" \r"); // Not use '\n'
+ myled = !myled;
+ }
+}
+
+void time_enter_mode(void)
+{
+ char *ptr;
+ char linebuf[64];
+
+ pc.printf("\r\nSet time into RTC\r\n");
+ pc.printf(" e.g. >18 4 14 10 11 12 -> April 14th,'18, 10:11:12\r\n");
+ pc.printf(" If time is fine, just hit enter\r\n");
+ pc.putc('>');
+ ptr = linebuf;
+ get_line(ptr, sizeof(linebuf));
+ pc.printf("\r");
+ chk_and_set_time(ptr);
+}
+
+void goto_standby(void)
+{
+ deepsleep(); // Not Standby Mode but Deep Sleep Mode
+}
+
+// Get key input data
+void get_line (char *buff, int len)
+{
+ char c;
+ int idx = 0;
+
+ for (;;) {
+ c = pc.getc();
+ if (c == '\r') {
+ buff[idx++] = c;
+ break;
+ }
+ if ((c == '\b') && idx) {
+ idx--;
+ pc.putc(c);
+ pc.putc(' ');
+ pc.putc(c);
+ }
+ if (((uint8_t)c >= ' ') && (idx < len - 1)) {
+ buff[idx++] = c;
+ pc.putc(c);
+ }
+ }
+ buff[idx] = 0;
+ pc.putc('\n');
+}
+
+void chk_and_set_time(char *ptr)
+{
+ unsigned long p1;
+ struct tm t;
+ time_t seconds;
+
+ if (xatoi(&ptr, &p1)) {
+ t.tm_year = (uint8_t)p1 + 100;
+ pc.printf("Year:%d ",p1);
+ xatoi( &ptr, &p1 );
+ t.tm_mon = (uint8_t)p1 - 1;
+ pc.printf("Month:%d ",p1);
+ xatoi( &ptr, &p1 );
+ t.tm_mday = (uint8_t)p1;
+ pc.printf("Day:%d ",p1);
+ xatoi( &ptr, &p1 );
+ t.tm_hour = (uint8_t)p1;
+ pc.printf("Hour:%d ",p1);
+ xatoi( &ptr, &p1 );
+ t.tm_min = (uint8_t)p1;
+ pc.printf("Min:%d ",p1);
+ xatoi( &ptr, &p1 );
+ t.tm_sec = (uint8_t)p1;
+ pc.printf("Sec: %d \r\n",p1);
+ } else {
+ return;
+ }
+ seconds = mktime(&t);
+ set_time(seconds);
+ pc.printf(
+ "Date: %04d/%02d/%02d, %02d:%02d:%02d\r\n",
+ t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec
+ );
+}
+
+// Change string -> integer
+int xatoi (char **str, unsigned long *res)
+{
+ unsigned long val;
+ unsigned char c, radix, s = 0;
+
+ while ((c = **str) == ' ') {
+ (*str)++;
+ }
+ if (c == '-') {
+ s = 1;
+ c = *(++(*str));
+ }
+ if (c == '0') {
+ c = *(++(*str));
+ if (c <= ' ') {
+ *res = 0;
+ return 1;
+ }
+ if (c == 'x') {
+ radix = 16;
+ c = *(++(*str));
+ } else {
+ if (c == 'b') {
+ radix = 2;
+ c = *(++(*str));
+ } else {
+ if ((c >= '0')&&(c <= '9')) {
+ radix = 8;
+ } else {
+ return 0;
+ }
+ }
+ }
+ } else {
+ if ((c < '1')||(c > '9')) {
+ return 0;
+ }
+ radix = 10;
+ }
+ val = 0;
+ while (c > ' ') {
+ if (c >= 'a') {
+ c -= 0x20;
+ }
+ c -= '0';
+ if (c >= 17) {
+ c -= 7;
+ if (c <= 9) {
+ return 0;
+ }
+ }
+ if (c >= radix) {
+ return 0;
+ }
+ val = val * radix + c;
+ c = *(++(*str));
+ }
+ if (s) {
+ val = -val;
+ }
+ *res = val;
+ return 1;
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/2_EddyStoneBeacon/Eddystone/EddystoneService.cpp Sat Apr 14 04:56:34 2018 +0000
@@ -0,0 +1,570 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2015 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 "EddystoneService.h"
+
+/* Initialise the EddystoneService using parameters from persistent storage */
+EddystoneService::EddystoneService(BLE &bleIn,
+ EddystoneParams_t ¶msIn,
+ const PowerLevels_t &advPowerLevelsIn,
+ const PowerLevels_t &radioPowerLevelsIn,
+ uint32_t advConfigIntervalIn) :
+ ble(bleIn),
+ operationMode(EDDYSTONE_MODE_NONE),
+ urlFrame(paramsIn.urlData, paramsIn.urlDataLength),
+ uidFrame(paramsIn.uidNamespaceID, paramsIn.uidInstanceID),
+ tlmFrame(paramsIn.tlmVersion),
+ resetFlag(false),
+ tlmBatteryVoltageCallback(NULL),
+ tlmBeaconTemperatureCallback(NULL)
+{
+ lockState = paramsIn.lockState;
+ flags = paramsIn.flags;
+ txPowerMode = paramsIn.txPowerMode;
+ beaconPeriod = correctAdvertisementPeriod(paramsIn.beaconPeriod);
+
+ memcpy(lock, paramsIn.lock, sizeof(Lock_t));
+ memcpy(unlock, paramsIn.unlock, sizeof(Lock_t));
+
+ eddystoneConstructorHelper(advPowerLevelsIn, radioPowerLevelsIn, advConfigIntervalIn);
+}
+
+/* When using this constructor we need to call setURLData,
+ * setTMLData and setUIDData to initialise values manually
+ */
+EddystoneService::EddystoneService(BLE &bleIn,
+ const PowerLevels_t &advPowerLevelsIn,
+ const PowerLevels_t &radioPowerLevelsIn,
+ uint32_t advConfigIntervalIn) :
+ ble(bleIn),
+ operationMode(EDDYSTONE_MODE_NONE),
+ urlFrame(),
+ uidFrame(),
+ tlmFrame(),
+ lockState(false),
+ resetFlag(false),
+ lock(),
+ unlock(),
+ flags(0),
+ txPowerMode(0),
+ beaconPeriod(DEFAULT_BEACON_PERIOD_MSEC),
+ tlmBatteryVoltageCallback(NULL),
+ tlmBeaconTemperatureCallback(NULL)
+{
+ eddystoneConstructorHelper(advPowerLevelsIn, radioPowerLevelsIn, advConfigIntervalIn);
+}
+
+/* Setup callback to update BatteryVoltage in TLM frame */
+void EddystoneService::onTLMBatteryVoltageUpdate(TlmUpdateCallback_t tlmBatteryVoltageCallbackIn)
+{
+ tlmBatteryVoltageCallback = tlmBatteryVoltageCallbackIn;
+}
+
+/* Setup callback to update BeaconTemperature in TLM frame */
+void EddystoneService::onTLMBeaconTemperatureUpdate(TlmUpdateCallback_t tlmBeaconTemperatureCallbackIn)
+{
+ tlmBeaconTemperatureCallback = tlmBeaconTemperatureCallbackIn;
+}
+
+void EddystoneService::setTLMData(uint8_t tlmVersionIn)
+{
+ tlmFrame.setTLMData(tlmVersionIn);
+}
+
+void EddystoneService::setURLData(const char *urlDataIn)
+{
+ urlFrame.setURLData(urlDataIn);
+}
+
+void EddystoneService::setUIDData(const UIDNamespaceID_t *uidNamespaceIDIn, const UIDInstanceID_t *uidInstanceIDIn)
+{
+ uidFrame.setUIDData(uidNamespaceIDIn, uidInstanceIDIn);
+}
+
+EddystoneService::EddystoneError_t EddystoneService::startConfigService(void)
+{
+ if (operationMode == EDDYSTONE_MODE_CONFIG) {
+ /* Nothing to do, we are already in config mode */
+ return EDDYSTONE_ERROR_NONE;
+ } else if (advConfigInterval == 0) {
+ /* Nothing to do, the advertisement interval is 0 */
+ return EDDYSTONE_ERROR_INVALID_ADVERTISING_INTERVAL;
+ }
+
+ if (operationMode == EDDYSTONE_MODE_BEACON) {
+ ble.shutdown();
+ /* Free unused memory */
+ freeBeaconFrames();
+ operationMode = EDDYSTONE_MODE_CONFIG;
+ ble.init(this, &EddystoneService::bleInitComplete);
+ return EDDYSTONE_ERROR_NONE;
+ }
+
+ operationMode = EDDYSTONE_MODE_CONFIG;
+ setupConfigService();
+ return EDDYSTONE_ERROR_NONE;
+}
+
+EddystoneService::EddystoneError_t EddystoneService::startBeaconService(uint16_t consecUrlFramesIn, uint16_t consecUidFramesIn, uint16_t consecTlmFramesIn)
+{
+ if (operationMode == EDDYSTONE_MODE_BEACON) {
+ /* Nothing to do, we are already in beacon mode */
+ return EDDYSTONE_ERROR_NONE;
+ } else if (!consecUrlFramesIn && !consecUidFramesIn && !consecTlmFramesIn) {
+ /* Nothing to do, the user wants 0 consecutive frames of everything */
+ return EDDYSTONE_ERROR_INVALID_CONSEC_FRAMES;
+ } else if (!beaconPeriod) {
+ /* Nothing to do, the period is 0 for all frames */
+ return EDDYSTONE_ERROR_INVALID_BEACON_PERIOD;
+ }
+
+ /* Setup tracking of the current advertised frame. Note that this will
+ * cause URL or UID frames to be advertised first!
+ */
+ currentAdvertisedFrame = EDDYSTONE_FRAME_TLM;
+ consecFrames[EDDYSTONE_FRAME_URL] = consecUrlFramesIn;
+ consecFrames[EDDYSTONE_FRAME_UID] = consecUidFramesIn;
+ consecFrames[EDDYSTONE_FRAME_TLM] = consecTlmFramesIn;
+
+ memset(currentConsecFrames, 0, sizeof(uint16_t) * NUM_EDDYSTONE_FRAMES);
+
+ if (operationMode == EDDYSTONE_MODE_CONFIG) {
+ ble.shutdown();
+ /* Free unused memory */
+ freeConfigCharacteristics();
+ operationMode = EDDYSTONE_MODE_BEACON;
+ ble.init(this, &EddystoneService::bleInitComplete);
+ return EDDYSTONE_ERROR_NONE;
+ }
+
+ operationMode = EDDYSTONE_MODE_BEACON;
+ setupBeaconService();
+ return EDDYSTONE_ERROR_NONE;
+}
+
+/* It is not the responsibility of the Eddystone implementation to store
+ * the configured parameters in persistent storage since this is
+ * platform-specific. So we provide this function that returns the
+ * configured values that need to be stored and the main application
+ * takes care of storing them.
+ */
+void EddystoneService::getEddystoneParams(EddystoneParams_t *params)
+{
+ params->lockState = lockState;
+ params->flags = flags;
+ params->txPowerMode = txPowerMode;
+ params->beaconPeriod = beaconPeriod;
+ params->tlmVersion = tlmFrame.getTLMVersion();
+ params->urlDataLength = urlFrame.getEncodedURLDataLength();
+
+ memcpy(params->advPowerLevels, advPowerLevels, sizeof(PowerLevels_t));
+ memcpy(params->lock, lock, sizeof(Lock_t));
+ memcpy(params->unlock, unlock, sizeof(Lock_t));
+ memcpy(params->urlData, urlFrame.getEncodedURLData(), urlFrame.getEncodedURLDataLength());
+ memcpy(params->uidNamespaceID, uidFrame.getUIDNamespaceID(), sizeof(UIDNamespaceID_t));
+ memcpy(params->uidInstanceID, uidFrame.getUIDInstanceID(), sizeof(UIDInstanceID_t));
+}
+
+/* Helper function used only once during constructing the object to avoid
+ * duplicated code.
+ */
+void EddystoneService::eddystoneConstructorHelper(const PowerLevels_t &advPowerLevelsIn,
+ const PowerLevels_t &radioPowerLevelsIn,
+ uint32_t advConfigIntervalIn)
+{
+ advConfigInterval = (advConfigIntervalIn > 0) ? correctAdvertisementPeriod(advConfigIntervalIn) : 0;
+
+ memcpy(radioPowerLevels, radioPowerLevelsIn, sizeof(PowerLevels_t));
+ memcpy(advPowerLevels, advPowerLevelsIn, sizeof(PowerLevels_t));
+
+ /* TODO: Note that this timer is started from the time EddystoneService
+ * is initialised and NOT from when the device is booted. So app needs
+ * to take care that EddystoneService is one of the first things to be
+ * started!
+ */
+ timeSinceBootTimer.start();
+}
+
+/* When changing modes, we shutdown and init the BLE instance, so
+ * this is needed to complete the initialisation task.
+ */
+void EddystoneService::bleInitComplete(BLE::InitializationCompleteCallbackContext* initContext)
+{
+ if (initContext->error != BLE_ERROR_NONE) {
+ /* Initialisation failed */
+ return;
+ }
+
+ switch (operationMode) {
+ case EDDYSTONE_MODE_CONFIG:
+ setupConfigService();
+ break;
+ case EDDYSTONE_MODE_BEACON:
+ setupBeaconService();
+ break;
+ default:
+ /* Some error occurred */
+ break;
+ }
+}
+
+void EddystoneService::swapAdvertisedFrame(void)
+{
+ /* This essentially works out which is the next frame to be swapped in
+ * and updated the advertised packets. It will eventually terminate
+ * and in the worst case the frame swapped in is the current advertised
+ * frame.
+ */
+ while (true) {
+ currentAdvertisedFrame = (currentAdvertisedFrame + 1) % NUM_EDDYSTONE_FRAMES;
+
+ if (currentAdvertisedFrame == EDDYSTONE_FRAME_URL && consecFrames[EDDYSTONE_FRAME_URL] > 0) {
+ updateAdvertisementPacket(rawUrlFrame, urlFrame.getRawFrameSize());
+ return;
+ } else if (currentAdvertisedFrame == EDDYSTONE_FRAME_UID && consecFrames[EDDYSTONE_FRAME_UID] > 0) {
+ updateAdvertisementPacket(rawUidFrame, uidFrame.getRawFrameSize());
+ return;
+ } else if (currentAdvertisedFrame == EDDYSTONE_FRAME_TLM && consecFrames[EDDYSTONE_FRAME_UID] > 0) {
+ updateRawTLMFrame();
+ updateAdvertisementPacket(rawTlmFrame, tlmFrame.getRawFrameSize());
+ return;
+ }
+ }
+}
+
+/* Helper function that calls user-defined functions to update Battery Voltage and Temperature (if available),
+ * then updates the raw frame data and finally updates the actual advertised packet. This operation must be
+ * done fairly often because the TLM frame TimeSinceBoot must have a 0.1 secs resolution according to the
+ * Eddystone specification.
+ */
+void EddystoneService::updateRawTLMFrame(void)
+{
+ if (tlmBeaconTemperatureCallback != NULL) {
+ tlmFrame.updateBeaconTemperature((*tlmBeaconTemperatureCallback)(tlmFrame.getBeaconTemperature()));
+ }
+ if (tlmBatteryVoltageCallback != NULL) {
+ tlmFrame.updateBatteryVoltage((*tlmBatteryVoltageCallback)(tlmFrame.getBatteryVoltage()));
+ }
+ tlmFrame.updateTimeSinceBoot(timeSinceBootTimer.read_ms());
+ tlmFrame.constructTLMFrame(rawTlmFrame);
+}
+
+void EddystoneService::updateAdvertisementPacket(const uint8_t* rawFrame, size_t rawFrameLength)
+{
+ ble.gap().clearAdvertisingPayload();
+ ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
+ ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, EDDYSTONE_UUID, sizeof(EDDYSTONE_UUID));
+ ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, rawFrame, rawFrameLength);
+}
+
+void EddystoneService::setupBeaconService(void)
+{
+ /* Initialise arrays to hold constructed raw frames */
+ if (consecFrames[EDDYSTONE_FRAME_URL] > 0) {
+ rawUrlFrame = new uint8_t[urlFrame.getRawFrameSize()];
+ urlFrame.constructURLFrame(rawUrlFrame, advPowerLevels[txPowerMode]);
+ }
+
+ if (consecFrames[EDDYSTONE_FRAME_UID] > 0) {
+ rawUidFrame = new uint8_t[uidFrame.getRawFrameSize()];
+ uidFrame.constructUIDFrame(rawUidFrame, advPowerLevels[txPowerMode]);
+ }
+
+ if (consecFrames[EDDYSTONE_FRAME_TLM] > 0) {
+ rawTlmFrame = new uint8_t[tlmFrame.getRawFrameSize()];
+ /* Do not initialise because we have to reconstruct every 0.1 secs */
+ }
+
+ /* Configure advertisements */
+ ble.gap().setTxPower(radioPowerLevels[txPowerMode]);
+ ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED);
+ ble.gap().setAdvertisingInterval(beaconPeriod);
+ ble.gap().onRadioNotification(this, &EddystoneService::radioNotificationCallback);
+ ble.gap().initRadioNotification();
+
+ /* Set advertisement packet payload */
+ swapAdvertisedFrame();
+
+ /* Start advertising */
+ ble.gap().startAdvertising();
+}
+
+void EddystoneService::setupConfigService(void)
+{
+ lockStateChar = new ReadOnlyGattCharacteristic<bool>(UUID_LOCK_STATE_CHAR, &lockState);
+ lockChar = new WriteOnlyArrayGattCharacteristic<uint8_t, sizeof(Lock_t)>(UUID_LOCK_CHAR, lock);
+ unlockChar = new WriteOnlyArrayGattCharacteristic<uint8_t, sizeof(Lock_t)>(UUID_UNLOCK_CHAR, unlock);
+ urlDataChar = new GattCharacteristic(UUID_URL_DATA_CHAR, urlFrame.getEncodedURLData(), 0, URL_DATA_MAX, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
+ flagsChar = new ReadWriteGattCharacteristic<uint8_t>(UUID_FLAGS_CHAR, &flags);
+ advPowerLevelsChar = new ReadWriteArrayGattCharacteristic<int8_t, sizeof(PowerLevels_t)>(UUID_ADV_POWER_LEVELS_CHAR, advPowerLevels);
+ txPowerModeChar = new ReadWriteGattCharacteristic<uint8_t>(UUID_TX_POWER_MODE_CHAR, &txPowerMode);
+ beaconPeriodChar = new ReadWriteGattCharacteristic<uint16_t>(UUID_BEACON_PERIOD_CHAR, &beaconPeriod);
+ resetChar = new WriteOnlyGattCharacteristic<bool>(UUID_RESET_CHAR, &resetFlag);
+
+ lockChar->setWriteAuthorizationCallback(this, &EddystoneService::lockAuthorizationCallback);
+ unlockChar->setWriteAuthorizationCallback(this, &EddystoneService::unlockAuthorizationCallback);
+ urlDataChar->setWriteAuthorizationCallback(this, &EddystoneService::urlDataWriteAuthorizationCallback);
+ flagsChar->setWriteAuthorizationCallback(this, &EddystoneService::basicAuthorizationCallback<uint8_t>);
+ advPowerLevelsChar->setWriteAuthorizationCallback(this, &EddystoneService::basicAuthorizationCallback<PowerLevels_t>);
+ txPowerModeChar->setWriteAuthorizationCallback(this, &EddystoneService::powerModeAuthorizationCallback);
+ beaconPeriodChar->setWriteAuthorizationCallback(this, &EddystoneService::basicAuthorizationCallback<uint16_t>);
+ resetChar->setWriteAuthorizationCallback(this, &EddystoneService::basicAuthorizationCallback<bool>);
+
+ charTable[0] = lockStateChar;
+ charTable[1] = lockChar;
+ charTable[2] = unlockChar;
+ charTable[3] = urlDataChar;
+ charTable[4] = flagsChar;
+ charTable[5] = advPowerLevelsChar;
+ charTable[6] = txPowerModeChar;
+ charTable[7] = beaconPeriodChar;
+ charTable[8] = resetChar;
+
+ GattService configService(UUID_URL_BEACON_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
+
+ ble.gattServer().addService(configService);
+ ble.gattServer().onDataWritten(this, &EddystoneService::onDataWrittenCallback);
+ updateCharacteristicValues();
+ setupEddystoneConfigAdvertisements();
+}
+
+void EddystoneService::freeConfigCharacteristics(void)
+{
+ delete lockStateChar;
+ delete lockChar;
+ delete unlockChar;
+ delete urlDataChar;
+ delete flagsChar;
+ delete advPowerLevelsChar;
+ delete txPowerModeChar;
+ delete beaconPeriodChar;
+ delete resetChar;
+}
+
+void EddystoneService::freeBeaconFrames(void)
+{
+ delete[] rawUrlFrame;
+ delete[] rawUidFrame;
+ delete[] rawTlmFrame;
+}
+
+void EddystoneService::radioNotificationCallback(bool radioActive)
+{
+ if (radioActive) {
+ /* Do nothing */
+ return;
+ }
+
+ tlmFrame.updatePduCount();
+ currentConsecFrames[currentAdvertisedFrame]++;
+
+ if (consecFrames[currentAdvertisedFrame] > currentConsecFrames[currentAdvertisedFrame]) {
+ if (currentAdvertisedFrame == EDDYSTONE_FRAME_TLM) {
+ /* Update the TLM frame otherwise we will not meet the 0.1 secs resolution of
+ * the Eddystone specification.
+ */
+ updateRawTLMFrame();
+ updateAdvertisementPacket(rawTlmFrame, tlmFrame.getRawFrameSize());
+ }
+ /* Keep advertising the same frame */
+ return;
+ }
+
+ currentConsecFrames[currentAdvertisedFrame] = 0;
+
+#ifdef YOTTA_CFG_MBED_OS
+ minar::Scheduler::postCallback(this, &EddystoneService::swapAdvertisedFrame);
+#else
+ swapAdvertisedFrameTimeout.attach_us(this, &EddystoneService::swapAdvertisedFrame, 1);
+#endif
+}
+
+/*
+ * Internal helper function used to update the GATT database following any
+ * change to the internal state of the service object.
+ */
+void EddystoneService::updateCharacteristicValues(void)
+{
+ ble.gattServer().write(lockStateChar->getValueHandle(), reinterpret_cast<uint8_t *>(&lockState), sizeof(bool));
+ ble.gattServer().write(urlDataChar->getValueHandle(), urlFrame.getEncodedURLData(), urlFrame.getEncodedURLDataLength());
+ ble.gattServer().write(flagsChar->getValueHandle(), &flags, sizeof(uint8_t));
+ ble.gattServer().write(beaconPeriodChar->getValueHandle(), reinterpret_cast<uint8_t *>(&beaconPeriod), sizeof(uint16_t));
+ ble.gattServer().write(txPowerModeChar->getValueHandle(), &txPowerMode, sizeof(uint8_t));
+ ble.gattServer().write(advPowerLevelsChar->getValueHandle(), reinterpret_cast<uint8_t *>(advPowerLevels), sizeof(PowerLevels_t));
+ ble.gattServer().write(lockChar->getValueHandle(), lock, sizeof(PowerLevels_t));
+ ble.gattServer().write(unlockChar->getValueHandle(), unlock, sizeof(PowerLevels_t));
+}
+
+void EddystoneService::setupEddystoneConfigAdvertisements(void)
+{
+ ble.gap().clearAdvertisingPayload();
+ ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
+
+ /* UUID is in different order in the ADV frame (!) */
+ uint8_t reversedServiceUUID[sizeof(UUID_URL_BEACON_SERVICE)];
+ for (size_t i = 0; i < sizeof(UUID_URL_BEACON_SERVICE); i++) {
+ reversedServiceUUID[i] = UUID_URL_BEACON_SERVICE[sizeof(UUID_URL_BEACON_SERVICE) - i - 1];
+ }
+ ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS, reversedServiceUUID, sizeof(reversedServiceUUID));
+ ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_TAG);
+ ble.gap().accumulateScanResponse(GapAdvertisingData::COMPLETE_LOCAL_NAME, reinterpret_cast<const uint8_t *>(&DEVICE_NAME), sizeof(DEVICE_NAME));
+ ble.gap().accumulateScanResponse(
+ GapAdvertisingData::TX_POWER_LEVEL,
+ reinterpret_cast<uint8_t *>(&advPowerLevels[TX_POWER_MODE_LOW]),
+ sizeof(uint8_t));
+
+ ble.gap().setTxPower(radioPowerLevels[txPowerMode]);
+ ble.gap().setDeviceName(reinterpret_cast<const uint8_t *>(&DEVICE_NAME));
+ ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
+ ble.gap().setAdvertisingInterval(advConfigInterval);
+ ble.gap().startAdvertising();
+}
+
+void EddystoneService::lockAuthorizationCallback(GattWriteAuthCallbackParams *authParams)
+{
+ if (lockState) {
+ authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
+ } else if (authParams->len != sizeof(Lock_t)) {
+ authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
+ } else if (authParams->offset != 0) {
+ authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
+ } else {
+ authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
+ }
+}
+
+void EddystoneService::unlockAuthorizationCallback(GattWriteAuthCallbackParams *authParams)
+{
+ if (!lockState && (authParams->len == sizeof(Lock_t))) {
+ authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
+ } else if (authParams->len != sizeof(Lock_t)) {
+ authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
+ } else if (authParams->offset != 0) {
+ authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
+ } else if (memcmp(authParams->data, lock, sizeof(Lock_t)) != 0) {
+ authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
+ } else {
+ authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
+ }
+}
+
+void EddystoneService::urlDataWriteAuthorizationCallback(GattWriteAuthCallbackParams *authParams)
+{
+ if (lockState) {
+ authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
+ } else if (authParams->offset != 0) {
+ authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
+ } else {
+ authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
+ }
+}
+
+void EddystoneService::powerModeAuthorizationCallback(GattWriteAuthCallbackParams *authParams)
+{
+ if (lockState) {
+ authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
+ } else if (authParams->len != sizeof(uint8_t)) {
+ authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
+ } else if (authParams->offset != 0) {
+ authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
+ } else if (*((uint8_t *)authParams->data) >= NUM_POWER_MODES) {
+ authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_WRITE_NOT_PERMITTED;
+ } else {
+ authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
+ }
+}
+
+template <typename T>
+void EddystoneService::basicAuthorizationCallback(GattWriteAuthCallbackParams *authParams)
+{
+ if (lockState) {
+ authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
+ } else if (authParams->len != sizeof(T)) {
+ authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
+ } else if (authParams->offset != 0) {
+ authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
+ } else {
+ authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
+ }
+}
+
+/*
+ * This callback is invoked when a GATT client attempts to modify any of the
+ * characteristics of this service. Attempts to do so are also applied to
+ * the internal state of this service object.
+ */
+void EddystoneService::onDataWrittenCallback(const GattWriteCallbackParams *writeParams)
+{
+ uint16_t handle = writeParams->handle;
+
+ if (handle == lockChar->getValueHandle()) {
+ memcpy(lock, writeParams->data, sizeof(Lock_t));
+ /* Set the state to be locked by the lock code (note: zeros are a valid lock) */
+ lockState = true;
+ ble.gattServer().write(lockChar->getValueHandle(), lock, sizeof(PowerLevels_t));
+ ble.gattServer().write(lockStateChar->getValueHandle(), reinterpret_cast<uint8_t *>(&lockState), sizeof(bool));
+ } else if (handle == unlockChar->getValueHandle()) {
+ /* Validated earlier */
+ lockState = false;
+ ble.gattServer().write(unlockChar->getValueHandle(), unlock, sizeof(PowerLevels_t));
+ ble.gattServer().write(lockStateChar->getValueHandle(), reinterpret_cast<uint8_t *>(&lockState), sizeof(bool));
+ } else if (handle == urlDataChar->getValueHandle()) {
+ urlFrame.setEncodedURLData(writeParams->data, writeParams->len);
+ ble.gattServer().write(urlDataChar->getValueHandle(), urlFrame.getEncodedURLData(), urlFrame.getEncodedURLDataLength());
+ } else if (handle == flagsChar->getValueHandle()) {
+ flags = *(writeParams->data);
+ ble.gattServer().write(flagsChar->getValueHandle(), &flags, sizeof(uint8_t));
+ } else if (handle == advPowerLevelsChar->getValueHandle()) {
+ memcpy(advPowerLevels, writeParams->data, sizeof(PowerLevels_t));
+ ble.gattServer().write(advPowerLevelsChar->getValueHandle(), reinterpret_cast<uint8_t *>(advPowerLevels), sizeof(PowerLevels_t));
+ } else if (handle == txPowerModeChar->getValueHandle()) {
+ txPowerMode = *(writeParams->data);
+ ble.gattServer().write(txPowerModeChar->getValueHandle(), &txPowerMode, sizeof(uint8_t));
+ } else if (handle == beaconPeriodChar->getValueHandle()) {
+ uint16_t tmpBeaconPeriod = correctAdvertisementPeriod(*((uint16_t *)(writeParams->data)));
+ if (tmpBeaconPeriod != beaconPeriod) {
+ beaconPeriod = tmpBeaconPeriod;
+ ble.gattServer().write(beaconPeriodChar->getValueHandle(), reinterpret_cast<uint8_t *>(&beaconPeriod), sizeof(uint16_t));
+ }
+ } else if (handle == resetChar->getValueHandle() && (*((uint8_t *)writeParams->data) != 0)) {
+ /* Reset characteristics to default values */
+ flags = 0;
+ txPowerMode = TX_POWER_MODE_LOW;
+ beaconPeriod = DEFAULT_BEACON_PERIOD_MSEC;
+
+ urlFrame.setURLData(DEFAULT_URL);
+ memset(lock, 0, sizeof(Lock_t));
+
+ ble.gattServer().write(urlDataChar->getValueHandle(), urlFrame.getEncodedURLData(), urlFrame.getEncodedURLDataLength());
+ ble.gattServer().write(flagsChar->getValueHandle(), &flags, sizeof(uint8_t));
+ ble.gattServer().write(txPowerModeChar->getValueHandle(), &txPowerMode, sizeof(uint8_t));
+ ble.gattServer().write(beaconPeriodChar->getValueHandle(), reinterpret_cast<uint8_t *>(&beaconPeriod), sizeof(uint16_t));
+ ble.gattServer().write(lockChar->getValueHandle(), lock, sizeof(PowerLevels_t));
+ }
+}
+
+uint16_t EddystoneService::correctAdvertisementPeriod(uint16_t beaconPeriodIn) const
+{
+ /* Re-map beaconPeriod to within permissible bounds if necessary. */
+ if (beaconPeriodIn != 0) {
+ if (beaconPeriodIn < ble.gap().getMinAdvertisingInterval()) {
+ return ble.gap().getMinAdvertisingInterval();
+ } else if (beaconPeriodIn > ble.gap().getMaxAdvertisingInterval()) {
+ return ble.gap().getMaxAdvertisingInterval();
+ }
+ }
+ return beaconPeriodIn;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/2_EddyStoneBeacon/Eddystone/EddystoneService.h Sat Apr 14 04:56:34 2018 +0000
@@ -0,0 +1,238 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2015 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.
+ */
+
+#ifndef __EDDYSTONESERVICE_H__
+#define __EDDYSTONESERVICE_H__
+
+#include "ble/BLE.h"
+#include "EddystoneTypes.h"
+#include "URLFrame.h"
+#include "UIDFrame.h"
+#include "TLMFrame.h"
+#include <string.h>
+#ifdef YOTTA_CFG_MBED_OS
+ #include "mbed-drivers/mbed.h"
+#else
+ #include "mbed.h"
+#endif
+
+class EddystoneService
+{
+public:
+ static const uint16_t TOTAL_CHARACTERISTICS = 9;
+
+ static const uint32_t DEFAULT_CONFIG_PERIOD_MSEC = 1000;
+ static const uint16_t DEFAULT_BEACON_PERIOD_MSEC = 1000;
+
+ /* Operation modes of the EddystoneService:
+ * NONE: EddystoneService has been initialised but no memory has been
+ * dynamically allocated. Additionally, no services are running
+ * nothing is being advertised.
+ * CONFIG: EddystoneService has been initialised, the configuration
+ * service started and memory has been allocated for BLE
+ * characteristics. Memory consumption peaks during CONFIG
+ * mode.
+ * BEACON: Eddystone service is running as a beacon advertising URL,
+ * UID and/or TLM frames depending on how it is configured.
+ * Note: The main app can change the mode of EddystoneService at any point
+ * of time by calling startConfigService() or startBeaconService().
+ * Resources from the previous mode will be freed. It is currently NOT
+ * possible to force EddystoneService back into MODE_NONE.
+ */
+ enum OperationModes {
+ EDDYSTONE_MODE_NONE,
+ EDDYSTONE_MODE_CONFIG,
+ EDDYSTONE_MODE_BEACON
+ };
+
+ struct EddystoneParams_t {
+ bool lockState;
+ Lock_t lock;
+ Lock_t unlock;
+ uint8_t flags;
+ PowerLevels_t advPowerLevels;
+ uint8_t txPowerMode;
+ uint16_t beaconPeriod;
+ uint8_t tlmVersion;
+ uint8_t urlDataLength;
+ UrlData_t urlData;
+ UIDNamespaceID_t uidNamespaceID;
+ UIDInstanceID_t uidInstanceID;
+ };
+
+ enum EddystoneError_t {
+ EDDYSTONE_ERROR_NONE,
+ EDDYSTONE_ERROR_INVALID_BEACON_PERIOD,
+ EDDYSTONE_ERROR_INVALID_CONSEC_FRAMES,
+ EDDYSTONE_ERROR_INVALID_ADVERTISING_INTERVAL
+ };
+
+ enum FrameType {
+ EDDYSTONE_FRAME_URL,
+ EDDYSTONE_FRAME_UID,
+ EDDYSTONE_FRAME_TLM,
+ NUM_EDDYSTONE_FRAMES
+ };
+
+ /* Initialise the EddystoneService using parameters from persistent storage */
+ EddystoneService(BLE &bleIn,
+ EddystoneParams_t ¶msIn,
+ const PowerLevels_t &advPowerLevelsIn,
+ const PowerLevels_t &radioPowerLevelsIn,
+ uint32_t advConfigIntervalIn = DEFAULT_CONFIG_PERIOD_MSEC);
+
+ /* When using this constructor we need to call setURLData,
+ * setTMLData and setUIDData to initialise values manually
+ */
+ EddystoneService(BLE &bleIn,
+ const PowerLevels_t &advPowerLevelsIn,
+ const PowerLevels_t &radioPowerLevelsIn,
+ uint32_t advConfigIntervalIn = DEFAULT_CONFIG_PERIOD_MSEC);
+
+ /* Setup callback to update BatteryVoltage in TLM frame */
+ void onTLMBatteryVoltageUpdate(TlmUpdateCallback_t tlmBatteryVoltageCallbackIn);
+
+ /* Setup callback to update BeaconTemperature in TLM frame */
+ void onTLMBeaconTemperatureUpdate(TlmUpdateCallback_t tlmBeaconTemperatureCallbackIn);
+
+ void setTLMData(uint8_t tlmVersionIn = 0);
+
+ void setURLData(const char *urlDataIn);
+
+ void setUIDData(const UIDNamespaceID_t *uidNamespaceIDIn, const UIDInstanceID_t *uidInstanceIDIn);
+
+ EddystoneError_t startConfigService(void);
+
+ EddystoneError_t startBeaconService(uint16_t consecUrlFramesIn = 2, uint16_t consecUidFramesIn = 2, uint16_t consecTlmFramesIn = 2);
+
+ /* It is not the responsibility of the Eddystone implementation to store
+ * the configured parameters in persistent storage since this is
+ * platform-specific. So we provide this function that returns the
+ * configured values that need to be stored and the main application
+ * takes care of storing them.
+ */
+ void getEddystoneParams(EddystoneParams_t *params);
+
+private:
+ /* Helper function used only once during constructing the object to avoid
+ * duplicated code.
+ */
+ void eddystoneConstructorHelper(const PowerLevels_t &advPowerLevelsIn,
+ const PowerLevels_t &radioPowerLevelsIn,
+ uint32_t advConfigIntervalIn);
+
+ /* When changing modes, we shutdown and init the BLE instance, so
+ * this is needed to complete the initialisation task.
+ */
+ void bleInitComplete(BLE::InitializationCompleteCallbackContext* initContext);
+
+ void swapAdvertisedFrame(void);
+
+ void updateAdvertisementPacket(const uint8_t* rawFrame, size_t rawFrameLength);
+
+ /* Helper function that calls user-defined functions to update Battery Voltage and Temperature (if available),
+ * then updates the raw frame data and finally updates the actual advertised packet. This operation must be
+ * done fairly often because the TLM frame TimeSinceBoot must have a 0.1 secs resolution according to the
+ * Eddystone specification.
+ */
+ void updateRawTLMFrame(void);
+
+ void setupBeaconService(void);
+
+ void setupConfigService(void);
+
+ void freeConfigCharacteristics(void);
+
+ void freeBeaconFrames(void);
+
+ void radioNotificationCallback(bool radioActive);
+
+ /*
+ * Internal helper function used to update the GATT database following any
+ * change to the internal state of the service object.
+ */
+ void updateCharacteristicValues(void);
+
+ void setupEddystoneConfigAdvertisements(void);
+
+ void lockAuthorizationCallback(GattWriteAuthCallbackParams *authParams);
+
+ void unlockAuthorizationCallback(GattWriteAuthCallbackParams *authParams);
+
+ void urlDataWriteAuthorizationCallback(GattWriteAuthCallbackParams *authParams);
+
+ void powerModeAuthorizationCallback(GattWriteAuthCallbackParams *authParams);
+
+ template <typename T>
+ void basicAuthorizationCallback(GattWriteAuthCallbackParams *authParams);
+
+ /*
+ * This callback is invoked when a GATT client attempts to modify any of the
+ * characteristics of this service. Attempts to do so are also applied to
+ * the internal state of this service object.
+ */
+ void onDataWrittenCallback(const GattWriteCallbackParams *writeParams);
+
+ uint16_t correctAdvertisementPeriod(uint16_t beaconPeriodIn) const;
+
+ BLE &ble;
+ uint32_t advConfigInterval;
+ uint8_t operationMode;
+
+ URLFrame urlFrame;
+ UIDFrame uidFrame;
+ TLMFrame tlmFrame;
+
+ PowerLevels_t radioPowerLevels;
+ PowerLevels_t advPowerLevels;
+ bool lockState;
+ bool resetFlag;
+ Lock_t lock;
+ Lock_t unlock;
+ uint8_t flags;
+ uint8_t txPowerMode;
+ uint16_t beaconPeriod;
+
+ ReadOnlyGattCharacteristic<bool> *lockStateChar;
+ WriteOnlyArrayGattCharacteristic<uint8_t, sizeof(Lock_t)> *lockChar;
+ WriteOnlyArrayGattCharacteristic<uint8_t, sizeof(Lock_t)> *unlockChar;
+ GattCharacteristic *urlDataChar;
+ ReadWriteGattCharacteristic<uint8_t> *flagsChar;
+ ReadWriteArrayGattCharacteristic<int8_t, sizeof(PowerLevels_t)> *advPowerLevelsChar;
+ ReadWriteGattCharacteristic<uint8_t> *txPowerModeChar;
+ ReadWriteGattCharacteristic<uint16_t> *beaconPeriodChar;
+ WriteOnlyGattCharacteristic<bool> *resetChar;
+
+ uint8_t *rawUrlFrame;
+ uint8_t *rawUidFrame;
+ uint8_t *rawTlmFrame;
+
+ uint16_t consecFrames[NUM_EDDYSTONE_FRAMES];
+ uint16_t currentConsecFrames[NUM_EDDYSTONE_FRAMES];
+ uint8_t currentAdvertisedFrame;
+
+ TlmUpdateCallback_t tlmBatteryVoltageCallback;
+ TlmUpdateCallback_t tlmBeaconTemperatureCallback;
+
+ Timer timeSinceBootTimer;
+#ifndef YOTTA_CFG_MBED_OS
+ Timeout swapAdvertisedFrameTimeout;
+#endif
+
+ GattCharacteristic *charTable[TOTAL_CHARACTERISTICS];
+};
+
+#endif /* __EDDYSTONESERVICE_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/2_EddyStoneBeacon/Eddystone/EddystoneTypes.h Sat Apr 14 04:56:34 2018 +0000
@@ -0,0 +1,72 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2015 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.
+ */
+
+#ifndef __EDDYSTONETYPES_H__
+#define __EDDYSTONETYPES_H__
+
+#include <stdint.h>
+#include <stddef.h>
+
+#define UUID_URL_BEACON(FIRST, SECOND) { \
+ 0xee, 0x0c, FIRST, SECOND, 0x87, 0x86, 0x40, 0xba, \
+ 0xab, 0x96, 0x99, 0xb9, 0x1a, 0xc9, 0x81, 0xd8, \
+}
+
+const uint8_t EDDYSTONE_UUID[] = {0xAA, 0xFE};
+
+const uint8_t UUID_URL_BEACON_SERVICE[] = UUID_URL_BEACON(0x20, 0x80);
+const uint8_t UUID_LOCK_STATE_CHAR[] = UUID_URL_BEACON(0x20, 0x81);
+const uint8_t UUID_LOCK_CHAR[] = UUID_URL_BEACON(0x20, 0x82);
+const uint8_t UUID_UNLOCK_CHAR[] = UUID_URL_BEACON(0x20, 0x83);
+const uint8_t UUID_URL_DATA_CHAR[] = UUID_URL_BEACON(0x20, 0x84);
+const uint8_t UUID_FLAGS_CHAR[] = UUID_URL_BEACON(0x20, 0x85);
+const uint8_t UUID_ADV_POWER_LEVELS_CHAR[] = UUID_URL_BEACON(0x20, 0x86);
+const uint8_t UUID_TX_POWER_MODE_CHAR[] = UUID_URL_BEACON(0x20, 0x87);
+const uint8_t UUID_BEACON_PERIOD_CHAR[] = UUID_URL_BEACON(0x20, 0x88);
+const uint8_t UUID_RESET_CHAR[] = UUID_URL_BEACON(0x20, 0x89);
+
+const char DEVICE_NAME[] = "EDDYSTONE CONFIG";
+
+const char DEFAULT_URL[] = "http://www.mbed.com/";
+
+enum PowerModes {
+ TX_POWER_MODE_LOWEST,
+ TX_POWER_MODE_LOW,
+ TX_POWER_MODE_MEDIUM,
+ TX_POWER_MODE_HIGH,
+ NUM_POWER_MODES
+};
+
+/* 128 bits of lock */
+typedef uint8_t Lock_t[16];
+typedef int8_t PowerLevels_t[NUM_POWER_MODES];
+
+const uint16_t URL_DATA_MAX = 18;
+typedef uint8_t UrlData_t[URL_DATA_MAX];
+
+/* UID Frame Type subfields */
+const size_t UID_NAMESPACEID_SIZE = 10;
+typedef uint8_t UIDNamespaceID_t[UID_NAMESPACEID_SIZE];
+const size_t UID_INSTANCEID_SIZE = 6;
+typedef uint8_t UIDInstanceID_t[UID_INSTANCEID_SIZE];
+
+/* Callbacks for updating BateryVoltage and Temperature */
+typedef uint16_t (*TlmUpdateCallback_t) (uint16_t);
+
+/* Size of Eddystone UUID needed for all frames */
+const uint16_t EDDYSTONE_UUID_SIZE = sizeof(EDDYSTONE_UUID);
+
+#endif /* __EDDYSTONETYPES_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/2_EddyStoneBeacon/Eddystone/TLMFrame.cpp Sat Apr 14 04:56:34 2018 +0000
@@ -0,0 +1,105 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2015 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 "TLMFrame.h"
+
+TLMFrame::TLMFrame(uint8_t tlmVersionIn,
+ uint16_t tlmBatteryVoltageIn,
+ uint16_t tlmBeaconTemperatureIn,
+ uint32_t tlmPduCountIn,
+ uint32_t tlmTimeSinceBootIn) :
+ tlmVersion(tlmVersionIn),
+ lastTimeSinceBootRead(0),
+ tlmBatteryVoltage(tlmBatteryVoltageIn),
+ tlmBeaconTemperature(tlmBeaconTemperatureIn),
+ tlmPduCount(tlmPduCountIn),
+ tlmTimeSinceBoot(tlmTimeSinceBootIn)
+{
+}
+
+void TLMFrame::setTLMData(uint8_t tlmVersionIn)
+{
+ /* According to the Eddystone spec BatteryVoltage is 0 and
+ * BeaconTemperature is 0x8000 if not supported
+ */
+ tlmVersion = tlmVersionIn;
+ tlmBatteryVoltage = 0;
+ tlmBeaconTemperature = 0x8000;
+ tlmPduCount = 0;
+ tlmTimeSinceBoot = 0;
+}
+
+void TLMFrame::constructTLMFrame(uint8_t *rawFrame)
+{
+ size_t index = 0;
+ rawFrame[index++] = EDDYSTONE_UUID[0]; // 16-bit Eddystone UUID
+ rawFrame[index++] = EDDYSTONE_UUID[1];
+ rawFrame[index++] = FRAME_TYPE_TLM; // Eddystone frame type = Telemetry
+ rawFrame[index++] = tlmVersion; // TLM Version Number
+ rawFrame[index++] = (uint8_t)(tlmBatteryVoltage >> 8); // Battery Voltage[0]
+ rawFrame[index++] = (uint8_t)(tlmBatteryVoltage >> 0); // Battery Voltage[1]
+ rawFrame[index++] = (uint8_t)(tlmBeaconTemperature >> 8); // Beacon Temp[0]
+ rawFrame[index++] = (uint8_t)(tlmBeaconTemperature >> 0); // Beacon Temp[1]
+ rawFrame[index++] = (uint8_t)(tlmPduCount >> 24); // PDU Count [0]
+ rawFrame[index++] = (uint8_t)(tlmPduCount >> 16); // PDU Count [1]
+ rawFrame[index++] = (uint8_t)(tlmPduCount >> 8); // PDU Count [2]
+ rawFrame[index++] = (uint8_t)(tlmPduCount >> 0); // PDU Count [3]
+ rawFrame[index++] = (uint8_t)(tlmTimeSinceBoot >> 24); // Time Since Boot [0]
+ rawFrame[index++] = (uint8_t)(tlmTimeSinceBoot >> 16); // Time Since Boot [1]
+ rawFrame[index++] = (uint8_t)(tlmTimeSinceBoot >> 8); // Time Since Boot [2]
+ rawFrame[index++] = (uint8_t)(tlmTimeSinceBoot >> 0); // Time Since Boot [3]
+}
+
+size_t TLMFrame::getRawFrameSize(void) const
+{
+ return FRAME_SIZE_TLM + EDDYSTONE_UUID_SIZE;
+}
+
+void TLMFrame::updateTimeSinceBoot(uint32_t nowInMillis)
+{
+ tlmTimeSinceBoot += (nowInMillis - lastTimeSinceBootRead) / 100;
+ lastTimeSinceBootRead = nowInMillis;
+}
+
+void TLMFrame::updateBatteryVoltage(uint16_t tlmBatteryVoltageIn)
+{
+ tlmBatteryVoltage = tlmBatteryVoltageIn;
+}
+
+void TLMFrame::updateBeaconTemperature(uint16_t tlmBeaconTemperatureIn)
+{
+ tlmBeaconTemperature = tlmBeaconTemperatureIn;
+}
+
+void TLMFrame::updatePduCount(void)
+{
+ tlmPduCount++;
+}
+
+uint16_t TLMFrame::getBatteryVoltage(void) const
+{
+ return tlmBatteryVoltage;
+}
+
+uint16_t TLMFrame::getBeaconTemperature(void) const
+{
+ return tlmBeaconTemperature;
+}
+
+uint8_t TLMFrame::getTLMVersion(void) const
+{
+ return tlmVersion;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/2_EddyStoneBeacon/Eddystone/TLMFrame.h Sat Apr 14 04:56:34 2018 +0000
@@ -0,0 +1,63 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2015 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.
+ */
+
+#ifndef __TLMFRAME_H__
+#define __TLMFRAME_H__
+
+#include "EddystoneTypes.h"
+
+class TLMFrame
+{
+public:
+ TLMFrame(uint8_t tlmVersionIn = 0,
+ uint16_t tlmBatteryVoltageIn = 0,
+ uint16_t tlmBeaconTemperatureIn = 0x8000,
+ uint32_t tlmPduCountIn = 0,
+ uint32_t tlmTimeSinceBootIn = 0);
+
+ void setTLMData(uint8_t tlmVersionIn = 0);
+
+ void constructTLMFrame(uint8_t *rawFrame);
+
+ size_t getRawFrameSize(void) const;
+
+ void updateTimeSinceBoot(uint32_t nowInMillis);
+
+ void updateBatteryVoltage(uint16_t tlmBatteryVoltageIn);
+
+ void updateBeaconTemperature(uint16_t tlmBeaconTemperatureIn);
+
+ void updatePduCount(void);
+
+ uint16_t getBatteryVoltage(void) const;
+
+ uint16_t getBeaconTemperature(void) const;
+
+ uint8_t getTLMVersion(void) const;
+
+private:
+ static const uint8_t FRAME_TYPE_TLM = 0x20;
+ static const uint8_t FRAME_SIZE_TLM = 14;
+
+ uint8_t tlmVersion;
+ uint32_t lastTimeSinceBootRead;
+ uint16_t tlmBatteryVoltage;
+ uint16_t tlmBeaconTemperature;
+ uint32_t tlmPduCount;
+ uint32_t tlmTimeSinceBoot;
+};
+
+#endif /* __TLMFRAME_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/2_EddyStoneBeacon/Eddystone/UIDFrame.cpp Sat Apr 14 04:56:34 2018 +0000
@@ -0,0 +1,67 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2015 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 "UIDFrame.h"
+
+UIDFrame::UIDFrame(void)
+{
+ memset(uidNamespaceID, 0, sizeof(UIDNamespaceID_t));
+ memset(uidInstanceID, 0, sizeof(UIDInstanceID_t));
+}
+
+UIDFrame::UIDFrame(const UIDNamespaceID_t uidNamespaceIDIn, const UIDInstanceID_t uidInstanceIDIn)
+{
+ memcpy(uidNamespaceID, uidNamespaceIDIn, sizeof(UIDNamespaceID_t));
+ memcpy(uidInstanceID, uidInstanceIDIn, sizeof(UIDInstanceID_t));
+}
+
+void UIDFrame::setUIDData(const UIDNamespaceID_t *uidNamespaceIDIn, const UIDInstanceID_t *uidInstanceIDIn)
+{
+ memcpy(uidNamespaceID, uidNamespaceIDIn, sizeof(UIDNamespaceID_t));
+ memcpy(uidInstanceID, uidInstanceIDIn, sizeof(UIDInstanceID_t));
+}
+
+void UIDFrame::constructUIDFrame(uint8_t *rawFrame, int8_t advPowerLevel)
+{
+ size_t index = 0;
+
+ rawFrame[index++] = EDDYSTONE_UUID[0]; // 16-bit Eddystone UUID
+ rawFrame[index++] = EDDYSTONE_UUID[1];
+ rawFrame[index++] = FRAME_TYPE_UID; // 1B Type
+ rawFrame[index++] = advPowerLevel; // 1B Power @ 0meter
+
+ memcpy(rawFrame + index, uidNamespaceID, sizeof(UIDNamespaceID_t)); // 10B Namespace ID
+ index += sizeof(UIDNamespaceID_t);
+ memcpy(rawFrame + index, uidInstanceID, sizeof(UIDInstanceID_t)); // 6B Instance ID
+ index += sizeof(UIDInstanceID_t);
+
+ memset(rawFrame + index, 0, 2 * sizeof(uint8_t)); // 2B RFU, which are unused
+}
+
+size_t UIDFrame::getRawFrameSize(void) const
+{
+ return FRAME_SIZE_UID + EDDYSTONE_UUID_SIZE;
+}
+
+uint8_t* UIDFrame::getUIDNamespaceID(void)
+{
+ return uidNamespaceID;
+}
+
+uint8_t* UIDFrame::getUIDInstanceID(void)
+{
+ return uidInstanceID;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/2_EddyStoneBeacon/Eddystone/UIDFrame.h Sat Apr 14 04:56:34 2018 +0000
@@ -0,0 +1,48 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2015 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.
+ */
+
+#ifndef __UIDFRAME_H__
+#define __UIDFRAME_H__
+
+#include <string.h>
+#include "EddystoneTypes.h"
+
+class UIDFrame
+{
+public:
+ UIDFrame(void);
+
+ UIDFrame(const UIDNamespaceID_t uidNamespaceIDIn, const UIDInstanceID_t uidInstanceIDIn);
+
+ void setUIDData(const UIDNamespaceID_t *uidNamespaceIDIn, const UIDInstanceID_t *uidInstanceIDIn);
+
+ void constructUIDFrame(uint8_t *rawFrame, int8_t advPowerLevel);
+
+ size_t getRawFrameSize(void) const;
+
+ uint8_t* getUIDNamespaceID(void);
+
+ uint8_t* getUIDInstanceID(void);
+
+private:
+ static const uint8_t FRAME_TYPE_UID = 0x00;
+ static const uint8_t FRAME_SIZE_UID = 20;
+
+ UIDNamespaceID_t uidNamespaceID;
+ UIDInstanceID_t uidInstanceID;
+};
+
+#endif /* __UIDFRAME_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/2_EddyStoneBeacon/Eddystone/URLFrame.cpp Sat Apr 14 04:56:34 2018 +0000
@@ -0,0 +1,141 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2015 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 "URLFrame.h"
+
+URLFrame::URLFrame(void)
+{
+ urlDataLength = 0;
+ memset(urlData, 0, sizeof(UrlData_t));
+}
+
+URLFrame::URLFrame(const char *urlDataIn)
+{
+ encodeURL(urlDataIn);
+}
+
+URLFrame::URLFrame(UrlData_t urlDataIn, uint8_t urlDataLength)
+{
+ if (urlDataLength > URL_DATA_MAX) {
+ memcpy(urlData, urlDataIn, URL_DATA_MAX);
+ } else {
+ memcpy(urlData, urlDataIn, urlDataLength);
+ }
+}
+
+void URLFrame::constructURLFrame(uint8_t* rawFrame, int8_t advPowerLevel)
+{
+ size_t index = 0;
+ rawFrame[index++] = EDDYSTONE_UUID[0]; // 16-bit Eddystone UUID
+ rawFrame[index++] = EDDYSTONE_UUID[1];
+ rawFrame[index++] = FRAME_TYPE_URL; // 1B Type
+ rawFrame[index++] = advPowerLevel; // 1B Power @ 0meter
+ memcpy(rawFrame + index, urlData, urlDataLength); // Encoded URL
+}
+
+size_t URLFrame::getRawFrameSize(void) const
+{
+ return urlDataLength + FRAME_MIN_SIZE_URL + EDDYSTONE_UUID_SIZE;
+}
+
+uint8_t* URLFrame::getEncodedURLData(void)
+{
+ return urlData;
+}
+
+uint8_t URLFrame::getEncodedURLDataLength(void) const
+{
+ return urlDataLength;
+}
+
+void URLFrame::setURLData(const char *urlDataIn)
+{
+ encodeURL(urlDataIn);
+}
+
+void URLFrame::setEncodedURLData(const uint8_t* urlEncodedDataIn, const uint8_t urlEncodedDataLengthIn)
+{
+ urlDataLength = urlEncodedDataLengthIn;
+ memcpy(urlData, urlEncodedDataIn, urlEncodedDataLengthIn);
+}
+
+void URLFrame::encodeURL(const char *urlDataIn)
+{
+ const char *prefixes[] = {
+ "http://www.",
+ "https://www.",
+ "http://",
+ "https://",
+ };
+ const size_t NUM_PREFIXES = sizeof(prefixes) / sizeof(char *);
+ const char *suffixes[] = {
+ ".com/",
+ ".org/",
+ ".edu/",
+ ".net/",
+ ".info/",
+ ".biz/",
+ ".gov/",
+ ".com",
+ ".org",
+ ".edu",
+ ".net",
+ ".info",
+ ".biz",
+ ".gov"
+ };
+ const size_t NUM_SUFFIXES = sizeof(suffixes) / sizeof(char *);
+
+ urlDataLength = 0;
+ memset(urlData, 0, sizeof(UrlData_t));
+
+ if ((urlDataIn == NULL) || (strlen(urlDataIn) == 0)) {
+ return;
+ }
+
+ /*
+ * handle prefix
+ */
+ for (size_t i = 0; i < NUM_PREFIXES; i++) {
+ size_t prefixLen = strlen(prefixes[i]);
+ if (strncmp(urlDataIn, prefixes[i], prefixLen) == 0) {
+ urlData[urlDataLength++] = i;
+ urlDataIn += prefixLen;
+ break;
+ }
+ }
+
+ /*
+ * handle suffixes
+ */
+ while (*urlDataIn && (urlDataLength < URL_DATA_MAX)) {
+ /* check for suffix match */
+ size_t i;
+ for (i = 0; i < NUM_SUFFIXES; i++) {
+ size_t suffixLen = strlen(suffixes[i]);
+ if (strncmp(urlDataIn, suffixes[i], suffixLen) == 0) {
+ urlData[urlDataLength++] = i;
+ urlDataIn += suffixLen;
+ break; /* from the for loop for checking against suffixes */
+ }
+ }
+ /* This is the default case where we've got an ordinary character which doesn't match a suffix. */
+ if (i == NUM_SUFFIXES) {
+ urlData[urlDataLength++] = *urlDataIn;
+ ++urlDataIn;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/2_EddyStoneBeacon/Eddystone/URLFrame.h Sat Apr 14 04:56:34 2018 +0000
@@ -0,0 +1,56 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2015 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.
+ */
+
+#ifndef __URLFRAME_H__
+#define __URLFRAME_H__
+
+#include "EddystoneTypes.h"
+#include <string.h>
+
+class URLFrame
+{
+public:
+ URLFrame(void);
+
+ URLFrame(const char *urlDataIn);
+
+ URLFrame(UrlData_t urlDataIn, uint8_t urlDataLength);
+
+ void constructURLFrame(uint8_t* rawFrame, int8_t advPowerLevel);
+
+ size_t getRawFrameSize(void) const;
+
+ uint8_t* getEncodedURLData(void);
+
+ uint8_t getEncodedURLDataLength(void) const;
+
+ void setURLData(const char *urlDataIn);
+
+ void setEncodedURLData(const uint8_t* urlEncodedDataIn, const uint8_t urlEncodedDataLengthIn);
+
+private:
+ void encodeURL(const char *urlDataIn);
+
+ static const uint8_t FRAME_TYPE_URL = 0x10;
+ /* Even if the URL is 0 bytes we still need to include the type and txPower i.e. 2 bytes */
+ static const uint8_t FRAME_MIN_SIZE_URL = 2;
+
+ uint8_t urlDataLength;
+ UrlData_t urlData;
+
+};
+
+#endif /* __URLFRAME_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/2_EddyStoneBeacon/main.cpp Sat Apr 14 04:56:34 2018 +0000
@@ -0,0 +1,165 @@
+/* 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.
+ */
+
+/*
+ * /////// Works well on TYBLE16 Module ///////
+ * Modified by Kenji Arai
+ * http://www.page.sannet.ne.jp/kenjia/index.html
+ * https://os.mbed.com/users/kenjiArai/
+ *
+ * Started: Feburary 18th, 2018
+ * Revised: April 14th, 2018
+ *
+ * Original:
+ * nRF51822_SimpleControls
+ * https://developer.mbed.org/teams
+ * /Bluetooth-Low-Energy/code/BLE_EddystoneBeacon_Service/
+ * Tested Controller Device:
+ * iPhone6 Physical Web (PhyWeb) By Viet Hoa Dinh
+ * https://itunes.apple.com/us/app/physical-web/id927653608?mt=8
+ */
+
+//#define EXAMPLE_2_EDDYSTONE_BEACON
+#ifdef EXAMPLE_2_EDDYSTONE_BEACON
+
+// Include --------------------------------------------------------------------
+#include "mbed.h"
+#include "TYBLE16_BASE.h"
+#include "BLE.h"
+//#include "EddystoneService.h"
+#include "../Eddystone/EddystoneService.h"
+
+// Object ---------------------------------------------------------------------
+DigitalOut led(P0_5);
+Serial pc(USBTX, USBRX);
+
+// Definition -----------------------------------------------------------------
+
+// RAM ------------------------------------------------------------------------
+EddystoneService *eddyServicePtr;
+Gap::Address_t my_mac;
+
+// ROM / Constant data --------------------------------------------------------
+char *const opngmsg =
+ "\x1b[2J\x1b[H"__FILE__ "\r\n"__DATE__ " " __TIME__ " (UTC)\r\n""\r\n";
+
+// Function prototypes --------------------------------------------------------
+int8_t check_dice(void);
+uint16_t update_vdd(uint16_t x);
+uint16_t update_temp(uint16_t x);
+void onBleInitError(BLE::InitializationCompleteCallbackContext* initContext);
+void bleInitComplete(BLE::InitializationCompleteCallbackContext* initContext);
+
+//------------------------------------------------------------------------------
+// Control Program
+//------------------------------------------------------------------------------
+// !!!!!!!! Please select number of 0 to 6 !!!!!!!!!!!!!!!!!
+int8_t check_dice(void)
+{
+ return 5;
+}
+
+void bleInitComplete(BLE::InitializationCompleteCallbackContext* initContext)
+{
+ BLE &ble = initContext->ble;
+ ble_error_t error = initContext->error;
+
+ if (error != BLE_ERROR_NONE) {
+ onBleInitError(initContext);
+ return;
+ }
+ // Set UID and TLM frame data
+ const UIDNamespaceID_t uidNamespaceID =
+ {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99};
+ const UIDInstanceID_t uidInstanceID =
+ {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};
+ uint8_t tlmVersion = 0x00;
+
+ Gap::AddressType_t my_mac_type;
+ ble.gap().getAddress(&my_mac_type, my_mac);
+ // Initialize a EddystoneBeaconConfig service
+ // Values for ADV packets related to firmware levels,
+ // calibrated based on measured values at 1m
+ static const PowerLevels_t defaultAdvPowerLevels = {-47, -33, -21, -13};
+ // Values for radio power levels, provided by manufacturer.
+ static const PowerLevels_t radioPowerLevels = {-30, -16, -4, 4};
+ eddyServicePtr = new EddystoneService(ble,
+ defaultAdvPowerLevels,
+ radioPowerLevels);
+ // created short cut web addres by http://bitly.oshiire.org/
+ switch (check_dice()) {
+ case 1: // Switch sience(mbed)
+ eddyServicePtr->setURLData("http://bit.ly/1oJh91B");
+ break;
+ case 2: // switch sience(HP)
+ eddyServicePtr->setURLData("http://bit.ly/1oJhP7g");
+ break;
+ case 3: // Taiyo Yuden BLE
+ eddyServicePtr->setURLData("http://bit.ly/1VvuCVr");
+ break;
+ case 4: // Taiyo Yuden
+ eddyServicePtr->setURLData("http://bit.ly/1Vvtp0l");
+ break;
+ case 5: // JH1PJL(mbed)
+ eddyServicePtr->setURLData("http://bit.ly/1Vvt51J");
+ break;
+ case 6: // JH1PJL(HP)
+ eddyServicePtr->setURLData("http://bit.ly/1VvteT0");
+ break;
+ case 0:
+ default: // Mbed
+ eddyServicePtr->setURLData("http://mbed.org");
+ break;
+ }
+ eddyServicePtr->setUIDData(&uidNamespaceID, &uidInstanceID);
+ eddyServicePtr->setTLMData(tlmVersion);
+ // Start Eddystone in config mode
+ eddyServicePtr->startBeaconService(5, 5, 5);
+}
+
+int main(void)
+{
+ pc.puts(opngmsg);
+ led = 1;
+ // Check TYBLE-16 configuration
+ cpu_sys();
+ if (compile_condition() == false) {
+ pc.printf("This is wrong configuration!!\r\n");
+ while(true) {
+ led = !led;
+ wait(0.2);
+ }
+ }
+ BLE& ble = BLE::Instance(BLE::DEFAULT_INSTANCE);
+ ble.init(bleInitComplete);
+ while (ble.hasInitialized() == false) {
+ ;
+ }
+ //
+ led = 0;
+ //pc.printf("line:%d\r\n", __LINE__);
+ while (true) {
+ ble.waitForEvent();
+ }
+}
+
+void onBleInitError(BLE::InitializationCompleteCallbackContext* initContext)
+{
+ // Initialization error handling goes here...
+ (void) initContext;
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/3_Heart_Rate/main.cpp Sat Apr 14 04:56:34 2018 +0000
@@ -0,0 +1,162 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2015 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.
+ */
+/*
+ Modified by Kenji Arai, April 14th, 2018
+ https://os.mbed.com/users/kenjiArai/
+ */
+
+//#define EXAMPLE_3_HEART_RATE
+#ifdef EXAMPLE_3_HEART_RATE
+
+#include "mbed.h"
+#include "events/mbed_events.h"
+#include "ble/BLE.h"
+#include "ble/Gap.h"
+#include "ble/services/HeartRateService.h"
+#include "ble/services/BatteryService.h"
+#include "ble/services/DeviceInformationService.h"
+#include "TYBLE16_BASE.h"
+
+DigitalOut led1(LED1, 1);
+Serial pc(USBTX, USBRX);
+
+const static char DEVICE_NAME[] = "TYBLE16";
+char *const opngmsg =
+ "\x1b[2J\x1b[H"__FILE__ "\r\n"__DATE__ " " __TIME__ " (UTC)\r\n""\r\n";
+
+static const uint16_t uuid16_list[] = {
+ GattService::UUID_HEART_RATE_SERVICE,
+ GattService::UUID_DEVICE_INFORMATION_SERVICE
+};
+
+static volatile bool triggerSensorPolling = false;
+
+uint8_t hrmCounter = 100; // init HRM to 100bps
+
+HeartRateService *hrService;
+DeviceInformationService *deviceInfo;
+
+void disconnectionCallback(
+ const Gap::DisconnectionCallbackParams_t *params
+)
+{
+ // restart advertising
+ BLE::Instance(BLE::DEFAULT_INSTANCE).gap().startAdvertising();
+}
+
+void periodicCallback(void)
+{
+ led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */
+
+ /* Note that the periodicCallback() executes in interrupt context,
+ * so it is safer to do
+ * heavy-weight sensor polling from the main thread. */
+ triggerSensorPolling = true;
+}
+
+void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
+{
+ BLE &ble = params->ble;
+ ble_error_t error = params->error;
+
+ if (error != BLE_ERROR_NONE) {
+ return;
+ }
+
+ ble.gap().onDisconnection(disconnectionCallback);
+
+ /* Setup primary service. */
+ hrService = new HeartRateService(
+ ble,
+ hrmCounter,
+ HeartRateService::LOCATION_FINGER
+ );
+
+ /* Setup auxiliary service. */
+ deviceInfo = new DeviceInformationService(
+ ble,
+ "ARM",
+ "Model1",
+ "SN1",
+ "hw-rev1",
+ "fw-rev1",
+ "soft-rev1"
+ );
+
+ /* 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::GENERIC_HEART_RATE_SENSOR
+ );
+ 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();
+}
+
+int main(void)
+{
+ pc.puts(opngmsg);
+ led1 = 1;
+ Ticker ticker;
+ ticker.attach(periodicCallback, 1); // blink LED every second
+
+ // Check TYBLE-16 configuration
+ cpu_sys();
+ compile_condition();
+ //
+ BLE& ble = BLE::Instance(BLE::DEFAULT_INSTANCE);
+ ble.init(bleInitComplete);
+
+ /* SpinWait for initialization to complete. This is necessary
+ * because the BLE object is used in the main loop below. */
+ while (ble.hasInitialized() == false) {
+ /* spin loop */
+ }
+
+ // infinite loop
+ while (true) {
+ // check for trigger from periodicCallback()
+ if (triggerSensorPolling && ble.getGapState().connected) {
+ triggerSensorPolling = false;
+
+ // Do blocking calls or whatever is necessary for sensor polling.
+ // In our case, we simply update the HRM measurement.
+ hrmCounter++;
+ if (hrmCounter == 175) { // 100 <= HRM bps <=175
+ hrmCounter = 100;
+ }
+
+ hrService->updateHeartRate(hrmCounter);
+ } else {
+ ble.waitForEvent(); // low power wait for event
+ }
+ }
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/4_RCBController/RCBController.h Sat Apr 14 04:56:34 2018 +0000
@@ -0,0 +1,74 @@
+/*
+ * Modifed by Kenji Arai on December 31st, 2015
+ */
+
+typedef union {
+ struct {
+ /*
+ 1st and 2nd byte: buttom
+ UP: 0x0001
+ DOWN: 0x0002
+ RIGHT: 0x0004
+ LEFT: 0x0008
+ Y button: 0x0010
+ A button: 0x0020
+ B button: 0x0040
+ X button: 0x0100
+ L1: 0x0200
+ L2: 0x0400
+ R1: 0x0800
+ R2: 0x1000
+ START: 0x0003
+ SELECT: 0x000C
+ */
+ unsigned X : 1;
+ unsigned L1 : 1;
+ unsigned L2 : 1;
+ unsigned R1 : 1;
+ unsigned R2 : 1;
+ unsigned space1 : 3;
+ unsigned UP : 1;
+ unsigned DOWN : 1;
+ unsigned RIGHT : 1;
+ unsigned LEFT : 1;
+ unsigned Y : 1;
+ unsigned A : 1;
+ unsigned B : 1;
+ unsigned space2 : 1;
+ /*
+ 3rd and 4th byte: Analog value (left side)
+ Left to Right: 1-255 (Neutral=128)
+ Down to UP : 1-255 (Neutral=128)
+ */
+ unsigned LeftAnalogLR:8;
+ unsigned LeftAnalogUD:8;
+ /*
+ 5th to 6th byte: Analog value (Right side)
+ Left to Right: 1-255 (Neutral=128)
+ Down to UP : 1-255 (Neutral=128)
+ */
+ unsigned RightAnalogLR:8;
+ unsigned RightAnalogUD:8;
+ /*
+ 7th to 9th byte: Accel
+ X-axis: 1-255 (Neutral=128)
+ Y-axis: 1-255 (Neutral=128)
+ Z-axis: 1-255 (Neutral=128)
+ */
+ unsigned AcceleX:8;
+ unsigned AcceleY:8;
+ unsigned AcceleZ:8;
+ /*
+ 10th byte : Setting parameter
+ 7th and 6th bit: setting accel (0-3)
+ 5th bit : Analog-Left (0 or 1)
+ 4th bit : Analog-Right (0 or 1)
+ 3th to 1st bit : iOS device direction (1-4)
+ */
+ unsigned DEV_DIR:4;
+ unsigned RIGHT_ANALOG:1;
+ unsigned LEFT_ANALOG:1;
+ unsigned ACCELE_SETTING:2;
+ } status;
+ unsigned char data[10];
+} RCBController;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/4_RCBController/main.cpp Sat Apr 14 04:56:34 2018 +0000
@@ -0,0 +1,162 @@
+/*
+ * December 31st, 2015 Modified by Kenji Arai
+ * January 19th, 2016
+ * October 12th, 2017 !! Run on Mbed-os5
+ * http://www.page.sannet.ne.jp/kenjia/index.html
+ * https://os.mbed.com/users/kenjiArai/
+ * April 14th, 2018 run on TYBLE16
+ *
+ * Original:
+ * BLE_RCBController2_Motor
+ * https://developer.mbed.org/users/robo8080/code/BLE_RCBController2_Motor/
+ * Tested Controller Device:
+ * iPhone6 RCBController (Ver1.4.0)
+ * https://itunes.apple.com/jp/app/rcbcontroller/id689724127?mt=8
+ */
+
+//#define EXAMPLE_4_RCB_CONTROLLER
+#ifdef EXAMPLE_4_RCB_CONTROLLER
+
+#include "mbed.h"
+#include "BLE.h"
+#include "RCBController.h"
+#include "TYBLE16_BASE.h"
+
+#define NEED_CONSOLE_OUTPUT 1 // Keep 1
+
+#if NEED_CONSOLE_OUTPUT
+#define DEBUG(...) { pc.printf(__VA_ARGS__); }
+#else
+#define DEBUG(...)
+#endif
+
+BLE ble_rcb;
+Serial pc(USBTX, USBRX);
+
+uint8_t RCBControllerPayload[10] = {0,};
+RCBController controller;
+
+// RCBController Service
+static const uint16_t RCBController_service_uuid = 0xFFF0;
+static const uint16_t RCBController_Characteristic_uuid = 0xFFF1;
+const char *deviceName = "Mbed-BLE";
+char *const opngmsg =
+ "\x1b[2J\x1b[H"__FILE__ "\r\n"__DATE__ " " __TIME__ " (UTC)\r\n""\r\n";
+
+GattCharacteristic ControllerChar (
+ RCBController_Characteristic_uuid,RCBControllerPayload,10, 10,
+ GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE |
+ GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE
+);
+GattCharacteristic *ControllerChars[] = {&ControllerChar};
+GattService RCBControllerService(
+ RCBController_service_uuid,
+ ControllerChars,
+ sizeof(ControllerChars) / sizeof(GattCharacteristic *)
+);
+
+//------------------------------------------------------------------------------
+// Control Program
+//------------------------------------------------------------------------------
+void data_analysis(void)
+{
+ static uint8_t cont_flg_A = 0;
+ static uint8_t cont_flg_B = 0;
+ static uint8_t cont_flg_X = 0;
+ static uint8_t cont_flg_Y = 0;
+
+ if (controller.status.A == 1) {
+ if (cont_flg_A == 0) {
+ cont_flg_A = 1;
+ }
+ } else {
+ cont_flg_A = 0;
+ }
+ if (controller.status.B == 1) {
+ if (cont_flg_B == 0) {
+ cont_flg_B = 1;
+ }
+ } else {
+ cont_flg_B = 0;
+ }
+ if (controller.status.X == 1) {
+ if (cont_flg_X == 0) {
+ cont_flg_X = 1;
+ }
+ } else {
+ cont_flg_X = 0;
+ }
+ if (controller.status.Y == 1) {
+ if (cont_flg_Y == 0) {
+ cont_flg_Y = 1;
+ }
+ } else {
+ cont_flg_Y = 0;
+ }
+}
+
+void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
+{
+ DEBUG("Disconnected!\r\n");
+ DEBUG("Restarting the advertising process\r\n");
+ ble_rcb.startAdvertising();
+}
+
+void onDataWritten(const GattWriteCallbackParams *params)
+{
+ if (params->handle == ControllerChar.getValueAttribute().getHandle()) {
+ uint16_t bytesRead;
+ ble_rcb.readCharacteristicValue(
+ ControllerChar.getValueAttribute().getHandle(),
+ RCBControllerPayload, &bytesRead
+ );
+ memcpy( &controller.data[0], RCBControllerPayload, sizeof(controller));
+ DEBUG("DATA:0x%02x 0x%02x %d %d %d %d %d %d %d 0x%02x\r\n",
+ controller.data[0],controller.data[1],
+ controller.data[2],controller.data[3],
+ controller.data[4],controller.data[5],
+ controller.data[6],controller.data[7],
+ controller.data[8],controller.data[9]
+ );
+ data_analysis();
+ }
+}
+
+int main(void)
+{
+ DEBUG(opngmsg);
+ DEBUG("\r\nInitialising the nRF51822\r\n");
+ // Check TYBLE-16 configuration
+ cpu_sys();
+ compile_condition();
+
+ ble_rcb.init();
+ ble_rcb.setDeviceName((const uint8_t *)deviceName);
+ ble_rcb.onDisconnection(disconnectionCallback);
+ ble_rcb.onDataWritten(onDataWritten);
+ DEBUG("Start RCB Controller\r\n");
+ /* setup advertising */
+ ble_rcb.accumulateAdvertisingPayload(
+ GapAdvertisingData::BREDR_NOT_SUPPORTED
+ );
+ ble_rcb.setAdvertisingType(
+ GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED
+ );
+ ble_rcb.accumulateAdvertisingPayload(
+ GapAdvertisingData::SHORTENED_LOCAL_NAME,
+ (const uint8_t *)deviceName, strlen(deviceName)
+ );
+ ble_rcb.accumulateAdvertisingPayload(
+ GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS,
+ (const uint8_t *)RCBController_service_uuid,
+ sizeof(RCBController_service_uuid)
+ );
+ ble_rcb.setAdvertisingInterval(160); /* 100ms; in multiples of 0.625ms. */
+ ble_rcb.startAdvertising();
+ ble_rcb.addService(RCBControllerService);
+ while (true) {
+ ble_rcb.waitForEvent();
+ }
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/5_SDCard/FatFs_Mon/mon.cpp Sat Apr 14 04:56:34 2018 +0000
@@ -0,0 +1,1228 @@
+/*
+ * mbed Application program for the mbed
+ * FatFs Check program / monitor part
+ *
+ * Copyright (c) 2015,'18 Kenji Arai / JH1PJL
+ * http://www.page.sannet.ne.jp/kenjia/index.html
+ * https://os.mbed.com/users/kenjiArai/
+ * Created: May 5th, 2015
+ * Revised: June 14th, 2015
+ * Revised: April 7th, 2018
+ */
+
+/*
+ *---------------- REFERENCE ---------------------------------------------------
+ * Original Source Information
+ * FatFs sample program
+ * ChaN FatFs http://elm-chan.org/
+ * http://elm-chan.org/fsw/ff/00index_e.html
+ */
+/*----------------------------------------------------------------------*/
+/* FAT file system sample project for FatFs (C)ChaN, 2016 */
+/*----------------------------------------------------------------------*/
+
+// Include --------------------------------------------------------------------
+#include "mbed.h"
+#if (MBED_MAJOR_VERSION == 2)
+#include "SDFileSystem.h"
+#elif (MBED_MAJOR_VERSION == 5)
+#include "FATFileSystem.h"
+#endif
+#include "ff.h"
+#include "ffconf.h"
+#include "diskio.h"
+#include "mon.h"
+
+// Definition -----------------------------------------------------------------
+#define DO_DEBUG 0
+
+#if DO_DEBUG
+#define DEBUG_LINE pc.printf("line:%d\r\n", __LINE__);
+#else
+#define DEBUG_LINE {;}
+#endif
+
+// Com
+#if 1
+#define BAUD(x) pc.baud(x)
+#define GETC(x) pc.getc(x)
+#define PUTC(x) pc.putc(x)
+#define PUTS(x) pc.puts(x)
+#define PRINTF(...) pc.printf(__VA_ARGS__)
+#define READABLE(x) pc.readable(x)
+#else
+#define BAUD(x) {;}
+#define GETC(x) {;}
+#define PUTC(x) {;}
+#define PRINTF(...) {;}
+#define READABLE(x) {;}
+#endif
+
+#define UTC_JST_OFFSET (32400) // +9 hours
+
+// from ffconf.h
+#define _VOLUMES 1
+#define FF_USE_LFN 0
+
+#if !defined(FF_FS_RPATH)
+#define FF_FS_RPATH 0
+#endif
+
+#define DW_CHAR sizeof(char)
+#define DW_SHORT sizeof(short)
+#define DW_LONG sizeof(long)
+
+/* These types must be 16-bit, 32-bit or larger integer */
+typedef int INT;
+typedef unsigned int UINT;
+
+/* These types must be 8-bit integer */
+typedef char CHAR;
+typedef unsigned char UCHAR;
+typedef unsigned char BYTE;
+
+/* These types must be 16-bit integer */
+typedef short SHORT;
+typedef unsigned short USHORT;
+typedef unsigned short WORD;
+typedef unsigned short WCHAR;
+
+/* These types must be 32-bit integer */
+typedef long LONG;
+typedef unsigned long ULONG;
+typedef unsigned long DWORD;
+/* by Kenji Arai / JH1PJL September 10th, 2012 */
+typedef unsigned long long DDWORD;
+
+// RAM ------------------------------------------------------------------------
+BYTE Buff[4096];
+char Linebuf[128]; // Console input buffer
+FATFS Fatfs[_VOLUMES]; // File system object for each logical drive
+FIL File1, File2; // File objects
+FATFS_DIR* Dirx;
+FILINFO Finfo;
+#if FF_USE_LFN
+//inside of FILINFO
+char Lfname[512];
+#endif
+DWORD AccSize; // Work register for fs command
+WORD AccFiles, AccDirs;
+
+// ROM / Constant data --------------------------------------------------------
+char *const monmsg0 = "Start monitor program for FatFs File System\r\n";
+char *const monmsg1 = " <Please press any key to start the monitor>";
+
+static const char HelpMsg0[] =
+ "dir <full_pass>\r\n"
+ "type <file_name>\r\n"
+ "vol\r\n"
+ "ren <org_file_name> <new_file_name>\r\n"
+ "copy <file_name> <file_name>\r\n"
+ "mkdir <dir_name>\r\n"
+ "cd <dir_name>\r\n"
+ "x extend commands mode\r\n"
+ "q Return to main\r\n"
+ "t Show current time or Adjust time\r\n"
+ " e.g. t 18 3 28 14 48 20 -> 2018-03-28 14:48:20\r\n"
+ "? Help/You know the command\r\n"
+ "\r\n";
+
+static const char HelpMsg1[] =
+ "[File system controls]\r\n"
+ " fi <ld#> [<mount>]- Force initialized the volume\r\n"
+ " fs [<path>] - Show volume status\r\n"
+ " fl [<path>] - Show a directory\r\n"
+ " fo <mode> <file> - Open a file\r\n"
+ " <mode> Read=1, Write=2\r\n"
+ " fc - Close the file\r\n"
+ " fe <ofs> - Move fp in normal seek\r\n"
+ " fd <len> - Read and dump the file\r\n"
+ " fr <len> - Read the file\r\n"
+ " fw <len> <val> - Write to the file\r\n"
+ " fn <org.name> <new.name> - Rename an object\r\n"
+ " fu <name> - Unlink an object\r\n"
+ " fv - Truncate the file at current fp\r\n"
+ " fk <name> - Create a directory\r\n"
+ " fa <atrr> <mask> <object name> - Change attribute of an object\r\n"
+ " ft <year> <month> <day> <hour> <min> <sec> <name>"
+ " - Change timestamp of an object\r\n"
+ " fx <src.file> <dst.file> - Copy a file\r\n"
+ " fg <path> - Change current directory\r\n"
+ " fq - Show current directory\r\n"
+ " fb <name> - Set volume label\r\n"
+ " fm <ld#> <type> <csize> - Create file system\r\n"
+ " fz [<len>] - Change/Show R/W length for fr/fw/fx command\r\n"
+ "[Disk contorls]\r\n"
+ " di <pd#> - Initialize disk\r\n"
+ " dd [<pd#> <lba>] - Dump a secrtor\r\n"
+ " ds <pd#> - Show disk status\r\n"
+ "[Buffer controls]\r\n"
+ " bd <ofs> - Dump working buffer\r\n"
+ " be <ofs> [<data>] ... - Edit working buffer\r\n"
+ " br <pd#> <lba> [<count>] - Read disk into working buffer\r\n"
+ " bw <pd#> <lba> [<count>] - Write working buffer into disk\r\n"
+ " bf <val> - Fill working buffer\r\n"
+ "[Misc commands]\r\n"
+ " q Return\r\n"
+ " ? Help\r\n"
+ "\r\n";
+
+// Function prototypes --------------------------------------------------------
+#if (MBED_MAJOR_VERSION == 2)
+extern SDFileSystem fs;
+#elif (MBED_MAJOR_VERSION == 5)
+extern HeapBlockDevice bd;
+extern FATFileSystem fs;
+#endif
+
+static void extended_mon( char *ptr );
+static void v_next( char *ptr );
+static void d_next( char *ptr );
+static void c_next( char *ptr );
+static void m_next( char *ptr );
+static void r_next( char *ptr );
+static void t_next( char *ptr );
+static void memory_inf(char *ptr);
+static void disk_inf(char *ptr);
+
+static void crlf( void );
+static FRESULT scan_files( char* path );
+static void put_rc( FRESULT rc );
+static void file_inf( char *ptr );
+static void put_dump( void* buff, unsigned long addr, int len, int width );
+static void chk_and_set_time(char *ptr);
+static int xatoi ( char **str, long *res );
+
+void get_line (char *buff, int len);
+
+// Object ---------------------------------------------------------------------
+extern Serial pc;
+static Timer t;
+
+//------------------------------------------------------------------------------
+// Control Program
+//------------------------------------------------------------------------------
+// Monitor program for File control
+void mon ()
+{
+ char *ptr;
+
+ Dirx = new FATFS_DIR;
+ /* Open Uart to communicate with Host PC */
+ PUTS(monmsg0);
+ PUTS(monmsg1);
+ crlf();
+#if FF_USE_LFN
+ // no needs because FILINFO structure is changed
+ Finfo.lfname = Lfname;
+ Finfo.lfsize = sizeof Lfname;
+#endif
+ for (;;) {
+ DEBUG_LINE
+ PUTC('>');
+ ptr = Linebuf;
+ get_line( ptr, sizeof(Linebuf) );
+ switch ( *ptr++ ) {
+ // vol
+ case 'v' :
+ v_next(ptr);
+ break;
+ // dir
+ case 'd' :
+ d_next(ptr);
+ break;
+ // cd, copy
+ case 'c' :
+ c_next(ptr);
+ break;
+ // mkdir
+ case 'm' :
+ m_next(ptr);
+ break;
+ // ren
+ case 'r' :
+ r_next(ptr);
+ break;
+ case 't' :
+ t_next(ptr);
+ break;
+ case 'x' :
+ extended_mon(ptr);
+ break;
+ // Help
+ case '?' :
+ PUTS(HelpMsg0);
+ break;
+ // Exit monitor (return to main())
+ case 'q' :
+ PUTS("Return to main\r\n");
+ return;
+ // Not a command
+ default:
+ PUTS("? [HELP]=?");
+ crlf();
+ break;
+ }
+ }
+}
+
+uint32_t get_disk_freespace(void)
+{
+ long p1;
+ UINT s1, s2;
+ FATFS *fs;
+ BYTE res;
+
+ if (Dirx == NULL){
+ Dirx = new FATFS_DIR;
+ }
+ char p = NULL;
+ res = f_opendir(Dirx, &p);
+ if (res) {
+ return 0;
+ }
+ p1 = s1 = s2 = 0;
+ for(;;) {
+ res = f_readdir(Dirx, &Finfo);
+ if ((res != FR_OK) || !Finfo.fname[0]) break;
+ if (Finfo.fattrib & AM_DIR) {
+ s2++;
+ } else {
+ s1++;
+ p1 += Finfo.fsize;
+ }
+ }
+ res = f_getfree(&p, (DWORD*)&p1, &fs);
+ uint32_t size = p1 * fs->csize * 512;
+ if (res == FR_OK) {
+ return size;
+ } else {
+ return 0;
+ }
+}
+
+static void extended_mon( char *ptr )
+{
+ PUTS(HelpMsg1);
+ while(true) {
+ PUTS("e>");
+ ptr = Linebuf;
+ get_line( ptr, sizeof(Linebuf) );
+ switch ( *ptr++ ) {
+ case 'f' :
+ DEBUG_LINE;
+ file_inf(ptr);
+ break;
+ case 'd' :
+ DEBUG_LINE;
+ disk_inf(ptr);
+ break;
+ case 'm' :
+ DEBUG_LINE;
+ memory_inf(ptr);
+ break;
+ case '?' :
+ DEBUG_LINE;
+ PUTS(HelpMsg1);
+ break;
+ case 'q' :
+ DEBUG_LINE;
+ return;
+ default:
+ PUTS( "?\r\n" );
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+// General monitor functions
+static void v_next( char *ptr )
+{
+ switch ( *ptr++ ) {
+ case 'o' :
+ if (*ptr == 'l') {
+ *ptr = 's';
+ file_inf(ptr); // fs [<path>] - Show volume status
+ }
+ break;
+ default:
+ PUTS( "?\r\n" );
+ }
+}
+
+static void d_next(char *ptr)
+{
+ switch ( *ptr++ ) {
+ case 'i' :
+ if (*ptr == 'r') {
+ *ptr = 'l';
+ file_inf(ptr); // fl [<path>] - Directory listing
+ }
+ break;
+ default:
+ PUTS( "?\r\n" );
+ }
+}
+
+static void c_next(char *ptr)
+{
+ switch ( *ptr++ ) {
+ case 'o' :
+ if ((*ptr == 'p') && (*(ptr + 1) == 'y')) {
+ ptr++;
+ *ptr = 'x';
+ file_inf(ptr); // fx <src_name> <dst_name> - Copy file
+ }
+ break;
+ case 'd' :
+ *ptr = 'g';
+ file_inf(ptr); // fx <src_name> <dst_name> - Copy file
+ break;
+ default:
+ PUTS( "?\r\n" );
+ }
+}
+
+static void m_next(char *ptr)
+{
+ switch ( *ptr++ ) {
+ case 'k' :
+ if ((*ptr == 'd') && (*(ptr + 1) == 'i') && (*(ptr + 2) == 'r')) {
+ ptr += 2;
+ *ptr = 'k';
+ file_inf(ptr); // fk <name> - Create a directory
+ }
+ break;
+ default:
+ PUTS("?\r\n");
+ }
+}
+
+static void r_next(char *ptr)
+{
+ switch (*ptr++) {
+ case 'e' :
+ if (*ptr == 'n') {
+ // fn <old_name> <new_name> - Change file/dir name
+ file_inf(ptr);
+ }
+ break;
+ default:
+ PUTS("?\r\n");
+ }
+}
+
+static void t_next(char *ptr)
+{
+ switch (*ptr++) {
+ case ' ' :
+ case 0x0d:
+ chk_and_set_time(ptr);
+ case 'y' :
+ if ((*ptr == 'p') && (*(ptr + 1) == 'e')) {
+ ptr++;
+ *ptr = '&';
+ file_inf(ptr);
+ }
+ break;
+ default:
+ PUTS("?\r\n");
+ }
+}
+
+static FRESULT scan_files (
+ char* path /* Pointer to the path name working buffer */
+)
+{
+ FATFS_DIR dirs;
+ FRESULT res;
+ BYTE i;
+ char *fn;
+
+ if ((res = f_opendir(&dirs, path)) == FR_OK) {
+ i = strlen(path);
+ PRINTF("path: %s, n=%u\r\n", path, i);
+ while (((res = f_readdir(&dirs, &Finfo)) == FR_OK) && Finfo.fname[0]) {
+ if (FF_FS_RPATH && Finfo.fname[0] == '.') {
+ continue;
+ }
+#if FF_USE_LFN
+ //fn = *Finfo.lfname ? Finfo.lfname : Finfo.fname;
+ if (Finfo.altname[0] == 0) {
+ fn = Finfo.fname;
+ } else {
+ fn = Finfo.altname;
+ }
+#else
+ fn = Finfo.fname;
+#endif
+ if (Finfo.fattrib & AM_DIR) {
+ AccDirs++;
+ *(path+i) = '/';
+ strcpy(path+i+1, fn);
+ res = scan_files(path);
+ *(path+i) = '\0';
+ if (res != FR_OK) break;
+ } else {
+ PRINTF("%s/%s\r\n", path, fn);
+ AccFiles++;
+ AccSize += Finfo.fsize;
+ }
+ }
+ }
+ return res;
+}
+
+static void put_rc (FRESULT rc)
+{
+ const char *str =
+ "OK\0" "DISK_ERR\0" "INT_ERR\0" "NOT_READY\0" "NO_FILE\0" "NO_PATH\0"
+ "INVALID_NAME\0" "DENIED\0" "EXIST\0" "INVALID_OBJECT\0"
+ "WRITE_PROTECTED\0" "INVALID_DRIVE\0" "NOT_ENABLED\0"
+ "NO_FILE_SYSTEM\0" "MKFS_ABORTED\0" "TIMEOUT\0"
+ "LOCKED\0" "NOT_ENOUGH_CORE\0" "TOO_MANY_OPEN_FILES\0";
+ int i;
+
+ for ( i = 0; i != rc && *str; i++ ) {
+ while ( *str++ ) {
+ ;
+ }
+ }
+ PRINTF( "rc=%u FR_%s\r\n", (UINT)rc, str );
+}
+
+static void file_inf(char *ptr)
+{
+ long p1, p2, p3;
+ CHAR *ptr2;
+ BYTE f_res;
+ UINT s1, s2, cnt, blen = sizeof Buff;
+ FATFS *fs;
+ static const BYTE ft[] = {0, 12, 16, 32};
+ BYTE res;
+ DWORD ofs = 0;
+ uint32_t tim;
+
+ switch (*ptr++) {
+ case '&' :
+ DEBUG_LINE;
+ while (*ptr == ' ') ptr++;
+ /* Open a file */
+ f_res = f_open(&File1, ptr, FA_READ);
+ if ( f_res ) {
+ put_rc((FRESULT)f_res);
+ break;
+ }
+ DEBUG_LINE;
+ /* Read all lines and display it */
+ while(true) {
+ f_res = f_read(&File1, (TCHAR*)Buff, blen, &cnt);
+ if ( f_res ) {
+ put_rc((FRESULT)f_res);
+ break;
+ }
+ for (s1 = 0; s1 < cnt; s1++) {
+ PUTC(Buff[s1]);
+ }
+ if (cnt != blen) {
+ break;
+ }
+ }
+ DEBUG_LINE;
+ /* Close the file */
+ f_close(&File1);
+ break;
+
+ case 'i' : /* fi [<opt>]- Initialize logical drive */
+ if ( !xatoi(&ptr, &p1) ) {
+ break;
+ }
+ if (!xatoi(&ptr, &p2)) p2 = 0;
+ put_rc(f_mount(&Fatfs[p1], (const TCHAR*)p1, 0));
+ break;
+
+ case 's' : /* fs [<path>] - Show volume status */
+ f_res = f_getfree( ptr, (DWORD*)&p2, &fs );
+ if ( f_res ) {
+ put_rc((FRESULT)f_res);
+ break;
+ }
+ PRINTF
+ (
+ "\rFAT type = FAT%u\r\nBytes/Cluster"
+ " = %lu\r\nNumber of FATs = %u\r\n"
+ "Root DIR entries = %u\r\n"
+ "Sectors/FAT = %lu\r\n"
+ "Number of clusters = %lu\r\n"
+ "FAT start (lba) = %lu\r\n"
+ "DIR start (lba,clustor) = %lu\r\n"
+ "Data start (lba) = %lu\r\n",
+ ft[fs->fs_type & 3], (DWORD)fs->csize * 512, fs->n_fats,
+ fs->n_rootdir, fs->fsize, (DWORD)fs->n_fatent - 2,
+ fs->fatbase, fs->dirbase, fs->database
+ );
+ AccSize = AccFiles = AccDirs = 0;
+ break;
+ case 'l' : /* fl [<path>] - Directory listing */
+ while (*ptr == ' ') ptr++;
+ res = f_opendir(Dirx, ptr);
+ if (res) {
+ put_rc((FRESULT)res);
+ break;
+ }
+ p1 = s1 = s2 = 0;
+ for(;;) {
+ res = f_readdir(Dirx, &Finfo);
+ if ((res != FR_OK) || !Finfo.fname[0]) break;
+ if (Finfo.fattrib & AM_DIR) {
+ s2++;
+ } else {
+ s1++;
+ p1 += Finfo.fsize;
+ }
+ PRINTF("%c%c%c%c%c %u/%02u/%02u %02u:%02u %9lu %s\r\n",
+ (Finfo.fattrib & AM_DIR) ? 'D' : '-',
+ (Finfo.fattrib & AM_RDO) ? 'R' : '-',
+ (Finfo.fattrib & AM_HID) ? 'H' : '-',
+ (Finfo.fattrib & AM_SYS) ? 'S' : '-',
+ (Finfo.fattrib & AM_ARC) ? 'A' : '-',
+ (Finfo.fdate >> 9) + 1980, (Finfo.fdate >> 5) & 15,
+ Finfo.fdate & 31,
+ (Finfo.ftime >> 11), (Finfo.ftime >> 5) & 63,
+ Finfo.fsize, Finfo.fname);
+ }
+#if 0 // f_getfree cannnot count under Dir, subdirectory area
+ PRINTF("%4u File(s),%10lu bytes total\r\n%4u Dir(s)", s1, p1, s2);
+ res = f_getfree(ptr, (DWORD*)&p1, &fs);
+ if (res == FR_OK)
+ PRINTF(", %10lu bytes free\r\n", p1 * fs->csize * 512);
+ else
+ put_rc((FRESULT)res);
+#else
+ PRINTF("%4u File(s) = %10lu bytes total, %4u Dir(s)\r\n",
+ s1, p1, s2);
+#endif
+ break;
+
+ case 'o' : /* fo <mode> <file> - Open a file */
+ if (!xatoi(&ptr, &p1)) break;
+ while (*ptr == ' ') ptr++;
+ put_rc(f_open(&File1, ptr, (BYTE)p1));
+#if 0
+ put_rc(f_open(&File1, "savedata.txt", 1));
+ PRINTF("Open savedata.txt as read mode\r\n");
+#endif
+ break;
+
+ case 'c' : /* fc - Close a file */
+ put_rc(f_close(&File1));
+ break;
+
+ case 'e' : /* fe - Seek file pointer */
+ if (!xatoi(&ptr, &p1)) break;
+ res = f_lseek(&File1, p1);
+ put_rc((FRESULT)res);
+ if (res == FR_OK)
+ PRINTF("fptr=%lu(0x%lX)\r\n", File1.fptr, File1.fptr);
+ break;
+
+ case 'd' : /* fd <len> - read and dump file from current fp */
+ if (!xatoi(&ptr, &p1)) break;
+ ofs = File1.fptr;
+ while (p1) {
+ if ((UINT)p1 >= 16) {
+ cnt = 16;
+ p1 -= 16;
+ } else {
+ cnt = p1;
+ p1 = 0;
+ }
+ res = f_read(&File1, Buff, cnt, &cnt);
+ if (res != FR_OK) {
+ put_rc((FRESULT)res);
+ break;
+ }
+ if (!cnt) break;
+ put_dump(Buff, ofs, cnt, DW_CHAR);
+ ofs += 16;
+ }
+ break;
+
+ case 'r' : /* fr <len> - read file */
+ if (!xatoi(&ptr, &p1)) break;
+ p2 = 0;
+ t.reset();
+ t.start();
+ while (p1) {
+ if ((UINT)p1 >= blen) {
+ cnt = blen;
+ p1 -= blen;
+ } else {
+ cnt = p1;
+ p1 = 0;
+ }
+ res = f_read(&File1, Buff, cnt, &s2);
+ if (res != FR_OK) {
+ put_rc((FRESULT)res);
+ break;
+ }
+ p2 += s2;
+ if (cnt != s2) break;
+ }
+ tim = t.read_ms();
+ PRINTF("%lu bytes read with %lu kB/sec.\r\n",
+ p2, tim ? (p2 / tim) : 0);
+ break;
+
+ case 'w' : /* fw <len> <val> - write file */
+ if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2)) break;
+ memset(Buff, (BYTE)p2, blen);
+ p2 = 0;
+ t.reset();
+ t.start();
+ while (p1) {
+ if ((UINT)p1 >= blen) {
+ cnt = blen;
+ p1 -= blen;
+ } else {
+ cnt = p1;
+ p1 = 0;
+ }
+ res = f_write(&File1, Buff, cnt, &s2);
+ if (res != FR_OK) {
+ put_rc((FRESULT)res);
+ break;
+ }
+ p2 += s2;
+ if (cnt != s2) break;
+ }
+ tim = t.read_ms();
+ PRINTF("%lu bytes written with %lu kB/sec.\r\n",
+ p2, tim ? (p2 / tim) : 0);
+ break;
+
+ case 'n' : /* fn <org.name> <new.name> - Change name of an object */
+ while (*ptr == ' ') ptr++;
+ ptr2 = strchr(ptr, ' ');
+ if (!ptr2) break;
+ *ptr2++ = 0;
+ while (*ptr2 == ' ') ptr2++;
+ put_rc(f_rename(ptr, ptr2));
+ break;
+
+ case 'u' : /* fu <name> - Unlink an object */
+ while (*ptr == ' ') ptr++;
+ put_rc(f_unlink(ptr));
+ break;
+
+ case 'v' : /* fv - Truncate file */
+ put_rc(f_truncate(&File1));
+ break;
+
+ case 'k' : /* fk <name> - Create a directory */
+ while (*ptr == ' ') ptr++;
+ put_rc(f_mkdir(ptr));
+ break;
+#if 0
+ case 'a' : /* fa <atrr> <mask> <name> - Change attribute of an object */
+ if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2)) break;
+ while (*ptr == ' ') ptr++;
+ put_rc(f_chmod(ptr, p1, p2));
+ break;
+#endif
+#if 0
+ /* ft <year> <month> <day> <hour> <min> <sec> <name>
+ - Change timestamp of an object */
+ case 't' :
+ if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2) || !xatoi(&ptr, &p3)) {
+ break;
+ }
+ Finfo.fdate = ((p1 - 1980) << 9) | ((p2 & 15) << 5) | (p3 & 31);
+ if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2) || !xatoi(&ptr, &p3)) {
+ break;
+ }
+ Finfo.ftime =
+ ((p1 & 31) << 11) | ((p2 & 63) << 5) | ((p3 >> 1) & 31);
+ put_rc(f_utime(ptr, &Finfo));
+ break;
+#endif
+#if FILCPY_NOTUSE == 0
+ case 'x' : /* fx <src_name> <dst_name> - Copy file */
+ while ( *ptr == ' ' ) {
+ ptr++;
+ }
+ ptr2 = strchr( ptr, ' ' );
+ if ( !ptr2 ) {
+ break;
+ }
+ *ptr2++ = 0;
+ while ( *ptr2 == ' ' ) {
+ ptr2++;
+ }
+ f_res = f_open( &File1, ptr, FA_OPEN_EXISTING | FA_READ );
+ PRINTF("Opening %s \r\n", ptr);
+ if ( f_res ) {
+ put_rc( (FRESULT)f_res );
+ break;
+ }
+ f_res = f_open( &File2, ptr2, FA_CREATE_ALWAYS | FA_WRITE );
+ PRINTF(" Creating %s \r\n", ptr2);
+ if ( f_res ) {
+ put_rc( (FRESULT)f_res );
+ f_close( &File1 );
+ break;
+ }
+ PRINTF("Copying file...");
+ p1 = 0;
+ for ( ;; ) {
+ f_res = f_read( &File1, Buff, blen, &s1 );
+ if ( f_res || s1 == 0 ) {
+ break; /* error or eof */
+ }
+ f_res = f_write( &File2, Buff, s1, &s2 );
+ p1 += s2;
+ if ( f_res || s2 < s1 ) {
+ break; /* error or disk full */
+ }
+ }
+ f_close( &File1 );
+ f_close( &File2 );
+ crlf();
+ break;
+#endif
+#if 0
+ case 'x' : /* fx <src.name> <dst.name> - Copy a file */
+ while (*ptr == ' ') ptr++;
+ ptr2 = strchr(ptr, ' ');
+ if (!ptr2) break;
+ *ptr2++ = 0;
+ while (*ptr2 == ' ') ptr2++;
+ PRINTF("Opening \"%s\"", ptr);
+ res = f_open(&File1, ptr, FA_OPEN_EXISTING | FA_READ);
+ PUTS("\r\n");
+ if (res) {
+ put_rc((FRESULT)res);
+ break;
+ }
+ PRINTF("Creating \"%s\"", ptr2);
+ res = f_open(&File1, ptr2, FA_CREATE_ALWAYS | FA_WRITE);
+ PUTS("\r\n");
+ if (res) {
+ put_rc((FRESULT)res);
+ f_close(&File1);
+ break;
+ }
+ PRINTF("Copying file...");
+ t.reset();
+ t.start();
+ p1 = 0;
+ for (;;) {
+ res = f_read(&File1, Buff, blen, &s1);
+ if (res || s1 == 0) break; /* error or eof */
+ res = f_write(&File2, Buff, s1, &s2);
+ p1 += s2;
+ if (res || s2 < s1) break; /* error or disk full */
+ }
+ tim = t.read_ms();
+ PRINTF("\r\n%lu bytes copied with %lu kB/sec.\r\n",
+ p1, tim ? (p1 / tim) : 0);
+ f_close(&File1);
+ f_close(&File2);
+ break;
+#endif
+#if FF_FS_RPATH
+ case 'g' : /* fg <path> - Change current directory */
+ while (*ptr == ' ') ptr++;
+ put_rc(f_chdir(ptr));
+ break;
+#if FF_FS_RPATH >= 2
+ case 'q' : /* fq - Show current dir path */
+ res = f_getcwd(Linebuf, sizeof Linebuf);
+ if (res)
+ put_rc(res);
+ else
+ PRINTF("%s\r\n", Linebuf);
+ break;
+#endif
+#endif
+#if FF_USE_LABEL
+ case 'b' : /* fb <name> - Set volume label */
+ while (*ptr == ' ') ptr++;
+ put_rc(f_setlabel(ptr));
+ break;
+#endif /* FF_USE_LABEL */
+#if FF_USE_MKFS
+ case 'm' : /* fm <type> <csize> - Create file system */
+ if (!xatoi(&ptr, &p2) || !xatoi(&ptr, &p3)) break;
+ PRINTF("The volume will be formatted. Are you sure? (Y/n)=");
+ get_line(Linebuf, sizeof Linebuf);
+ if (Linebuf[0] == 'Y')
+ put_rc(f_mkfs("", (BYTE)p2, (DWORD)p3, Buff, sizeof Buff));
+ break;
+#endif /* FF_USE_MKFS */
+ /* fz [<size>] - Change/Show R/W length for fr/fw/fx command */
+ case 'z' :
+ if (xatoi(&ptr, &p1) && p1 >= 1 && p1 <= (long)sizeof Buff)
+ blen = p1;
+ PRINTF("blen=%u\r\n", blen);
+ break;
+ }
+}
+
+static void memory_inf(char *ptr)
+{
+ long p1, p2, p3;
+
+ switch (*ptr++) {
+ case 'd' : /* md[b|h|w] <address> [<count>] - Dump memory */
+ switch (*ptr++) {
+ case 'w':
+ p3 = DW_LONG;
+ break;
+ case 'h':
+ p3 = DW_SHORT;
+ break;
+ default:
+ p3 = DW_CHAR;
+ }
+ if (!xatoi(&ptr, &p1)) break;
+ if (!xatoi(&ptr, &p2)) p2 = 128 / p3;
+ for (ptr = (char*)p1; p2 >= 16 / p3; ptr += 16, p2 -= 16 / p3)
+ put_dump(ptr, (DWORD)ptr, 16 / p3, p3);
+ if (p2) put_dump((BYTE*)ptr, (UINT)ptr, p2, p3);
+ break;
+ case 'f' : /* mf <address> <value> <count> - Fill memory */
+ if (!xatoi(&ptr, &p1) || !xatoi(&ptr, &p2) || !xatoi(&ptr, &p3)) {
+ break;
+ }
+ while (p3--) {
+ *(BYTE*)p1 = (BYTE)p2;
+ p1++;
+ }
+ break;
+ case 'e' : /* me[b|h|w] <address> [<value> ...] - Edit memory */
+ switch (*ptr++) { /* Get data width */
+ case 'w':
+ p3 = DW_LONG;
+ break;
+ case 'h':
+ p3 = DW_SHORT;
+ break;
+ default:
+ p3 = DW_CHAR;
+ }
+ if (!xatoi(&ptr, &p1)) break; /* Get start address */
+ if (xatoi(&ptr, &p2)) { /* 2nd parameter is given (direct mode) */
+ do {
+ switch (p3) {
+ case DW_LONG:
+ *(DWORD*)p1 = (DWORD)p2;
+ break;
+ case DW_SHORT:
+ *(WORD*)p1 = (WORD)p2;
+ break;
+ default:
+ *(BYTE*)p1 = (BYTE)p2;
+ }
+ p1 += p3;
+ } while (xatoi(&ptr, &p2)); /* Get next value */
+ break;
+ }
+ for (;;) { /* 2nd parameter is not given (interactive mode) */
+ switch (p3) {
+ case DW_LONG:
+ PRINTF("%08X 0x%08X-", p1, *(DWORD*)p1);
+ break;
+ case DW_SHORT:
+ PRINTF("%08X 0x%04X-", p1, *(WORD*)p1);
+ break;
+ default:
+ PRINTF("%08X 0x%02X-", p1, *(BYTE*)p1);
+ }
+ ptr = Linebuf;
+ get_line(ptr, sizeof Linebuf);
+ if (*ptr == '.') break;
+ if ((BYTE)*ptr >= ' ') {
+ if (!xatoi(&ptr, &p2)) continue;
+ switch (p3) {
+ case DW_LONG:
+ *(DWORD*)p1 = (DWORD)p2;
+ break;
+ case DW_SHORT:
+ *(WORD*)p1 = (WORD)p2;
+ break;
+ default:
+ *(BYTE*)p1 = (BYTE)p2;
+ }
+ }
+ p1 += p3;
+ }
+ }
+}
+
+static void disk_inf(char *ptr)
+{
+ long p1, p2;
+ UINT s1;
+ BYTE res, b, drv = 0;
+ DWORD ofs = 0, sect = 0, blk[2];
+
+ switch (*ptr++) {
+ case 'd' : /* dd [<pd#> <sect>] - Dump secrtor */
+ if (!xatoi(&ptr, &p1)) {
+ p1 = drv;
+ p2 = sect;
+ } else {
+ if (!xatoi(&ptr, &p2)) break;
+ }
+ drv = (BYTE)p1;
+ sect = p2;
+ res = disk_read(drv, Buff, sect, 1);
+ if (res) {
+ PRINTF("rc=%d\r\n", (WORD)res);
+ break;
+ }
+ PRINTF("PD#:%u LBA:%lu\r\n", drv, sect++);
+ for (ptr=(char*)Buff, ofs = 0; ofs < 0x200; ptr += 16, ofs += 16)
+ put_dump((BYTE*)ptr, ofs, 16, DW_CHAR);
+ break;
+
+ case 'i' : /* di <pd#> - Initialize disk */
+ if (!xatoi(&ptr, &p1)) break;
+ PRINTF("rc=%d\r\n", (WORD)disk_initialize((BYTE)p1));
+ break;
+
+ case 's' : /* ds <pd#> - Show disk status */
+ if (!xatoi(&ptr, &p1)) break;
+ if (disk_ioctl((BYTE)p1, GET_SECTOR_COUNT, &p2) == RES_OK) {
+ PRINTF("Drive size: %lu sectors\r\n", p2);
+ }
+ if (disk_ioctl((BYTE)p1, GET_BLOCK_SIZE, &p2) == RES_OK) {
+ PRINTF("Block size: %lu sectors\r\n", p2);
+ }
+ if (disk_ioctl((BYTE)p1, MMC_GET_TYPE, &b) == RES_OK) {
+ PRINTF("Media type: %u\r\n", b);
+ }
+ if (disk_ioctl((BYTE)p1, MMC_GET_CSD, Buff) == RES_OK) {
+ PUTS("CSD:\r\n");
+ put_dump(Buff, 0, 16, DW_CHAR);
+ }
+ if (disk_ioctl((BYTE)p1, MMC_GET_CID, Buff) == RES_OK) {
+ PUTS("CID:\r\n");
+ put_dump(Buff, 0, 16, DW_CHAR);
+ }
+ if (disk_ioctl((BYTE)p1, MMC_GET_OCR, Buff) == RES_OK) {
+ PUTS("OCR:\r\n");
+ put_dump(Buff, 0, 4, DW_CHAR);
+ }
+ if (disk_ioctl((BYTE)p1, MMC_GET_SDSTAT, Buff) == RES_OK) {
+ PUTS("SD Status:\r\n");
+ for (s1 = 0; s1 < 64; s1 += 16) {
+ put_dump(Buff+s1, s1, 16, DW_CHAR);
+ }
+ }
+ break;
+
+ case 'c' : /* Disk ioctl */
+ switch (*ptr++) {
+ case 's' : /* dcs <pd#> - CTRL_SYNC */
+ if (!xatoi(&ptr, &p1)) break;
+ PRINTF("rc=%d\r\n", disk_ioctl((BYTE)p1, CTRL_SYNC, 0));
+ break;
+ case 'e' : /* dce <pd#> <s.lba> <e.lba> - CTRL_TRIM */
+ if (!xatoi(&ptr, &p1) ||
+ !xatoi(&ptr, (long*)&blk[0]) ||
+ !xatoi(&ptr, (long*)&blk[1])) {
+ break;
+ }
+ PRINTF("rc=%d\r\n", disk_ioctl((BYTE)p1, CTRL_TRIM, blk));
+ break;
+ }
+ }
+}
+
+void put_dump (
+ void* buff, /* Pointer to the array to be dumped */
+ unsigned long addr, /* Heading address value */
+ int len, /* Number of items to be dumped */
+ int width /* Size of the items (DW_CHAR, DW_SHORT, DW_LONG) */
+)
+{
+ int i;
+ unsigned char *bp;
+ unsigned short *sp;
+ unsigned long *lp;
+
+ PRINTF( "%08lx ", addr ); /* address */
+ switch ( width ) {
+ case DW_CHAR:
+ bp = (unsigned char *)buff;
+ for ( i = 0; i < len; i++ ) { /* Hexdecimal dump */
+ PRINTF( " %02x", bp[i] );
+ }
+ PUTC(' ');
+ for ( i = 0; i < len; i++ ) { /* ASCII dump */
+ PUTC( (bp[i] >= ' ' && bp[i] <= '~') ? bp[i] : '.' );
+ }
+ break;
+ case DW_SHORT:
+ sp = (unsigned short *)buff;
+ do { /* Hexdecimal dump */
+ PRINTF( " %04x", *sp++ );
+ } while ( --len );
+ break;
+ case DW_LONG:
+ lp = (unsigned long *)buff;
+ do { /* Hexdecimal dump */
+ PRINTF( " %08lx", *lp++ );
+ } while ( --len );
+ break;
+ }
+ PUTS( "\r\n" );
+}
+
+// RTC related subroutines
+void chk_and_set_time(char *ptr)
+{
+ char buf[64];
+
+ long p1;
+ struct tm t;
+ time_t seconds;
+
+ if (xatoi(&ptr, &p1)) {
+ t.tm_year = (uint8_t)p1 + 100;
+ pc.printf("Year:%d ",p1);
+ xatoi( &ptr, &p1 );
+ t.tm_mon = (uint8_t)p1 - 1;
+ pc.printf("Month:%d ",p1);
+ xatoi( &ptr, &p1 );
+ t.tm_mday = (uint8_t)p1;
+ pc.printf("Day:%d ",p1);
+ xatoi( &ptr, &p1 );
+ t.tm_hour = (uint8_t)p1;
+ pc.printf("Hour:%d ",p1);
+ xatoi( &ptr, &p1 );
+ t.tm_min = (uint8_t)p1;
+ pc.printf("Min:%d ",p1);
+ xatoi( &ptr, &p1 );
+ t.tm_sec = (uint8_t)p1;
+ pc.printf("Sec: %d \r\n",p1);
+ seconds = mktime(&t);
+ set_time(seconds);
+ } else {
+ seconds = time(NULL);
+ }
+ strftime(buf, 50, " %B %d,'%y, %H:%M:%S\r\n", localtime(&seconds));
+ pc.printf("[Time] %s", buf);
+}
+
+// Get key input data
+void get_line (char *buff, int len)
+{
+ char c;
+ int idx = 0;
+
+ for (;;) {
+ c = GETC();
+ // Added by Kenji Arai / JH1PJL May 9th, 2010
+ if (c == '\r') {
+ buff[idx++] = c;
+ break;
+ }
+ if ((c == '\b') && idx) {
+ idx--;
+ PUTC(c);
+ PUTC(' ');
+ PUTC(c);
+ }
+ if (((uint8_t)c >= ' ') && (idx < len - 1)) {
+ buff[idx++] = c;
+ PUTC(c);
+ }
+ }
+ buff[idx] = 0;
+ PUTS("\r\n");
+}
+
+/* Outpur LF & CR */
+void crlf( void )
+{
+ PRINTF( "\r\n" );
+}
+
+/* Check key input */
+unsigned int check_hit_key (void)
+{
+ return ( READABLE() );
+}
+
+/*----------------------------------------------*/
+/* Get a value of the string */
+/*----------------------------------------------*/
+/* "123 -5 0x3ff 0b1111 0377 w "
+ ^ 1st call returns 123 and next ptr
+ ^ 2nd call returns -5 and next ptr
+ ^ 3rd call returns 1023 and next ptr
+ ^ 4th call returns 15 and next ptr
+ ^ 5th call returns 255 and next ptr
+ ^ 6th call fails and returns 0
+*/
+int xatoi ( /* 0:Failed, 1:Successful */
+ char **str, /* Pointer to pointer to the string */
+ long *res /* Pointer to the valiable to store the value */
+)
+{
+ unsigned long val;
+ unsigned char c, r, s = 0;
+
+ *res = 0;
+ while ( (c = **str) == ' ' ) {
+ (*str)++; /* Skip leading spaces */
+ }
+ if ( c == '-' ) { /* negative? */
+ s = 1;
+ c = *(++(*str));
+ }
+ if ( c == '0' ) {
+ c = *(++(*str));
+ switch (c) {
+ case 'x': /* hexdecimal */
+ r = 16;
+ c = *(++(*str));
+ break;
+ case 'b': /* binary */
+ r = 2;
+ c = *(++(*str));
+ break;
+ default:
+ if ( c <= ' ' ) return 1; /* single zero */
+ if ( c < '0' || c > '9' ) return 0; /* invalid char */
+ r = 8; /* octal */
+ }
+ } else {
+ if ( c < '0' || c > '9' ) return 0; /* EOL or invalid char */
+ r = 10; /* decimal */
+ }
+ val = 0;
+ while ( c > ' ' ) {
+ if ( c >= 'a' ) {
+ c -= 0x20;
+ }
+ c -= '0';
+ if ( c >= 17 ) {
+ c -= 7;
+ if ( c <= 9 ) {
+ return 0; /* invalid char */
+ }
+ }
+ if ( c >= r ) {
+ return 0; /* invalid char for current radix */
+ }
+ val = val * r + c;
+ c = *(++(*str));
+ }
+ if (s) val = 0 - val; /* apply sign if needed */
+ *res = val;
+ return 1;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/5_SDCard/FatFs_Mon/mon.h Sat Apr 14 04:56:34 2018 +0000 @@ -0,0 +1,15 @@ +/* + * mbed Application program for the mbed + * FatFs Check program /monitor part + * + * Copyright (c) 2015,'18 Kenji Arai / JH1PJL + * http://www.page.sannet.ne.jp/kenjia/index.html + * https://os.mbed.com/users/kenjiArai/ + * Created: May 5th, 2015 + * Revised: June 14th, 2015 + * Revised: April 7th, 2018 + */ + +// Function prototypes -------------------------------------------------------- +void mon(void); +uint32_t get_disk_freespace(void);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/5_SDCard/main.cpp Sat Apr 14 04:56:34 2018 +0000
@@ -0,0 +1,111 @@
+/*
+ * Mbed Application program
+ * SD Card file control function with FatFs on Mbed-os5
+ *
+ * Copyright (c) 2018 Kenji Arai / JH1PJL
+ * http://www.page.sannet.ne.jp/kenjia/index.html
+ * https://os.mbed.com/users/kenjiArai/
+ * Created: April 4th, 2018
+ * Revised: April 14th, 2018 only for TYBLE16
+ */
+
+//#define EXAMPLE_5_SDCARD
+#ifdef EXAMPLE_5_SDCARD
+
+// Include --------------------------------------------------------------------
+#include "mbed.h"
+#include "SDBlockDevice.h"
+#include "FATFileSystem.h"
+#include "mon.h"
+#include "TYBLE16_BASE.h"
+#include <stdlib.h>
+
+// Definition -----------------------------------------------------------------
+#define USER_SW_ON 0
+
+// Constructor ----------------------------------------------------------------
+DigitalOut led(LED1);
+DigitalIn user_sw(BUTTON1, PullUp);
+Serial pc(USBTX, USBRX, 115200);
+SDBlockDevice sd(D3, D2, D0, D1, 8000000);
+FATFileSystem fs("fs");
+
+// RAM ------------------------------------------------------------------------
+
+// ROM / Constant data --------------------------------------------------------
+char *const opngmsg =
+ "\x1b[2J\x1b[H"__FILE__ "\r\n"__DATE__ " " __TIME__ " (UTC)\r\n""\r\n";
+char *const opening_msg0 = "microSD Card test program";
+char *const opening_msg1 = " -> run on Mbed OS-5\r\n";
+
+// Function prototypes --------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// Control Program
+//------------------------------------------------------------------------------
+int main()
+{
+ time_t seconds;
+ uint32_t data0 = 10000U;
+ uint32_t data1 = 20000U;
+ uint32_t data2 = 30000U;
+ uint32_t data3 = 40000U;
+ uint32_t data4 = 50000U;
+ uint32_t data5 = 60000U;
+
+ pc.puts(opngmsg);
+ // Check TYBLE-16 configuration
+ cpu_sys();
+ compile_condition();
+ if (user_sw == USER_SW_ON) {
+ mon();
+ }
+ //pc.printf("line:%d\r\n", __LINE__);
+ /* Init SD CARD reader */
+ sd.init();
+ fs.mount(&sd);
+ FILE* fp = fopen("/fs/mydata.txt", "a");
+ if (fp != 0) {
+ pc.printf("%s%s", opening_msg0, opening_msg1);
+ fprintf(fp,"%s%s", opening_msg0, opening_msg1);
+ } else {
+ pc.printf("ERROR\r\n");
+ }
+ fclose(fp);
+ while (pc.readable()) {
+ char c = pc.getc(); // dummy read
+ }
+ while (true) {
+ uint32_t size = get_disk_freespace();
+ pc.printf("free %u ", size);
+ fp = fopen("/fs/mydata.txt", "a");
+ if(fp != 0) {
+ char tmp[64];
+ seconds = time(NULL);
+ strftime(tmp, 64, "TYBLE16 %H:%M:%S,%Y/%m/%d,", localtime(&seconds));
+ pc.printf(tmp);
+ fprintf(fp, "%s", tmp);
+ pc.printf("%08d;%08d;%08d;%08d;%08d;%08d\r\n",
+ ++data0, ++data1, ++data2, ++data3, ++data4, ++data5);
+ fprintf(fp, "%08d;%08d;%08d;%08d;%08d;%08d\r\n",
+ data0, data1, data2, data3, data4, data5);
+ } else {
+ pc.printf("ERROR\r\n");
+ }
+ fclose(fp);
+ Thread::wait(100);
+ if (user_sw == USER_SW_ON) {
+ break;
+ }
+ if (pc.readable()) {
+ mon();
+ }
+ led = !led;
+ }
+ while(true) {
+ mon();
+ NVIC_SystemReset();
+ }
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/5_SDCard/sd-driver.lib Sat Apr 14 04:56:34 2018 +0000 @@ -0,0 +1,1 @@ +https://github.com/armmbed/sd-driver/#6238fc964f8e8dc5c303ab75a1e6c115c7db30d7
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/6_Thermo/main.cpp Sat Apr 14 04:56:34 2018 +0000
@@ -0,0 +1,206 @@
+/* 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.
+ */
+/*
+ Modified by Kenji Arai, April 14th, 2018
+ https://os.mbed.com/users/kenjiArai/
+ */
+
+//#define EXAMPLE_6_THERMO
+#ifdef EXAMPLE_6_THERMO
+
+#include <events/mbed_events.h>
+#include "mbed.h"
+#include "ble/BLE.h"
+#include "ble/services/HealthThermometerService.h"
+#include "TYBLE16_BASE.h"
+#include "TextLCD.h"
+#include "BME280.h"
+
+#define NO_SENSOR 1
+#define HAS_SENSOR 0
+#define USE_LCD 0
+
+DigitalOut led1(LED1, 1);
+Serial pc(USBTX, USBRX);
+I2C i2c(I2C_SDA, I2C_SCL);
+BME280 hmtp(i2c);
+#if USE_LCD
+TextLCD_I2C_N lcd(&i2c, 0x7c, TextLCD::LCD16x2); // LCD(Akizuki AQM1602A)
+#endif
+
+const static char DEVICE_NAME[] = "TYBLE16";
+static const uint16_t uuid16_list[]
+= {GattService::UUID_HEALTH_THERMOMETER_SERVICE};
+
+char *const opngmsg =
+ "\x1b[2J\x1b[H"__FILE__ "\r\n"__DATE__ " " __TIME__ " (UTC)\r\n""\r\n";
+
+static float currentTemperature = 39.6f;
+static HealthThermometerService *thermometerServicePtr;
+
+static EventQueue eventQueue(/* event count */ 16 * EVENTS_EVENT_SIZE);
+
+/* Restart Advertising on disconnection*/
+void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *)
+{
+ BLE::Instance().gap().startAdvertising();
+}
+
+void updateSensorValue(void)
+{
+ static uint32_t count = 0;
+
+#if NO_SENSOR
+ /* Do blocking calls or whatever is necessary for sensor polling.
+ In our case, we simply update the Temperature measurement. */
+ currentTemperature
+ = (currentTemperature + 0.1f > 43.0f) ? 39.6f : currentTemperature + 0.1f;
+ thermometerServicePtr->updateTemperature(currentTemperature);
+#elif HAS_SENSOR
+ currentTemperature = hmtp.getTemperature();
+ pc.printf("Temperature= %+5.2f [degC]", currentTemperature);
+ pc.printf(", count = %8u\r\n", count++);
+#if USE_LCD
+ lcd.locate(0, 1);
+ lcd.printf(" %+5.2f %7u", currentTemperature, count);
+#endif
+ thermometerServicePtr->updateTemperature(currentTemperature);
+#else
+ thermometerServicePtr->updateTemperature(currentTemperature);
+#endif
+}
+
+void periodicCallback(void)
+{
+ led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */
+
+ if (BLE::Instance().gap().getState().connected) {
+ eventQueue.call(updateSensorValue);
+ }
+}
+
+void onBleInitError(BLE &ble, ble_error_t error)
+{
+ /* Initialization error handling should go here */
+}
+
+void printMacAddress()
+{
+ /* Print out device MAC address to the console*/
+ Gap::AddressType_t addr_type;
+ Gap::Address_t address;
+ BLE::Instance().gap().getAddress(&addr_type, address);
+ pc.printf("DEVICE MAC ADDRESS: ");
+ for (int i = 5; i >= 1; i--) {
+ pc.printf("%02x:", address[i]);
+ }
+ pc.printf("%02x\r\n", address[0]);
+}
+
+void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
+{
+ BLE& ble = params->ble;
+ ble_error_t error = params->error;
+
+ if (error != BLE_ERROR_NONE) {
+ onBleInitError(ble, error);
+ return;
+ }
+
+ if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
+ return;
+ }
+
+ ble.gap().onDisconnection(disconnectionCallback);
+
+ /* Setup primary service. */
+ thermometerServicePtr =
+ new HealthThermometerService(ble,
+ currentTemperature,
+ HealthThermometerService::LOCATION_EAR);
+
+ /* 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::THERMOMETER_EAR
+ );
+ 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();
+
+ printMacAddress();
+}
+
+void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context)
+{
+ BLE &ble = BLE::Instance();
+ eventQueue.call(Callback<void()>(&ble, &BLE::processEvents));
+}
+
+int main()
+{
+ pc.puts(opngmsg);
+#if USE_LCD
+ lcd.locate(0, 0);
+ // 1234567890123456
+ lcd.puts("TYBLE16/Mbed-os5");
+ lcd.locate(0, 1);
+ // 1234567890123456
+ lcd.puts(" by JH1PJL ");
+ lcd.setCursor(TextLCD_Base::CurOff_BlkOff);
+ lcd.setContrast(0x19);
+ wait(2.0f);
+#endif
+ // Check TYBLE-16 configuration
+ cpu_sys();
+ if (compile_condition() == false) {
+ pc.printf("This is wrong configuration!!\r\n");
+ while(true) {
+ led1 = !led1;
+ wait(0.2);
+ }
+ }
+#if USE_LCD
+ lcd.locate(0, 0);
+ // 123456 7890123456
+ lcd.printf("Temp: %cC count", 0xdf);
+#endif
+ eventQueue.call_every(1000, periodicCallback);
+
+ BLE &ble = BLE::Instance();
+ ble.onEventsToProcess(scheduleBleEventsProcessing);
+ ble.init(bleInitComplete);
+
+ eventQueue.dispatch_forever();
+
+ return 0;
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/7_Uart_Client/main.cpp Sat Apr 14 04:56:34 2018 +0000
@@ -0,0 +1,482 @@
+/*
+ * ------- BLE Central/Client UART function -----------------------------------
+ * communicate with BLE_UART_Server program
+ * --- Tested on Switch Science mbed TY51822r3 ---
+ *
+ * Modified by Kenji Arai
+ * http://www.page.sannet.ne.jp/kenjia/index.html
+ * https://os.mbed.com/users/kenjiArai/
+ *
+ * Started: April 8th, 2016
+ * Revised: June 13th, 2016
+ * Revised: Feburary 10th, 2018 Not set mac addr but use device name
+ * Revised: Feburary 11th, 2018 use mbed-os5.7.4 with CircularBuffer
+ * Revised: April 14th, 2018 only for TYBLE16
+ *
+ * Original program (see original.cpp file):
+ * S130 potential unstability case [closed] by Fabien Comte
+ * https://devzone.nordicsemi.com/question/49705/
+ * s130-potential-unstability-case/
+ * GitHub Q&A by Fabien COMTE
+ * https://github.com/ARMmbed/ble/issues/69
+ * Reference program:
+ * BLE_Central_test by noboru koshinaka
+ * https://os.mbed.com/users/noboruk/code/BLE_Central_test/
+ * Tested Server Device:
+ * BLE_Uart_Server
+ * https://os.mbed.com/users/kenjiArai/code/BLE_Uart_Server/
+ */
+
+//#define EXAMPLE_7_UART_CLIENT
+#ifdef EXAMPLE_7_UART_CLIENT
+
+// Include --------------------------------------------------------------------
+#include "mbed.h"
+#include "BLE.h"
+#include "DiscoveredCharacteristic.h"
+#include "DiscoveredService.h"
+#include "UARTService.h"
+#include "CircularBuffer.h"
+
+// Definition -----------------------------------------------------------------
+//#define USE_MAC // if you use mac address, please define it
+
+#define NUM_ONCE 20
+#define BFSIZE (NUM_ONCE+4)
+
+//#define USE_DEBUG_MODE
+#ifdef USE_DEBUG_MODE
+#define DBG(...) { pc.printf(__VA_ARGS__); }
+#else
+#define DBG(...)
+#endif
+
+#define SOFT_DEVICE_FATHER_HANDLE 3
+
+// Object ---------------------------------------------------------------------
+BLE& ble_uart = BLE::Instance();
+DigitalOut alivenessLED(LED1, 1);
+DigitalOut connectedLED(D0, 0);
+Serial pc(USBTX, USBRX, 115200);
+//Serial pc(P0_3, P0_1, 115200); // for another board
+Ticker ticker;
+CircularBuffer<char, 1536> ser_bf;
+Thread tsk;
+
+// ROM / Constant data --------------------------------------------------------
+#ifdef USE_MAC
+#warning "You need to modify below value based on your board."
+const Gap::Address_t mac_board_0 = {0x50, 0x2b, 0xea, 0x14, 0x95, 0xd2};
+const Gap::Address_t mac_board_1 = {0x59, 0x2c, 0xa8, 0x0e, 0xe2, 0xef};
+const Gap::Address_t mac_board_2 = {0x0f, 0x72, 0xbf, 0x43, 0xbc, 0xd0};
+const Gap::Address_t mac_board_3 = {0x83, 0xc9, 0x1a, 0x90, 0xdf, 0xd6};
+const Gap::Address_t mac_board_4 = {0x43, 0xa4, 0x36, 0x11, 0x5b, 0xeb};
+#else
+const char PEER_NAME[] = "UART_PJL";
+#endif
+
+// RAM ------------------------------------------------------------------------
+Gap::Handle_t connectionHandle = 0xFFFF;
+DiscoveredCharacteristic uartTXCharacteristic;
+DiscoveredCharacteristic uartRXCharacteristic;
+bool foundUartRXCharacteristic = false;
+bool connected2server = false;
+bool connection_tx = false;
+bool connection_rx = false;
+UARTService * uartServicePtr = NULL;
+Gap::Address_t my_mac;
+int my_board_index = -1;
+bool received_uart_dat = false;
+int8_t uart_buffer[BFSIZE];
+uint8_t uart_bf_len;
+volatile bool rx_isr_busy = false;
+
+// Function prototypes --------------------------------------------------------
+// BLE
+void advertisementCallback(const Gap::AdvertisementCallbackParams_t *);
+void serviceDiscoveryCallback(const DiscoveredService *);
+void characteristicDiscoveryCallback(const DiscoveredCharacteristic *);
+void discoveryTerminationCallback(Gap::Handle_t );
+void onReceivedDataFromDeviceCallback(const GattHVXCallbackParams *);
+void connectionCallback(const Gap::ConnectionCallbackParams_t *);
+void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *);
+// Interrupt related
+void periodicCallback(void);
+void serialRxCallback(void);
+// serial receiving
+void pc_ser_rx(void);
+void preparation_sending_data(void);
+// Pre-check
+bool mac_equals(const Gap::Address_t, const Gap::Address_t);
+int get_board_index(const Gap::Address_t);
+void adjust_line(uint8_t *);
+
+//------------------------------------------------------------------------------
+// Control Program
+//------------------------------------------------------------------------------
+int main(void)
+{
+ alivenessLED = 0;
+ pc.attach(&serialRxCallback, Serial::RxIrq);
+ ticker.attach(periodicCallback, 1);
+ tsk.start(pc_ser_rx);
+ // clear terminal output
+ for (int k = 0; k < 3; k++) {
+ pc.printf("\r\n");
+ }
+ // opening message
+ pc.printf("UART Communication / Client(Central) side\r\n");
+ pc.printf(" need Server module (run BLE_Uart_Server program)\r\n");
+ // Mixed role **************************************************************
+ ble_uart.init();
+ ble_uart.gap().onConnection(connectionCallback);
+ ble_uart.gap().onDisconnection(disconnectionCallback);
+ // Client(Central) role ****************************************************
+ ble_uart.gattClient().onHVX(onReceivedDataFromDeviceCallback);
+ ble_uart.gap().setScanParams(500, 450);
+ ble_uart.gap().startScan(advertisementCallback);
+ while(true) {
+ // allow notifications from Server(Peripheral)
+ if (foundUartRXCharacteristic &&
+ !ble_uart.gattClient().isServiceDiscoveryActive()) {
+ // need to do the following only once
+ foundUartRXCharacteristic = false;
+ uint16_t value = BLE_HVX_NOTIFICATION;
+ ble_uart.gattClient().write(
+ GattClient::GATT_OP_WRITE_REQ,
+ connectionHandle,
+ uartRXCharacteristic.getValueHandle() + 1,
+ sizeof(uint16_t),
+ reinterpret_cast<const uint8_t *>(&value)
+ );
+ }
+ if (received_uart_dat == true) {
+ received_uart_dat = false;
+ for(int i = 0; i < uart_bf_len; i++) {
+ //pc.printf("%c", uart_buffer[i]);
+ pc.putc(uart_buffer[i]);
+ }
+ }
+ ble_uart.waitForEvent();
+ }
+}
+
+void periodicCallback(void)
+{
+ // Do blinky on alivenessLED to indicate system aliveness
+ alivenessLED = !alivenessLED;
+ if (connected2server) {
+ connectedLED = 1;
+ } else {
+ connectedLED = 0;
+ }
+ if (rx_isr_busy == true) {
+ rx_isr_busy = false;
+ } else {
+ tsk.signal_set(0x01);
+ }
+}
+
+void serialRxCallback()
+{
+ ser_bf.push(pc.getc());
+ rx_isr_busy = true;
+ tsk.signal_set(0x01);
+}
+
+void pc_ser_rx()
+{
+ static uint8_t linebf_irq[BFSIZE];
+ static volatile uint8_t linebf_irq_len = 0;
+
+ while(true) {
+ Thread::signal_wait(0x01);
+ if (ser_bf.empty()) {
+ if (linebf_irq_len != 0) {
+ linebf_irq[linebf_irq_len] = 0;
+ adjust_line(linebf_irq);
+ linebf_irq_len = 0;
+ uartTXCharacteristic.write(NUM_ONCE, linebf_irq);
+ }
+ }
+ while(!ser_bf.empty()) {
+ char c;
+ ser_bf.pop(c);
+ if (c == '\b') {
+ linebf_irq_len--;
+ pc.putc(c);
+ pc.putc(' ');
+ pc.putc(c);
+ } else if ((c >= ' ') || (c == '\r') || (c == '\n')) {
+ bool overflow = false;
+ if ((c == '\r') || (c == '\n')) {
+ if (linebf_irq_len == NUM_ONCE - 1) { // remain only 1 buffer
+ overflow = true;
+ linebf_irq[linebf_irq_len++] = '\r';
+ pc.putc('\r');
+ } else {
+ overflow = false;
+ linebf_irq[linebf_irq_len++] = '\r';
+ linebf_irq[linebf_irq_len++] = '\n';
+ pc.printf("\r\n");
+ }
+ } else {
+ linebf_irq[linebf_irq_len++] = c;
+ pc.putc(c);
+ }
+ if (linebf_irq_len >= NUM_ONCE ) {
+ linebf_irq[linebf_irq_len] = 0;
+ uartTXCharacteristic.write(linebf_irq_len, linebf_irq);
+ linebf_irq_len = 0;
+ if (overflow == true) {
+ overflow = false;
+ linebf_irq[linebf_irq_len++] = '\n';
+ pc.putc('\n');
+ }
+ }
+ }
+ }
+ }
+}
+
+void adjust_line(uint8_t *bf)
+{
+ uint8_t i, c;
+
+ for (i = 0; i <NUM_ONCE; bf++, i++) {
+ c = *bf;
+ if (c == 0) {
+ break;
+ }
+ }
+ for (; i < NUM_ONCE; bf++, i++) {
+ *bf = 0x11;
+ }
+ *(bf + 1) = 0;
+}
+
+void onReceivedDataFromDeviceCallback(const GattHVXCallbackParams *params)
+{
+ DBG(
+ "received HVX callback for handle %u; type %s\r\r\n",
+ params->handle,
+ (params->type == BLE_HVX_NOTIFICATION) ? "notification" : "indication"
+ );
+ if (params->type == BLE_HVX_NOTIFICATION) {
+ if ((params->handle
+ == uartRXCharacteristic.getValueHandle()) && (params->len > 0)) {
+ uart_bf_len = params->len;
+ strcpy((char *)uart_buffer, (char *)params->data);
+ received_uart_dat = true;
+ }
+ }
+}
+
+#ifdef USE_MAC
+
+bool mac_equals(const Gap::Address_t mac_1, const Gap::Address_t mac_2)
+{
+ DBG("Address: ");
+ for (int i = 0; i < 6; i++) {
+ DBG("0x%02x ", mac_1[i]);
+ }
+ DBG("\r\n");
+ for (int i = 0; i < 6; i++) {
+ if (mac_1[i] != mac_2[i]) {
+ DBG("0x%02x != 0x%02x at %d\r\n", mac_1[i], mac_2[i], i);
+ return false;
+ } else {
+ DBG("0x%02x == 0x%02x at %d\r\n", mac_1[i], mac_2[i], i);
+ }
+ }
+ return true;
+}
+
+int get_board_index(const Gap::Address_t mac)
+{
+ if (mac_equals(mac, mac_board_0)) {
+ return 0;
+ }
+ if (mac_equals(mac, mac_board_1)) {
+ return 1;
+ }
+ if (mac_equals(mac, mac_board_2)) {
+ return 2;
+ }
+ if (mac_equals(mac, mac_board_3)) {
+ return 3;
+ }
+ if (mac_equals(mac, mac_board_4)) {
+ return 4;
+ }
+ return -1;
+}
+
+// Client(Central) role ********************************************************
+void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params)
+{
+ // connections
+ int peer_board_index = get_board_index(params->peerAddr);
+ if (peer_board_index != -1) {
+ pc.printf("");
+ pc.printf(
+ "adv peerAddr [%02x %02x %02x %02x %02x %02x]\r\n",
+ params->peerAddr[5], params->peerAddr[4], params->peerAddr[3],
+ params->peerAddr[2], params->peerAddr[1], params->peerAddr[0]
+ );
+ pc.printf(
+ "rssi=%+4d, isScanResponse %u, AdvertisementType %u\r\n",
+ params->rssi, params->isScanResponse, params->type
+ );
+ ble_uart.gap().connect(
+ params->peerAddr, Gap::ADDR_TYPE_RANDOM_STATIC, NULL, NULL);
+ }
+}
+
+#else
+
+// Client(Central) role ********************************************************
+void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params)
+{
+ bool name_match = false;
+
+ // parse the advertising payload, looking for data type COMPLETE_LOCAL_NAME
+ // The advertising payload is a collection of key/value records where
+ // byte 0: length of the record excluding this byte
+ // byte 1: The key, it is the type of the data
+ // byte [2..N] The value. N is equal to byte0 - 1
+
+ for( uint8_t i = 0; i < params->advertisingDataLen; ++i) {
+ const uint8_t record_length = params->advertisingData[i];
+ if (record_length == 0) {
+ continue;
+ }
+ const uint8_t type = params->advertisingData[i + 1];
+ const uint8_t* value = params->advertisingData + i + 2;
+ const uint8_t value_length = record_length - 1;
+
+ if(type == GapAdvertisingData::COMPLETE_LOCAL_NAME) {
+ if ((value_length == sizeof(PEER_NAME))
+ && (memcmp(value, PEER_NAME, value_length) == 0)) {
+ pc.printf(
+ "\r\nadv peerAddr[%02x %02x %02x %02x %02x %02x] rssi %d, ",
+ params->peerAddr[5], params->peerAddr[4],
+ params->peerAddr[3], params->peerAddr[2],
+ params->peerAddr[1], params->peerAddr[0],
+ params->rssi
+ );
+ pc.printf(
+ "isScanResponse %u, AdvertisementType %u\r\n",
+ params->isScanResponse, params->type
+ );
+ name_match = true;
+ break;
+ }
+ }
+ i += record_length;
+ }
+ if( name_match != true ) {
+ return;
+ }
+
+ pc.printf("Found device name : %s\r\n",PEER_NAME);
+ // connections
+ ble_uart.gap().connect(params->peerAddr,
+ Gap::ADDR_TYPE_RANDOM_STATIC, NULL, NULL);
+}
+
+#endif
+
+void serviceDiscoveryCallback(const DiscoveredService *service)
+{
+ DBG("service found...\r\n");
+ if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) {
+ DBG(
+ "Service UUID-%x attrs[%u %u]\r\n",
+ service->getUUID().getShortUUID(),
+ service->getStartHandle(),
+ service->getEndHandle()
+ );
+ } else {
+ DBG("Service UUID-");
+ const uint8_t *longUUIDBytes = service->getUUID().getBaseUUID();
+ for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) {
+ DBG("%02x", longUUIDBytes[i]);
+ }
+ DBG(" attrs[%u %u]\r\n",
+ service->getStartHandle(), service->getEndHandle());
+ }
+}
+
+void characteristicDiscoveryCallback(
+ const DiscoveredCharacteristic *characteristicP)
+{
+ DBG(
+ " C UUID-%x valueAttr[%u] props[%x]\r\n",
+ characteristicP->getUUID().getShortUUID(),
+ characteristicP->getValueHandle(),
+ (uint8_t)characteristicP->getProperties().broadcast()
+ );
+ if (characteristicP->getUUID().getShortUUID()
+ == UARTServiceTXCharacteristicShortUUID) {
+ DBG("Sevice TX 0x%04x\r\n", UARTServiceTXCharacteristicShortUUID);
+ uartTXCharacteristic = *characteristicP;
+ connection_tx = true;
+ } else if (characteristicP->getUUID().getShortUUID()
+ == UARTServiceRXCharacteristicShortUUID) {
+ DBG("Sevice RX 0x%04x\r\n", UARTServiceRXCharacteristicShortUUID);
+ uartRXCharacteristic = *characteristicP;
+ foundUartRXCharacteristic = true;
+ connection_rx = true;
+ }
+}
+
+void discoveryTerminationCallback(Gap::Handle_t connectionHandle)
+{
+ DBG("terminated SD for handle=%u\r\n", connectionHandle);
+}
+
+// Mixed role ******************************************************************
+void connectionCallback(const Gap::ConnectionCallbackParams_t *params)
+{
+ if (params->role == Gap::CENTRAL) {
+ pc.printf("connected as Client(Central) (handle = %d)\r\n\r",
+ params->handle);
+ connected2server = true;
+ connectionHandle = params->handle;
+ ble_uart.gattClient().onServiceDiscoveryTermination(
+ discoveryTerminationCallback);
+ ble_uart.gattClient().launchServiceDiscovery(
+ params->handle,
+ serviceDiscoveryCallback,
+ characteristicDiscoveryCallback
+ );
+ }
+ pc.printf(
+ "Client(Central/Myself) %02x:%02x:%02x:%02x:%02x:%02x\r\n",
+ params->ownAddr[5], params->ownAddr[4], params->ownAddr[3],
+ params->ownAddr[2], params->ownAddr[1], params->ownAddr[0]
+ );
+ pc.printf(
+ "Connected Server(Peripheral) %02x:%02x:%02x:%02x:%02x:%02x\r\n",
+ params->peerAddr[5], params->peerAddr[4], params->peerAddr[3],
+ params->peerAddr[2], params->peerAddr[1], params->peerAddr[0]
+ );
+}
+
+void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
+{
+ DBG("handle = %d ", params->handle);
+ pc.printf(" -> disconnected\r\n", params->handle);
+ connected2server = false;
+// connection_1st = false;
+ connection_tx = false;
+ connection_rx = false;
+ if (params->handle == SOFT_DEVICE_FATHER_HANDLE) {
+ ble_uart.startAdvertising(); // restart advertising
+ } else {
+ ble_uart.gap().startScan(advertisementCallback);// restart scan
+ }
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/7_Uart_Client/original.cpp Sat Apr 14 04:56:34 2018 +0000
@@ -0,0 +1,614 @@
+#if 0
+//-------------------------------------------------------------------------------------------------
+// ORIGINAL PROGRAM
+// S130 potential unstability case [closed] by Fabien Comte
+// https://devzone.nordicsemi.com/question/49705/s130-potential-unstability-case/
+//
+#include "mbed.h"
+#include "BLE.h"
+#include "UARTService.h"
+#include "ble/DiscoveredCharacteristic.h"
+#include "ble/DiscoveredService.h"
+#include "ble/service/UARTService.h"
+
+#define SOFT_DEVICE_FATHER_HANDLE 3
+
+#define BOARDS_COUNT 3
+
+const Gap::Address_t mac_board_0 = {0xb8, 0xac, 0x4e, 0x8d, 0x8b, 0xeb};
+const Gap::Address_t mac_board_1 = {0x9c, 0x43, 0x62, 0x30, 0xaf, 0xd2};
+const Gap::Address_t mac_board_2 = {0x5f, 0x1a, 0x9e, 0x6a, 0x63, 0xdd};
+
+
+// tiny ble board
+#define LED_GREEN p21
+#define LED_RED p22
+#define LED_BLUE p23
+#define BUTTON_PIN p17
+#define BATTERY_PIN p1
+
+#define MPU6050_SDA p12
+#define MPU6050_SCL p13
+
+#define UART_TX p9
+#define UART_RX p11
+#define UART_CTS p8
+#define UART_RTS p10
+
+DigitalOut led(LED_RED);
+DigitalOut alivenessLED(LED_GREEN);
+InterruptIn button(BUTTON_PIN);
+AnalogIn battery(BATTERY_PIN);
+Serial pc(UART_TX, UART_RX);
+
+bool mac_equals(const Gap::Address_t mac_1, const Gap::Address_t mac_2)
+{
+ #if 0
+ if (mac_1[0] != mac_2[0])
+ {
+ return false;
+ }
+ if (mac_1[1] != mac_2[1])
+ {
+ return false;
+ }
+ if (mac_1[2] != mac_2[2])
+ {
+ return false;
+ }
+ if (mac_1[3] != mac_2[3])
+ {
+ return false;
+ }
+ if (mac_1[4] != mac_2[4])
+ {
+ return false;
+ }
+ if (mac_1[5] != mac_2[5])
+ {
+ return false;
+ }
+ #else
+ for (int i = 0; i < 6; i++)
+ {
+ if (mac_1[i] != mac_2[i])
+ {
+ //pc.printf("0x%02x != 0x%02x at %d\r\n", mac_1[i], mac_2[i], i);
+ return false;
+ }
+ else
+ {
+ //pc.printf("0x%02x == 0x%02x at %d\r\n", mac_1[i], mac_2[i], i);
+ }
+ }
+ #endif
+ return true;
+}
+
+int get_board_index(const Gap::Address_t mac)
+{
+ if (mac_equals(mac, mac_board_0))
+ {
+ return 0;
+ }
+ if (mac_equals(mac, mac_board_1))
+ {
+ return 1;
+ }
+ if (mac_equals(mac, mac_board_2))
+ {
+ return 2;
+ }
+
+ return -1;
+}
+
+void periodicCallback(void)
+{
+ alivenessLED = !alivenessLED; /* do blinky on alivenessLED while we're waiting for BLE events */
+}
+
+
+// Mixed role ****************************************************
+BLE ble;
+Gap::Address_t my_mac;
+int my_board_index = -1;
+
+// Device role ****************************************************
+UARTService * uartServicePtr = NULL;
+const static char DEVICE_NAME[] = "ChangeMe!!"; // change this
+static const uint16_t uuid16_list[] = {UARTServiceShortUUID};
+volatile int central_handle = -1;
+
+
+// Central role ****************************************************
+Gap::Handle_t connectionHandle = 0xFFFF;
+DiscoveredCharacteristic uartTXCharacteristic;
+DiscoveredCharacteristic uartRXCharacteristic;
+bool foundUartRXCharacteristic = false;
+volatile int device_handle = -1;
+
+
+// Device role ****************************************************
+void onReceivedDataFromCentralCallback(const GattWriteCallbackParams *params)
+{
+ if (uartServicePtr != NULL)
+ {
+ if ((params->handle == uartServicePtr->getTXCharacteristicHandle()) && (params->len >= 1))
+ {
+ if (params->data[0] != '0')
+ {
+ led = 1;
+ }
+ else
+ {
+ led = 0;
+ }
+
+ for(int i = 0; i < params->len; i++)
+ {
+ pc.printf("%c", params->data[i]);
+ }
+
+ pc.printf(" (%d, %d)\r\n", params->handle, params->connHandle);
+ }
+ }
+}
+
+// Central role ****************************************************
+void advertisementCallback(const Gap::AdvertisementCallbackParams_t *params)
+{
+ // do connections like a triangle
+ int peer_board_index = get_board_index(params->peerAddr);
+
+ int next_board_index = my_board_index + 1;
+ if (next_board_index >= BOARDS_COUNT)
+ {
+ next_board_index = 0;
+ }
+
+ //pc.printf("adv %d, %d, %d\r\n", peer_board_index, my_board_index, next_board_index);
+
+ // force order
+ if ((central_handle != -1) || (peer_board_index == 0))
+ {
+ if (peer_board_index == next_board_index)
+ {
+ //pc.printf("adv peerAddr[%02x %02x %02x %02x %02x %02x] rssi %d, isScanResponse %u, AdvertisementType %u\r\n",
+ // params->peerAddr[5], params->peerAddr[4], params->peerAddr[3], params->peerAddr[2], params->peerAddr[1], params->peerAddr[0],
+ // params->rssi, params->isScanResponse, params->type);
+
+ ble.gap().connect(params->peerAddr, Gap::ADDR_TYPE_RANDOM_STATIC, NULL, NULL);
+ }
+ }
+}
+
+void serviceDiscoveryCallback(const DiscoveredService *service)
+{
+ if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT)
+ {
+ pc.printf("S UUID-%x attrs[%u %u]\r\n", service->getUUID().getShortUUID(), service->getStartHandle(), service->getEndHandle());
+ }
+ else
+ {
+ //pc.printf("S UUID-");
+ const uint8_t *longUUIDBytes = service->getUUID().getBaseUUID();
+ for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++)
+ {
+ pc.printf("%02x", longUUIDBytes[i]);
+ }
+ pc.printf(" attrs[%u %u]\r\n", service->getStartHandle(), service->getEndHandle());
+ }
+}
+
+void characteristicDiscoveryCallback(const DiscoveredCharacteristic *characteristicP)
+{
+ //pc.printf(" C UUID-%x valueAttr[%u] props[%x]\r\n", characteristicP->getUUID().getShortUUID(), characteristicP->getValueHandle(), (uint8_t)characteristicP->getProperties().broadcast());
+ if (characteristicP->getUUID().getShortUUID() == UARTServiceTXCharacteristicShortUUID)
+ {
+ pc.printf("fit TX 0x%04x\r\n", UARTServiceTXCharacteristicShortUUID);
+ /* !ALERT! Alter this filter to suit your device. */
+ uartTXCharacteristic = *characteristicP;
+ }
+ else if (characteristicP->getUUID().getShortUUID() == UARTServiceRXCharacteristicShortUUID)
+ {
+ pc.printf("fit RX 0x%04x\r\n", UARTServiceRXCharacteristicShortUUID);
+ /* !ALERT! Alter this filter to suit your device. */
+ uartRXCharacteristic = *characteristicP;
+ foundUartRXCharacteristic = true;
+ }
+}
+
+void discoveryTerminationCallback(Gap::Handle_t connectionHandle)
+{
+ pc.printf("terminated SD for handle %u\r\n", connectionHandle);
+}
+
+void onReceivedDataFromDeviceCallback(const GattHVXCallbackParams *params)
+{
+ //pc.printf("received HVX callback for handle %u; type %s\r\r\n", params->handle, (params->type == BLE_HVX_NOTIFICATION) ? "notification" : "indication");
+ if (params->type == BLE_HVX_NOTIFICATION)
+ {
+ if ((params->handle == uartRXCharacteristic.getValueHandle()) && (params->len > 0))
+ {
+ for (int i = 0; i < params->len; i++)
+ {
+ pc.printf("%c", params->data[i]);
+ }
+
+ pc.printf(" (%d, %d)\r\n", params->handle, params->connHandle);
+ }
+ }
+ else
+ {
+ pc.printf("%d\r\n", params->type);
+ }
+}
+
+// Mixed role ****************************************************
+void connectionCallback(const Gap::ConnectionCallbackParams_t *params)
+{
+ if (params->role == Gap::CENTRAL)
+ {
+ if (central_handle == -1)
+ {
+ ble.stopAdvertising(); // stop advertising during discovery, incoming connection breaks discovery
+ }
+
+ device_handle = params->handle;
+ pc.printf("connected as central (handle = %d)\r\n\r", params->handle);
+ connectionHandle = params->handle;
+ ble.gattClient().onServiceDiscoveryTermination(discoveryTerminationCallback);
+ int ret = ble.gattClient().launchServiceDiscovery(params->handle, serviceDiscoveryCallback, characteristicDiscoveryCallback, UARTServiceShortUUID/*, 0xa001*/);
+
+ if (ret != BLE_ERROR_NONE)
+ {
+ pc.printf("launchServiceDiscovery failed error = %d\r\n\r", ret);
+ }
+ }
+ else
+ {
+ central_handle = params->handle;
+ pc.printf("connected as device (handle = %d)\r\n\r", params->handle);
+
+ //pc.printf("Conn. params => min=%d, max=%d, slave=%d, supervision=%d\r\n", params->connectionParams->minConnectionInterval, params->connectionParams->maxConnectionInterval, params->connectionParams->slaveLatency, params->connectionParams->connectionSupervisionTimeout);
+ /*
+ Gap::ConnectionParams_t connectionParams;
+ connectionParams.minConnectionInterval = 6;
+ connectionParams.maxConnectionInterval = 12;
+ connectionParams.slaveLatency = 40;
+ connectionParams.connectionSupervisionTimeout = 500;
+
+ int ret = ble.updateConnectionParams(params->handle, &connectionParams);
+ if (ret != BLE_ERROR_NONE)
+ {
+ pc.printf("failed to update connection parameter\r\n");
+ }
+ */
+ }
+ pc.printf("own %02x:%02x:%02x:%02x:%02x:%02x (%s), peer %02x:%02x:%02x:%02x:%02x:%02x (%s)\r\n", params->ownAddr[5], params->ownAddr[4], params->ownAddr[3], params->ownAddr[2], params->ownAddr[1], params->ownAddr[0], (params->ownAddrType == Gap::ADDR_TYPE_PUBLIC) ? "public" : "random", params->peerAddr[5], params->peerAddr[4], params->peerAddr[3], params->peerAddr[2], params->peerAddr[1], params->peerAddr[0], (params->peerAddrType == Gap::ADDR_TYPE_PUBLIC) ? "public" : "random");
+}
+
+void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
+{
+ char * ascii_reason = "?";
+ switch (reason)
+ {
+ case Gap::CONNECTION_TIMEOUT:
+ ascii_reason = "connection timeout";
+ break;
+ case Gap::REMOTE_USER_TERMINATED_CONNECTION:
+ ascii_reason = "user terminated connection";
+ break;
+ case Gap::REMOTE_DEV_TERMINATION_DUE_TO_LOW_RESOURCES:
+ ascii_reason = "low resources";
+ break;
+ case Gap::REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF:
+ ascii_reason = "power off";
+ break;
+ case Gap::LOCAL_HOST_TERMINATED_CONNECTION:
+ ascii_reason = "host terminated connection";
+ break;
+ case Gap::CONN_INTERVAL_UNACCEPTABLE:
+ ascii_reason = "interval unacceptable";
+ break;
+ default:
+ ascii_reason = "unknown";
+ break;
+ }
+
+ pc.printf("disconnected (reason = %s, handle = %d)\r\n", ascii_reason, handle);
+
+
+ if (handle == SOFT_DEVICE_FATHER_HANDLE)
+ {
+ central_handle = -1;
+ // restart advertising
+ ble.startAdvertising();
+ }
+ else
+ {
+ device_handle = -1;
+ // restart scan
+ ble.gap().startScan(advertisementCallback);
+ }
+}
+
+
+
+void serialTxCallback()
+{
+
+}
+
+int rx_char = -1;
+void serialRxCallback()
+{
+ if (rx_char != -1)
+ {
+ pc.printf("overflow\r\n");
+ }
+
+ //computer.putc(computer.getc());
+ rx_char = pc.getc();
+}
+
+/*
+void gattServerOnDataSent(unsigned count)
+{
+
+}
+*/
+
+
+int main(void)
+{
+ alivenessLED = 0;
+
+ pc.baud(115200);
+ //pc.attach(&serialTxCallback, Serial::TxIrq);
+ pc.attach(&serialRxCallback, Serial::RxIrq);
+
+ // clear terminal output
+ for (int k = 0; k < 32; k++)
+ {
+ pc.printf("\r\n");
+ }
+
+ pc.printf("Central and device\r\n");
+
+ Ticker ticker;
+ ticker.attach(periodicCallback, 1);
+
+
+ // Mixed role ****************************************************
+ ble.init();
+
+ Gap::AddressType_t my_mac_type;
+ ble.gap().getAddress(&my_mac_type, my_mac);
+ my_board_index = get_board_index(my_mac);
+ pc.printf("me %02x:%02x:%02x:%02x:%02x:%02x (%s)\r\n", my_mac[5], my_mac[4], my_mac[3], my_mac[2], my_mac[1], my_mac[0], (my_mac_type == Gap::ADDR_TYPE_PUBLIC) ? "public" : "random");
+
+
+ // try to speed up but looks like if it was ignored
+ Gap::ConnectionParams_t fast;
+ if (ble.getPreferredConnectionParams(&fast) != BLE_ERROR_NONE)
+ {
+ pc.printf("getPreferredConnectionParams failed\r\n");
+ }
+ else
+ {
+ fast.minConnectionInterval = 16; // 20 ms
+ fast.maxConnectionInterval = 32; // 40 ms
+ fast.slaveLatency = 0;
+ if (ble.gap().setPreferredConnectionParams(&fast) != BLE_ERROR_NONE)
+ {
+ pc.printf("setPreferredConnectionParams failed\r\n");
+ }
+ }
+ ble.gap().onConnection(connectionCallback);
+ ble.gap().onDisconnection(disconnectionCallback);
+
+ // Device role ****************************************************
+ ble.gattServer().onDataWritten(onReceivedDataFromCentralCallback);
+ //ble.gattServer().onDataSent(gattServerOnDataSent);
+
+ UARTService uartService(ble);
+ uartServicePtr = &uartService;
+
+ // setup advertising
+ ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); // BLE only, no classic BT
+ ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); // add name
+ ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); // UUID's broadcast in advertising packet
+ ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); // advertising type
+ ble.setAdvertisingInterval(100);
+
+ // Central role ****************************************************
+ ble.gattClient().onHVX(onReceivedDataFromDeviceCallback);
+ ble.gap().setScanParams(500, 450);
+
+
+ // start advertising and scan
+ ble.startAdvertising();
+ ble.gap().startScan(advertisementCallback);
+
+ while (true)
+ {
+ // allow notifications from device
+ if (foundUartRXCharacteristic && !ble.gattClient().isServiceDiscoveryActive())
+ {
+ foundUartRXCharacteristic = false; /* need to do the following only once */
+
+ uint16_t value = BLE_HVX_NOTIFICATION;
+ int ret = ble.gattClient().write(GattClient::GATT_OP_WRITE_REQ,
+ connectionHandle,
+ uartRXCharacteristic.getValueHandle() + 1, /* HACK Alert. We're assuming that CCCD descriptor immediately follows the value attribute. */
+ sizeof(uint16_t), /* HACK Alert! size should be made into a BLE_API constant. */
+ reinterpret_cast<const uint8_t *>(&value));
+
+ if (ret == BLE_ERROR_NONE)
+ {
+ pc.printf("\r\ndevice notifications enabled\r\n");
+ }
+ else
+ {
+ switch (ret)
+ {
+ case BLE_STACK_BUSY:
+ foundUartRXCharacteristic = true; // retry later
+ break;
+ case BLE_ERROR_NO_MEM:
+ foundUartRXCharacteristic = true; // retry later
+ break;
+ case BLE_ERROR_INVALID_STATE:
+ pc.printf("\r\ndevice notifications enable failed\r\n");
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!foundUartRXCharacteristic)
+ {
+ if (central_handle == -1)
+ {
+ ble.startAdvertising();
+ }
+ }
+ }
+
+ // while a new char from computer is available
+ while (rx_char != -1)
+ {
+ uint8_t temp[20];
+ int length = 1;
+
+ uint8_t command = rx_char;
+ rx_char = -1;
+
+ // if special char to test a 20 bytes frame
+ /*
+ if (command == '*')
+ {
+ pc.printf("20 chars\r\n");
+
+ int c = 0;
+ for (c = 0; c < 20; c++)
+ {
+ temp[c] = 'a' + c;
+ }
+ length = 20;
+ }
+ else
+ {
+ temp[0] = command;
+ }
+ */
+ temp[0] = command;
+
+ // to central
+ //if (command == '1')
+ {
+ if (central_handle != -1)
+ {
+ // device to central
+ while (1)
+ {
+ if (central_handle == -1)
+ {
+ pc.printf("\r\ndisconnected 1 (to central)\r\n");
+ break;
+ }
+ if (!ble.gap().getState().connected)
+ {
+ pc.printf("\r\ndisconnected 2 (to central)\r\n");
+ break;
+ }
+ int ret = ble.gattServer().write(uartServicePtr->getRXCharacteristicHandle(), temp, length);
+
+ if (ret == BLE_ERROR_NONE)
+ {
+ //pc.printf("\r\nok (to central)\r\n");
+ break;
+ }
+ else if (ret == BLE_STACK_BUSY)
+ {
+ //pc.printf("\r\nbusy (to central)\r\n");
+ //break;
+ }
+ else if (ret == BLE_ERROR_OPERATION_NOT_PERMITTED)
+ {
+ pc.printf("\r\nnot permitted (to central)\r\n");
+ break;
+ }
+ else if (ret == BLE_ERROR_INVALID_STATE)
+ {
+ pc.printf("\r\ninvalid state (to central)\r\n");
+ break;
+ }
+ else
+ {
+ pc.printf("\r\ncode %d (to central)\r\n", ret);
+ break;
+ }
+ }
+ }
+ else
+ {
+ pc.printf("\r\nnot connected with central\r\n");
+ }
+ }
+
+ // to device
+ //if (command == '2')
+ {
+ if (device_handle != -1)
+ {
+ // central to device
+ while (1)
+ {
+ if (device_handle == -1)
+ {
+ pc.printf("\r\ndisconnected (to device)\r\n");
+ break;
+ }
+ int ret = uartTXCharacteristic.write(length, temp);
+ if (ret == BLE_ERROR_NONE)
+ {
+ //pc.printf("\r\nok (to device)\r\n");
+ break;
+ }
+ else if (ret == BLE_STACK_BUSY)
+ {
+ //pc.printf("\r\nbusy (to device)\r\n");
+ //break;
+ }
+ else if (ret == BLE_ERROR_OPERATION_NOT_PERMITTED)
+ {
+ pc.printf("\r\nnot permitted (to device)\r\n");
+ break;
+ }
+ else if (ret == BLE_ERROR_INVALID_STATE)
+ {
+ pc.printf("\r\ninvalid state (to device)\r\n");
+ break;
+ }
+ else
+ {
+ pc.printf("\r\ncode %d (to device)\r\n", ret);
+ break;
+ }
+ }
+ }
+ else
+ {
+ pc.printf("\r\nnot connected with device\r\n");
+ }
+ }
+ }
+
+ ble.waitForEvent(); // save power
+ }
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/8_Uart_Server/main.cpp Sat Apr 14 04:56:34 2018 +0000
@@ -0,0 +1,585 @@
+/* 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.
+ */
+
+/*
+ * ------- BLE Peripheral/Server UART function --------------------------------
+ * communicate with BLE_UART_Client program
+ * --- Tested on Switch Science mbed TY51822r3 ---
+ *
+ * http://www.page.sannet.ne.jp/kenjia/index.html
+ * https://os.mbed.com/users/kenjiArai/
+ *
+ * Started: March 7th, 2016
+ * Revised: June 13th, 2016
+ * Revised: Feburary 10th, 2018 Not set mac addr but use device name
+ * Revised: Feburary 11th, 2018 use mbed-os5.7.4 with CircularBuffer
+ * Revised: April 14th, 2018 modification only for TYBLE16
+ *
+ * Original program:
+ * BLE_LoopbackUART
+ * https://developer.mbed.org/teams/Bluetooth-Low-Energy/
+ * code/BLE_LoopbackUART/
+ * Reference program:
+ * BLE_Peripheral_test by noboru koshinaka
+ * https://os.mbed.com/users/noboruk/code/BLE_Peripheral_test/
+ * Tested Client Device:
+ * BLE_Uart_Client
+ * https://os.mbed.com/users/kenjiArai/code/BLE_Uart_Client/
+ */
+
+//#define EXAMPLE_8_UART_SERVER
+#ifdef EXAMPLE_8_UART_SERVER
+
+// Include --------------------------------------------------------------------
+#include "mbed.h"
+#include "BLE.h"
+#include "UARTService.h"
+#include "nRF51_Vdd.h"
+#include "nRF51_WakeUp.h"
+#include "CircularBuffer.h"
+
+// Definition -----------------------------------------------------------------
+//#define USE_MAC // if you use mac address, please define it
+
+#define NUM_ONCE 20
+#define BFSIZE (NUM_ONCE+4)
+
+// Please refer nRF51_WakeUP library
+#define GOTO_SLEEP_MODE 0
+#if GOTO_SLEEP_MODE
+#warning "Make sure!! -> You need to connected P0_21(LED1) and P0_0"
+#endif
+
+//#define USE_DEBUG_MODE
+#ifdef USE_DEBUG_MODE
+#define DEBUG(...) { printf(__VA_ARGS__); }
+#else
+#define DEBUG(...)
+#endif
+
+// Object ---------------------------------------------------------------------
+BLE& ble_uart = BLE::Instance();
+DigitalOut connectedLED(LED1);
+//InterruptIn wake_up_sw(P0_1);
+//nRF51_WakeUp wakeup(P0_21, P0_0);
+nRF51_Vdd vdd(3.0f, 2.2f);
+Serial pc(USBTX, USBRX, 115200);
+//Serial pc(P0_3, P0_1, 115200); // for another board
+UARTService *uartServicePtr;
+Ticker ticker;
+CircularBuffer<char, 1536> ser_bf;
+Thread tsk;
+Mutex bletx_mutex;
+
+// ROM / Constant data --------------------------------------------------------
+#warning "You need to confirm your device name."
+const static char DEVICE_NAME[] = "UART_PJL";
+
+// RAM ------------------------------------------------------------------------
+Gap::Address_t my_mac;
+uint8_t tx_buf[BFSIZE];
+uint8_t tx_len = 0;
+uint8_t rx_buf[BFSIZE];
+volatile bool trigger_transmit = false;
+volatile bool trigger_receive = false;
+volatile uint8_t command_continue = 0;
+uint16_t time_out_cntr = 3600;
+volatile bool time_out = false;
+//uint32_t sleep_time = 30; // unit:second
+volatile bool rx_isr_busy = false;
+
+// Function prototypes --------------------------------------------------------
+// BLE
+void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *);
+void onDataWritten_action(const GattWriteCallbackParams *);
+// Tasks
+void pc_ser_rx(void);
+void data_from_ble(void);
+void Update_Values(void);
+// Application related
+void command(uint8_t *cmd);
+void action_tx_help(void);
+void action_tx_vdd(void);
+void action_tx_temperature(void);
+//void action_tx_wait_time(uint8_t *);
+void action_tx_quit(void);
+static int xatoi (char **, int32_t *);
+void adjust_line(uint8_t *);
+// Interrupt related
+//void interrupt_by_sw(void);
+void serialRxCallback(void);
+void periodicCallback(void);
+
+//------------------------------------------------------------------------------
+// Control Program
+//------------------------------------------------------------------------------
+int main(void)
+{
+ connectedLED = 0;
+ pc.attach(&serialRxCallback, Serial::RxIrq);
+ ticker.attach(periodicCallback, 1);
+ tsk.start(pc_ser_rx);
+ // clear terminal output
+ for (int k = 0; k < 3; k++) {
+ pc.printf("\r\n");
+ }
+ // opening message
+ pc.printf("UART Communication / Server(Peripheral) side\r\n");
+ pc.printf(" need Client module (run BLE_Uart_Client program)\r\n");
+ // Interrupt by switch
+// wake_up_sw.fall(&interrupt_by_sw);
+ ble_uart.init();
+ Gap::AddressType_t my_mac_type;
+ ble_uart.gap().getAddress(&my_mac_type, my_mac);
+ DEBUG(
+ " my_MAC %02x:%02x:%02x:%02x:%02x:%02x (%s)\r\n",
+ my_mac[5], my_mac[4], my_mac[3], my_mac[2], my_mac[1], my_mac[0],
+ (my_mac_type == Gap::ADDR_TYPE_PUBLIC) ? "public" : "random"
+ );
+ pc.printf(
+ " My device name : %s\r\n", DEVICE_NAME);
+ pc.printf(
+ " My mac data %02x:%02x:%02x:%02x:%02x:%02x\r\n",
+ my_mac[5], my_mac[4], my_mac[3], my_mac[2], my_mac[1], my_mac[0]
+ );
+#ifdef USE_MAC
+ pc.printf(
+ " mac_board_x = {0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x};\r\n",
+ my_mac[0], my_mac[1], my_mac[2], my_mac[3], my_mac[4], my_mac[5]
+ );
+ pc.printf(
+ " Please write above data(mac_board_x line (x=0,1,2,...))\r\n");
+ pc.printf(
+ " into Client/main.cpp [ROM / Constant data] area\r\n");
+#endif
+ ble_uart.onDisconnection(disconnectionCallback);
+ ble_uart.onDataWritten(onDataWritten_action);
+ /* setup advertising */
+ ble_uart.accumulateAdvertisingPayload(
+ GapAdvertisingData::BREDR_NOT_SUPPORTED);
+ ble_uart.setAdvertisingType(
+ GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
+ ble_uart.accumulateAdvertisingPayload(
+ GapAdvertisingData::COMPLETE_LOCAL_NAME,
+ (const uint8_t *)DEVICE_NAME,
+ sizeof(DEVICE_NAME)
+ );
+ ble_uart.accumulateAdvertisingPayload(
+ GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
+ (const uint8_t *)UARTServiceUUID_reversed,
+ sizeof(UARTServiceUUID_reversed)
+ );
+ // Advertize Interval
+ ble_uart.setAdvertisingInterval(1000); /* 1000ms;in multiples of 0.625ms.*/
+ // Start
+ ble_uart.startAdvertising();
+ UARTService uartService(ble_uart);
+ uartServicePtr = &uartService;
+ while(true) {
+ if (time_out) {
+#if GOTO_SLEEP_MODE
+ wakeup.set_and_wait(sleep_time);
+ while(true) { // never come here but just in case
+ deepsleep();
+ }
+#endif
+ }
+ if (trigger_transmit) {
+ static uint8_t cmd_buf[BFSIZE];
+ static volatile bool flag_continue = 0;
+ trigger_transmit = false;
+ pc.printf((const char*)rx_buf);
+ if (flag_continue == true) {
+ strcat((char *)cmd_buf, (char *)rx_buf);
+ if (strchr((const char*)cmd_buf,(int)'\r') == 0) {
+ flag_continue = true;
+ } else {
+ command(cmd_buf);
+ for(uint8_t i = 0; i < BFSIZE; i++) {
+ cmd_buf[i] = 0;
+ }
+ flag_continue = false;
+ }
+ }
+ if ((rx_buf[0] == '~')) {
+ strcpy((char *)cmd_buf, (char *)rx_buf);
+ if (strchr((const char*)cmd_buf,(int)'\r') == 0) {
+ flag_continue = true;
+ } else {
+ command(cmd_buf);
+ for(uint8_t i = 0; i < BFSIZE; i++) {
+ cmd_buf[i] = 0;
+ }
+ flag_continue = false;
+ }
+ }
+ }
+ ble_uart.waitForEvent();
+ }
+}
+
+void command(uint8_t *cmd)
+{
+ uint8_t *p = cmd;
+
+ while(*p == ' ') {
+ ++p; // skip space
+ }
+ if (*p++ == '~') {
+ while(*p < '!') {
+ ++p; // skip space
+ }
+ uint8_t c = *p;
+ //pc.printf("c=%c\r\n", c);
+ switch (c) {
+ case 'v':
+ action_tx_vdd();
+ break;
+ case 't':
+ action_tx_temperature();
+ break;
+ case 'q':
+ action_tx_quit();
+ break;
+#if 0
+ case 'w':
+ action_tx_wait_time(cmd);
+ break;
+#endif
+ case 'h':
+ case '?':
+ action_tx_help();
+ break;
+ default:
+ //pc.printf("\r\nStep(%u)\r\n", __LINE__);
+ break;
+ }
+ }
+}
+
+void periodicCallback(void)
+{
+#if GOTO_SLEEP_MODE
+ if (--time_out_cntr == 0) {
+ time_out = true;
+ }
+#endif
+ if (rx_isr_busy == true) {
+ rx_isr_busy = false;
+ } else {
+ tsk.signal_set(0x01);
+ }
+}
+
+void serialRxCallback()
+{
+ ser_bf.push(pc.getc());
+ rx_isr_busy = true;
+ tsk.signal_set(0x01);
+}
+
+void pc_ser_rx()
+{
+ static uint8_t linebf_irq[BFSIZE];
+ static volatile uint8_t linebf_irq_len = 0;
+
+ while(true) {
+ Thread::signal_wait(0x01);
+ if (ser_bf.empty()) {
+ if (linebf_irq_len != 0) {
+ linebf_irq[linebf_irq_len] = 0;
+ adjust_line(linebf_irq);
+ linebf_irq_len = 0;
+ bletx_mutex.lock();
+ ble_uart.updateCharacteristicValue(
+ uartServicePtr->getRXCharacteristicHandle(),
+ linebf_irq,
+ NUM_ONCE
+ );
+ bletx_mutex.unlock();
+ }
+ }
+ while(!ser_bf.empty()) {
+ char c;
+ ser_bf.pop(c);
+ if (c == '\b') {
+ linebf_irq_len--;
+ pc.putc(c);
+ pc.putc(' ');
+ pc.putc(c);
+ } else if ((c >= ' ') || (c == '\r') || (c == '\n')) {
+ bool overflow = false;
+ if ((c == '\r') || (c == '\n')) {
+ if (linebf_irq_len == NUM_ONCE - 1) { // remain only 1 buffer
+ overflow = true;
+ linebf_irq[linebf_irq_len++] = '\r';
+ pc.putc('\r');
+ } else {
+ overflow = false;
+ linebf_irq[linebf_irq_len++] = '\r';
+ linebf_irq[linebf_irq_len++] = '\n';
+ pc.printf("\r\n");
+ }
+ } else {
+ linebf_irq[linebf_irq_len++] = c;
+ pc.putc(c);
+ }
+ if (linebf_irq_len >= NUM_ONCE ) {
+ linebf_irq[linebf_irq_len] = 0;
+ adjust_line(linebf_irq);
+ linebf_irq_len = 0;
+ bletx_mutex.lock();
+ ble_uart.updateCharacteristicValue(
+ uartServicePtr->getRXCharacteristicHandle(),
+ linebf_irq,
+ NUM_ONCE
+ );
+ bletx_mutex.unlock();
+ if (overflow == true) {
+ overflow = false;
+ linebf_irq[linebf_irq_len++] = '\n';
+ pc.putc('\n');
+ }
+ }
+ }
+ }
+ }
+}
+
+void adjust_line(uint8_t *bf)
+{
+ uint8_t i, c;
+
+ for (i = 0; i <NUM_ONCE; bf++, i++) {
+ c = *bf;
+ if (c == 0) {
+ break;
+ }
+ }
+ for (; i < NUM_ONCE; bf++, i++) {
+ *bf = 0x11;
+ }
+ *(bf + 1) = 0;
+}
+
+void onDataWritten_action(const GattWriteCallbackParams *params)
+{
+ if ((uartServicePtr != NULL) &&
+ (params->handle == uartServicePtr->getTXCharacteristicHandle())) {
+ strcpy((char *)rx_buf, (const char *)params->data);
+ trigger_transmit = true;
+ }
+}
+
+void action_tx_help()
+{
+ // 12345678901234567890
+ sprintf((char *)tx_buf," ~?:help\r\n");
+ tx_len = strlen((const char *)tx_buf);
+ Update_Values();
+ Thread::wait(200);
+ // 12345678901234567890
+ sprintf((char *)tx_buf," ~v:vdd\r\n");
+ tx_len = strlen((const char *)tx_buf);
+ Update_Values();
+ Thread::wait(200);
+ // 12345678901234567890
+ sprintf((char *)tx_buf," ~t:temperature\r\n");
+ tx_len = strlen((const char *)tx_buf);
+ Update_Values();
+ Thread::wait(200);
+#if 0
+ // 12345678901234567890
+ sprintf((char *)tx_buf," ~w:wait, w 120\r\n");
+ tx_len = strlen((const char *)tx_buf);
+ Update_Values();
+ Thread::wait(200);
+#endif
+ // 12345678901234567890
+ sprintf((char *)tx_buf," ~q:quit/sleep\r\n");
+ tx_len = strlen((const char *)tx_buf);
+ Update_Values();
+ Thread::wait(200);
+}
+
+void action_tx_vdd()
+{
+ sprintf((char *)tx_buf,"Vdd: %3.2f V\r\n", vdd.read_real_value());
+ tx_len = strlen((const char *)tx_buf);
+ Update_Values();
+}
+
+void action_tx_temperature()
+{
+ int32_t p_temp;
+ float temperature;
+
+ // Update a temperature (inside nRF51822 chip)
+ sd_temp_get(&p_temp);
+ // -16.0f is offset vale for chip die temp
+ // to ambient temp (depend on your board)
+ temperature = float(p_temp) / 4; // Original = float(p_temp)/4.0f - 16.0f;
+ sprintf((char *)tx_buf,"T: %+4.1f dC\r\n", temperature);
+ tx_len = strlen((const char *)tx_buf);
+ Update_Values();
+}
+
+#if 0
+void action_tx_wait_time(uint8_t *cmd)
+{
+ int32_t dt;
+ char *p;
+
+ p = (char *)(cmd);
+ p += 2; // point to time value
+ if (xatoi(&p, &dt)) {
+ if (dt <= 5) {
+ dt = 5;
+ }
+ sleep_time = dt; // set next wake-up period
+ } else {
+ DEBUG("data is unknown!\r\n");
+ sleep_time = 30;
+ }
+ DEBUG("slp_t:%d\r\n", sleep_time);
+ //pc.printf("slp_t:%d\r\n", sleep_time);
+ // 12345678901234567890
+ sprintf((char *)tx_buf, "W: %d sec\r\n", sleep_time);
+ tx_len = strlen((const char *)tx_buf);
+ Update_Values();
+}
+#endif
+
+void action_tx_quit()
+{
+#if GOTO_SLEEP_MODE
+ ticker.detach();
+ // 12345678901234567890
+ sprintf((char *)tx_buf,"Terminated the BLE");
+ tx_len = strlen((const char *)tx_buf);
+ Update_Values();
+ Thread::wait(1000);
+ wakeup.set_and_wait(sleep_time);
+ while(true) { // never come here but just in case
+ deepsleep();
+ }
+#else
+ SCB->AIRCR = 0x05fa0004; // System RESET!!
+#endif
+}
+
+// Change string -> integer
+static int xatoi (char **str, int32_t *res)
+{
+ unsigned long val;
+ unsigned char c, radix, s = 0;
+
+ for (;;) {
+ c = **str;
+ if (c == 0) {
+ return 0;
+ }
+ if (c == '-') {
+ break;
+ }
+ if (c == '+') {
+ (*str)++;
+ c = **str;
+ }
+ if (c>='0'&& c<='9') {
+ break;
+ } else {
+ (*str)++;
+ c = **str;
+ }
+ }
+ if (c == '-') {
+ s = 1;
+ c = *(++(*str));
+ }
+ if (c == '0') {
+ c = *(++(*str));
+ if (c <= ' ') {
+ *res = 0;
+ return 1;
+ }
+ if (c == 'x') {
+ radix = 16;
+ c = *(++(*str));
+ } else {
+ if (c == 'b') {
+ radix = 2;
+ c = *(++(*str));
+ } else {
+ if ((c >= '0')&&(c <= '9')) {
+ radix = 8;
+ } else {
+ return 0;
+ }
+ }
+ }
+ } else {
+ if ((c < '1')||(c > '9')) {
+ return 0;
+ }
+ radix = 10;
+ }
+ val = 0;
+ while (c > ' ') {
+ if (c >= 'a') c -= 0x20;
+ c -= '0';
+ if (c >= 17) {
+ c -= 7;
+ if (c <= 9) return 0;
+ }
+ if (c >= radix) return 0;
+ val = val * radix + c;
+ c = *(++(*str));
+ }
+ if (s) val = -val;
+ *res = val;
+ return 1;
+}
+
+#if 0
+void interrupt_by_sw() // Go to sleep
+{
+ NVIC_SystemReset();
+ // Not come here (Just in case)
+ sleep();
+}
+#endif
+
+void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
+{
+ DEBUG("Disconnected!\r\n");
+ DEBUG("Restarting the advertising process\r\n");
+ ble_uart.startAdvertising();
+}
+
+void Update_Values(void)
+{
+ bletx_mutex.lock();
+ ble_uart.updateCharacteristicValue(
+ uartServicePtr->getRXCharacteristicHandle(),
+ tx_buf,
+ tx_len
+ );
+ bletx_mutex.unlock();
+ tx_len = 0;
+}
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/9_Monitor/debug_tools/debug_common.h Sat Apr 14 04:56:34 2018 +0000
@@ -0,0 +1,162 @@
+/*
+ * mbed Application program (part of debuf_xxx.cpp)
+ *
+ * Copyright (c) 2010-2014,'18 Kenji Arai / JH1PJL
+ * http://www.page.sannet.ne.jp/kenjia/index.html
+ * https://os.mbed.com/users/kenjiArai/
+ * Created: October 16th, 2014
+ * Revised: Nobember 30th, 2016
+ * Revised: April 14th, 2018
+ */
+
+// Include --------------------------------------------------------------------
+#include "mon_hw_common.h"
+
+// Definition -----------------------------------------------------------------
+#define BAUD(x) pc.baud(x)
+#define GETC(x) pc.getc(x)
+#define PUTC(x) pc.putc(x)
+#define PRINTF(...) pc.printf(__VA_ARGS__)
+#define READABLE(x) pc.readable(x)
+
+#define BAUD_RATE 9600
+
+// Object ---------------------------------------------------------------------
+extern Serial pc;
+
+// RAM ------------------------------------------------------------------------
+char linebuf[64];
+int buf_size = sizeof(linebuf);
+
+// ROM / Constant data --------------------------------------------------------
+char *const mon_msg =
+ "Debug Interface for mbed system, created on UTC: "__DATE__"("__TIME__")";
+
+// Function prototypes --------------------------------------------------------
+extern int mon_hw(void);
+extern void get_freq(int pr);
+
+//------------------------------------------------------------------------------
+// Control Program
+//------------------------------------------------------------------------------
+// Put \r\n
+void put_rn ( void )
+{
+ PUTC('\r');
+ PUTC('\n');
+}
+
+// Put \r
+void put_r ( void )
+{
+ PUTC('\r');
+}
+
+// Put ", "
+void put_lin ( void )
+{
+ PRINTF(", ");
+}
+
+// Put space n
+void put_spc( uint8_t n)
+{
+ for(; n > 0; n--) {
+ PUTC(' ');
+ }
+}
+
+// Change string -> integer
+int xatoi (char **str, int32_t *res)
+{
+ unsigned long val;
+ unsigned char c, radix, s = 0;
+
+ while ((c = **str) == ' ') (*str)++;
+ if (c == '-') {
+ s = 1;
+ c = *(++(*str));
+ }
+ if (c == '0') {
+ c = *(++(*str));
+ if (c <= ' ') {
+ *res = 0;
+ return 1;
+ }
+ if (c == 'x') {
+ radix = 16;
+ c = *(++(*str));
+ } else {
+ if (c == 'b') {
+ radix = 2;
+ c = *(++(*str));
+ } else {
+ if ((c >= '0')&&(c <= '9')) {
+ radix = 8;
+ } else {
+ return 0;
+ }
+ }
+ }
+ } else {
+ if ((c < '1')||(c > '9')) {
+ return 0;
+ }
+ radix = 10;
+ }
+ val = 0;
+ while (c > ' ') {
+ if (c >= 'a') c -= 0x20;
+ c -= '0';
+ if (c >= 17) {
+ c -= 7;
+ if (c <= 9) return 0;
+ }
+ if (c >= radix) return 0;
+ val = val * radix + c;
+ c = *(++(*str));
+ }
+ if (s) val = -val;
+ *res = val;
+ return 1;
+}
+
+void get_line_no_param (char *buff)
+{
+ get_line(buff, buf_size);
+}
+
+// RTC related subroutines
+static void chk_and_set_time(char *ptr)
+{
+//unsigned long p1;
+ int32_t p1;
+ static struct tm t;
+ time_t seconds;
+ char buf[40];
+
+ if (xatoi(&ptr, &p1)) {
+ t.tm_year = (uint8_t)p1 + 100;
+ PRINTF("Year:%d ",p1);
+ xatoi( &ptr, &p1 );
+ t.tm_mon = (uint8_t)p1 - 1;
+ PRINTF("Month:%d ",p1);
+ xatoi( &ptr, &p1 );
+ t.tm_mday = (uint8_t)p1;
+ PRINTF("Day:%d ",p1);
+ xatoi( &ptr, &p1 );
+ t.tm_hour = (uint8_t)p1;
+ PRINTF("Hour:%d ",p1);
+ xatoi( &ptr, &p1 );
+ t.tm_min = (uint8_t)p1;
+ PRINTF("Min:%d ",p1);
+ xatoi( &ptr, &p1 );
+ t.tm_sec = (uint8_t)p1;
+ PRINTF("Sec: %d \r\n",p1);
+ seconds = mktime(&t);
+ set_time(seconds);
+ }
+ seconds = time(NULL);
+ strftime(buf, 40, "%B %d,'%y, %H:%M:%S", localtime(&seconds));
+ PRINTF("Date: %s\r\n", buf);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/9_Monitor/debug_tools/debug_nRF5x.cpp Sat Apr 14 04:56:34 2018 +0000
@@ -0,0 +1,198 @@
+/*
+ * mbed Application program
+ *
+ * Copyright (c) 2016,'18 Kenji Arai / JH1PJL
+ * http://www.page.sannet.ne.jp/kenjia/index.html
+ * https://os.mbed.com/users/kenjiArai/
+ * Created: Feburary 1st, 2016
+ * Revised: Nobember 1st, 2016
+ * Revised: April 14th, 2018
+ *
+ */
+
+#if defined(TARGET_NRF51822)
+
+// Include --------------------------------------------------------------------
+#include "mbed.h"
+#include "debug_common.h"
+#include "nrf_soc.h" // for internal Thermo sensoer
+#include "nRF51_Vdd.h" // Read nRF5x Vdd voltage
+#include "nrf_delay.h"
+
+// Object ---------------------------------------------------------------------
+nRF51_Vdd vdd_mon(3.6f, 2.6f);
+DigitalOut p_out(LED1);
+
+// Definition -----------------------------------------------------------------
+
+// RAM ------------------------------------------------------------------------
+
+// ROM / Constant data --------------------------------------------------------
+
+// Function prototypes --------------------------------------------------------
+extern void cpu_sys(void);
+void debug_core(void);
+void ble_stack_stop(void);
+
+//------------------------------------------------------------------------------
+// Control Program
+//------------------------------------------------------------------------------
+// Help Massage
+void msg_hlp (void)
+{
+ PRINTF(mon_msg);
+ put_rn();
+ PRINTF("c - CPU VDD & Temp info");
+ put_rn();
+ PRINTF("l - Low current (Sleep Mode)");
+ put_rn();
+#if 0
+ PRINTF("t - Test Radio module");
+ put_rn();
+#endif
+ PRINTF("s - CPU system info");
+ put_rn();
+ PRINTF("r - Reset(by Software)");
+ put_rn();
+ PRINTF("x - Goto HW monitor");
+ put_rn();
+ PRINTF("q - Return to main");
+ put_rn();
+ PRINTF(" --- special function (1,2...) see debugging_nRF51.h");
+ put_rn();
+ PRINTF("1 - Try new function");
+ put_rn();
+}
+
+// ---------- Program starts here! ---------------------------------------------
+void debug_interface(uint8_t mode)
+{
+ BAUD(BAUD_RATE);
+ if (mode) {
+ debug_core();
+ } else {
+ if(READABLE()) {
+ unsigned char c = GETC(); // dummy read
+ debug_core();
+ }
+ }
+}
+
+void step_by_step(char c)
+{
+ PRINTF("Waiting key input");
+ while (!READABLE()) {
+ ;
+ }
+ PRINTF("--- step %c", c);
+ put_rn();
+ c = GETC(); // dummy read
+}
+
+void debug_core(void)
+{
+ char *ptr;
+ int32_t p_temp;
+ float temperature;
+
+ uint32_t n;
+
+ put_rn();
+ put_rn();
+ PRINTF("%s [Help:'?' key]", mon_msg);
+ put_rn();
+ for (;;) {
+ put_r();
+ PUTC('>');
+ ptr = linebuf;
+ get_line(ptr, sizeof(linebuf));
+ put_r();
+ switch (*ptr++) {
+ //--------------------------------------------------------------
+ // CPU VDD Voltage and Chip temperature
+ //--------------------------------------------------------------
+ case 'c' :
+ NRF_TEMP->TASKS_START = 1;
+ while (NRF_TEMP->EVENTS_DATARDY == 0) {
+ ;
+ }
+ NRF_TEMP->EVENTS_DATARDY = 0;
+ if ((NRF_TEMP->TEMP & 0x00000200) != 0) {
+ p_temp = (NRF_TEMP->TEMP | 0xFFFFFC00);
+ } else {
+ p_temp = NRF_TEMP->TEMP;
+ }
+ NRF_TEMP->TASKS_STOP = 1; // Stop the temperature measurement
+ temperature = (float)p_temp / 4.0f;
+ PRINTF("nRF5x\r\nChip temperature: %+4.1fdegC", temperature);
+ put_rn();
+ // Vdd voltage
+ PRINTF("Vdd: %4.3fV", vdd_mon.read_real_value());
+ put_rn();
+ break;
+ //--------------------------------------------------------------
+ // Something new and try new functions
+ //--------------------------------------------------------------
+
+ // Please see following file
+#include "debugging_nRF5x.h"
+
+ //--------------------------------------------------------------
+ // Go to Low current (Sleep mode)
+ //--------------------------------------------------------------
+ case 'l' :
+ PRINTF("Enter Sleep mode (Please push RESET button)");
+ put_rn();
+ while(true) {
+ sleep();
+ //__WFI();
+ //__WFE();
+ }
+ // SCB->AIRCR = 0x05fa0004; // System RESET!!
+ //break;
+ //--------------------------------------------------------------
+ // CPU system info
+ //--------------------------------------------------------------
+ case 's' :
+ cpu_sys();
+ break;
+ //--------------------------------------------------------------
+ // System reset
+ //--------------------------------------------------------------
+ case 'r' :
+ SCB->AIRCR = 0x05fa0004; // System RESET!!
+ // Not come here (Just in case)
+ deepsleep();
+ break;
+ //--------------------------------------------------------------
+ // help
+ //--------------------------------------------------------------
+ case '?' :
+ msg_hlp();
+ break;
+ //--------------------------------------------------------------
+ // Go to special command
+ //--------------------------------------------------------------
+ case 'x' :
+ mon_hw();
+ PRINTF("->Came back monitor\r\n");
+ break;
+ //--------------------------------------------------------------
+ // Go back to main()
+ //--------------------------------------------------------------
+ case 'q' : // Quit
+ PRINTF("\rReturn to main\r\n");
+ //PRINTF("cannot control anymore from here\r\n");
+ return;
+ //--------------------------------------------------------------
+ // no support
+ //--------------------------------------------------------------
+ default:
+ PUTC('?');
+ put_rn();
+ break;
+ }
+ }
+}
+
+#endif // defined(TARGET_NRF51822)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/9_Monitor/debug_tools/debugging_nRF5x.h Sat Apr 14 04:56:34 2018 +0000
@@ -0,0 +1,218 @@
+/*
+ * mbed Application program
+ *
+ * Copyright (c) 2016,'18Kenji Arai / JH1PJL
+ * http://www.page.sannet.ne.jp/kenjia/index.html
+ * https://os.mbed.com/users/kenjiArai/
+ * Created: Feburary 1st, 2016
+ * Revised: Feburary 18th, 2016
+ * Revised: April 14th, 2018
+ *
+ */
+
+//------------------------------------------------------------------------------
+// Something new and try new functions
+//------------------------------------------------------------------------------
+#define NRF_RTC2_BASE 0x40024000UL
+#define NRF_RTC2 ((NRF_RTC_Type *) NRF_RTC2_BASE)
+#define MAX_RTC_TASKS_DELAY 47 //Maximum delay until an RTC task is executed
+
+// You do NOT need switch() sentence!!
+
+case '1' :
+step_by_step('1');
+sd_power_system_off();
+step_by_step('2');
+NRF_RTC2->PRESCALER = 0; /* for no pre-scaling. */
+NRF_RTC2->TASKS_START = 1;
+n = NRF_RTC2->COUNTER;
+wait(0.1);
+if ( n == NRF_RTC2->COUNTER)
+{
+ PRINTF("RTC2 is not running\r\n");
+} else
+{
+ PRINTF("RTC2 is running & counter = %d\r\n", n);
+}
+step_by_step('3');
+n = NRF_RTC2->COUNTER;
+wait(0.1);
+if ( n == NRF_RTC2->COUNTER)
+{
+ PRINTF("RTC2 is not running\r\n");
+} else
+{
+ PRINTF("RTC2 is running & counter = %d\r\n", n);
+}
+step_by_step('4');
+n = NRF_RTC0->COUNTER;
+wait(0.1);
+if ( n == NRF_RTC0->COUNTER)
+{
+ PRINTF("RTC0 is not running\r\n");
+} else
+{
+ PRINTF("RTC0 is running & counter = %d\r\n", n);
+}
+n = NRF_RTC1->COUNTER;
+wait(0.1);
+if ( n == NRF_RTC1->COUNTER)
+{
+ PRINTF("RTC1 is not running\r\n");
+ NRF_RTC1->PRESCALER = 0; /* for no pre-scaling. */
+ NRF_RTC1->TASKS_START = 1;
+ wait(0.5);
+ n = NRF_RTC1->COUNTER;
+ wait(0.1);
+ if ( n == NRF_RTC1->COUNTER) {
+ PRINTF("RTC1 is not running\r\n");
+ } else {
+ PRINTF("RTC1 is running & counter = %d\r\n", n);
+ }
+} else
+{
+ PRINTF("RTC1 is running & counter = %d\r\n", n);
+}
+break;
+case '2' :
+step_by_step('1');
+// Stop Radio
+NRF_RADIO->SHORTS = 0;
+NRF_RADIO->EVENTS_DISABLED = 0;
+NRF_RADIO->TEST = 0;
+NRF_RADIO->TASKS_DISABLE = 1;
+while (NRF_RADIO->EVENTS_DISABLED == 0)
+{
+ ;// Do nothing.
+}
+NRF_RADIO->EVENTS_DISABLED = 0;
+// Set RTC1 for wake-up
+NVIC_ClearPendingIRQ(RTC1_IRQn);
+NVIC_DisableIRQ(RTC1_IRQn);
+NRF_RTC1->TASKS_STOP = 1;
+nrf_delay_us(MAX_RTC_TASKS_DELAY);
+NRF_RTC1->TASKS_CLEAR = 1;
+nrf_delay_us(MAX_RTC_TASKS_DELAY);
+NRF_RTC1->INTENCLR = RTC_INTENSET_COMPARE0_Msk;
+NRF_RTC1->EVTENCLR = RTC_EVTEN_COMPARE0_Msk;
+NRF_RTC1->INTENCLR = RTC_INTENSET_OVRFLW_Msk;
+NRF_RTC1->EVTENCLR = RTC_EVTEN_OVRFLW_Msk;
+NRF_RTC1->EVENTS_COMPARE[0] = 0;
+NRF_RTC1->EVTENCLR = 0x000f0003; // all clear
+NRF_RTC1->EVTENSET = RTC_EVTEN_COMPARE0_Msk;
+NRF_RTC1->PRESCALER = 4095;
+// Set wake-up time
+NRF_RTC1->CC[0] = 50;
+// GPIOE
+NRF_GPIO->PIN_CNF[21] =
+ (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
+ | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
+ | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
+ | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
+ | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
+NRF_GPIOTE->CONFIG[0] =
+ (GPIOTE_CONFIG_POLARITY_LoToHi << GPIOTE_CONFIG_POLARITY_Pos)
+ | (21 << GPIOTE_CONFIG_PSEL_Pos)
+ | (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos);
+// Set PPI
+NRF_PPI->CH[0].EEP = (uint32_t)&NRF_RTC1->EVENTS_COMPARE[0];
+NRF_PPI->CH[0].TEP = (uint32_t)&NRF_GPIOTE->TASKS_OUT[0];
+// Enable only PPI channels 0
+NRF_PPI->CHEN = PPI_CHEN_CH0_Enabled << PPI_CHEN_CH0_Pos;
+// Restart RTC1
+NRF_RTC1->TASKS_START = 1;
+nrf_delay_us(MAX_RTC_TASKS_DELAY);
+// DEBUG
+PRINTF("NRF_RTC1->PRESCALER=0x%x\r\n", NRF_RTC1->PRESCALER);
+PRINTF("NRF_RTC1->EVTEN=0x%x\r\n", NRF_RTC1->EVTEN);
+PRINTF("NRF_RTC1->COUNTER=0x%x\r\n", NRF_RTC1->COUNTER);
+PRINTF("NRF_RTC1->EVENTS_COMPARE[0]=0x%x\r\n", NRF_RTC1->EVENTS_COMPARE[0]);
+PRINTF("NRF_RTC1->CC[0]=0x%x\r\n", NRF_RTC1->CC[0]);
+do
+{
+ PRINTF("NRF_RTC1->EVENTS_COMPARE[0]=");
+ PRINTF("%d", NRF_RTC1->EVENTS_COMPARE[0]);
+ PRINTF(" %d", NRF_RTC1->CC[0]);
+ PRINTF(" %d\r\n", NRF_RTC1->COUNTER);
+ nrf_delay_us(125000);
+} while(NRF_RTC1->EVENTS_COMPARE[0] == 0);
+PRINTF("NRF_RTC1->EVENTS_COMPARE[0]=");
+PRINTF("%d", NRF_RTC1->EVENTS_COMPARE[0]);
+PRINTF(" %d", NRF_RTC1->CC[0]);
+PRINTF(" %d\r\n", NRF_RTC1->COUNTER);
+step_by_step('4');
+// GPIOE
+NRF_GPIO->PIN_CNF[21] =
+ (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
+ | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
+ | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
+ | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
+ | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
+NRF_GPIOTE->CONFIG[0] =
+ (GPIOTE_CONFIG_POLARITY_LoToHi << GPIOTE_CONFIG_POLARITY_Pos)
+ | (21 << GPIOTE_CONFIG_PSEL_Pos)
+ | (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos);
+// RTC1
+NRF_RTC1->TASKS_STOP = 1;
+NRF_RTC1->EVENTS_COMPARE[0] = 0;
+NRF_RTC1->EVTENCLR = 0x000f0003; // all clear
+NRF_RTC1->EVTENSET = RTC_EVTEN_COMPARE0_Msk;
+NRF_RTC1->TASKS_CLEAR = 1;
+NRF_RTC1->CC[0] = 100;
+NRF_RTC1->PRESCALER = 4095;
+do
+{
+ NRF_RTC1->TASKS_STOP = 1;
+ NRF_RTC1->PRESCALER = 4095;
+ PRINTF("Retry PRESCALER setting\r\n");
+} while (NRF_RTC1->PRESCALER != 4095);
+PRINTF("NRF_RTC1->PRESCALER=0x%x\r\n", NRF_RTC1->PRESCALER);
+PRINTF("NRF_RTC1->EVTEN=0x%x\r\n", NRF_RTC1->EVTEN);
+PRINTF("NRF_RTC1->COUNTER=0x%x\r\n", NRF_RTC1->COUNTER);
+PRINTF("NRF_RTC1->EVENTS_COMPARE[0]=0x%x\r\n", NRF_RTC1->EVENTS_COMPARE[0]);
+PRINTF("NRF_RTC1->CC[0]=0x%x\r\n", NRF_RTC1->CC[0]);
+// PPI
+NRF_PPI->CH[0].EEP = (uint32_t)&NRF_RTC1->EVENTS_COMPARE[0];
+NRF_PPI->CH[0].TEP = (uint32_t)&NRF_GPIOTE->TASKS_OUT[0];
+// Enable only PPI channels 0
+NRF_PPI->CHEN = PPI_CHEN_CH0_Enabled << PPI_CHEN_CH0_Pos;
+NRF_RTC1->TASKS_START = 1;
+do
+{
+ PRINTF("NRF_RTC1->EVENTS_COMPARE[0]=");
+ PRINTF("%d", NRF_RTC1->EVENTS_COMPARE[0]);
+ PRINTF(" %d", NRF_RTC1->CC[0]);
+ PRINTF(" %d\r\n", NRF_RTC1->COUNTER);
+} while(NRF_RTC1->EVENTS_COMPARE[0] == 0);
+PRINTF("NRF_RTC1->EVENTS_COMPARE[0]=");
+PRINTF("%d", NRF_RTC1->EVENTS_COMPARE[0]);
+PRINTF(" %d", NRF_RTC1->CC[0]);
+PRINTF(" %d\r\n", NRF_RTC1->COUNTER);
+break;
+case '3' :
+step_by_step('x');
+p_out = 1;
+step_by_step('y');
+p_out = 0;
+step_by_step('z');
+for (int8_t n =0; n < 20; n++)
+{
+ p_out = 1;
+ wait_ms(100);
+ p_out = 0;
+ wait_ms(100);
+}
+break;
+case '4' :
+PRINTF("Please make your own command!!\r\n");
+PRINTF("Please see 9_Monitor\debug_tool\debugging_nRF5x.h\r\n");
+PRINTF("line:%d\r\n", __LINE__);
+step_by_step('x');
+;
+step_by_step('y');
+;
+step_by_step('z');
+;
+break;
+
+// You don't need any terminate bracket such as '}'
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/9_Monitor/debug_tools/mon_hw_common.h Sat Apr 14 04:56:34 2018 +0000
@@ -0,0 +1,59 @@
+/*
+ * mbed Headder file for Hardware Monitor
+ *
+ * Copyright (c) 2014,'18 Kenji Arai / JH1PJL
+ * http://www.page.sannet.ne.jp/kenjia/index.html
+ * https://os.mbed.com/users/kenjiArai/
+ * Created: June 1st, 2014
+ * Revised: Nobember 2nd, 2014
+ * Revised: April 14th, 2018
+ *
+ */
+
+// Object --------------------------------------------------------------------
+extern Serial pc;
+
+// Definition -----------------------------------------------------------------
+#define BAUD_RATE 9600
+
+#define BAUD(x) pc.baud(x)
+#define GETC(x) pc.getc(x)
+#define PUTC(x) pc.putc(x)
+#define PRINTF(...) pc.printf(__VA_ARGS__)
+#define READABLE(x) pc.readable(x)
+
+// Range check status
+#define ERR_NOTHING 0
+#define ERR_MODIFY_SIZ 1
+#define ERR_OUT_OF_RANGE 2
+
+// Reg. Size
+#define SIZE8 8
+#define SIZE16 16
+#define SIZE32 32
+#define SIZE_FULL 32
+#define SIZE_X 32
+
+// RAM ------------------------------------------------------------------------
+extern char linebuf[];
+extern int buf_size;
+
+#if USE_MEM
+typedef struct {
+ int32_t mstr;
+ int32_t msiz;
+ int32_t mtmp;
+ int32_t mold;
+ uint8_t mflg;
+ uint8_t mbhw;
+} MEMO;
+static MEMO mem;
+#endif
+
+// Function prototypes --------------------------------------------------------
+extern void put_rn ( void );
+extern void put_r ( void );
+extern void put_lin ( void );
+extern void put_spc( uint8_t n);
+extern void get_line (char *buff, int len);
+extern int xatoi (char **str, int32_t *res);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/9_Monitor/debug_tools/mon_hw_config.h Sat Apr 14 04:56:34 2018 +0000 @@ -0,0 +1,33 @@ +/* + * mbed Headder file for Hardware Monitor + * + * Copyright (c) 2014,'16,'18 Kenji Arai / JH1PJL + * http://www.page.sannet.ne.jp/kenjia/index.html + * https://os.mbed.com/users/kenjiArai/ + * Created: June 1st, 2014 + * Revised: Feburary 13th, 2016 + * Revised: April 14th, 2018 + * + */ + +// CPU nRF51822 / mbed nRF51822, mbed Nano, mbed which is used nRF51822 chip +// mon_hw_config.h mon_hw_mem.h mon_hw_nRF51.cpp + +#ifndef _MON_HW_CONF_H_ +#define _MON_HW_CONF_H_ + +// Definition ----------------------------------------------------------------- +// Please select each function for your purpose (selected = set 1) + +#define USE_MEM 1 +#define USE_PORT 1 +#define USE_FREQ 1 +#define USE_UART 1 +#define USE_SPI 1 +#define USE_I2C 1 +#define USE_ADC 1 +#define USE_TIMER 1 +#define USE_SYS 1 +#define USE_POWER 1 + +#endif // _MON_HW_CONF_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/9_Monitor/debug_tools/mon_hw_mem.h Sat Apr 14 04:56:34 2018 +0000
@@ -0,0 +1,242 @@
+/*
+ * Monitor program / Memory control part
+ *
+ * Copyright (c) 2010-2014,'16,'18 Kenji Arai / JH1PJL
+ * http://www.page.sannet.ne.jp/kenjia/index.html
+ * https://os.mbed.com/users/kenjiArai/
+ * Separated: October 13th, 2014 from mon_hw.cpp
+ * Revised: Feburary 4th, 2016
+ * Revised: April 14th, 2018
+ *
+ */
+
+//------------------------------------------------------------------------------
+// Control Program
+//------------------------------------------------------------------------------
+static void mem_cnfg_init( uint8_t print )
+{
+ uint32_t a, b, c;
+
+ a = NRF_FICR->CODEPAGESIZE;
+ b = NRF_FICR->CODESIZE;
+ c = a * b;
+ mem_range[0][1] = mem_range[0][0] + c -1;
+ if (print) {
+ PRINTF("CODEPAGESIZE:%d, CODESIZE:%d\r\nFLASH:0x%08x-0x%08x\r\n",
+ a, b, mem_range[0][0], mem_range[0][1]);
+ }
+ a = NRF_FICR->NUMRAMBLOCK;
+ b = NRF_FICR->SIZERAMBLOCKS;
+ c = a * b;
+ mem_range[1][1] = mem_range[1][0] + c -1;
+ if (print) {
+ PRINTF("NUMRAMBLOCK:%d, SIZERAMBLOCKS:%d\r\nRAM: 0x%08x-0x%08x\r\n",
+ a, b, mem_range[1][0], mem_range[1][1]);
+ }
+}
+
+// Range check for Memory dump
+static void check_range( MEMO * mem )
+{
+ uint8_t i;
+ uint32_t m;
+
+ mem->mflg = ERR_NOTHING;
+ for ( i = 0 ; i < 6 ; i++ ) {
+ if ( mem->mstr >= mem_range[i][0]) {
+ if ( mem->mstr < mem_range[i][1] ) {
+ m = mem->mstr + mem->msiz;
+ if ( m < mem_range[i][1]) {
+ return; // no modification
+ } else {
+ m = mem_range[i][1];
+ mem->msiz = m - mem->mstr + 1;
+ mem->mflg = ERR_MODIFY_SIZ;
+ return; // modified size
+ }
+ }
+ }
+ }
+ mem->mflg = ERR_OUT_OF_RANGE;
+ mem->mstr = 0;
+ mem->msiz = 0;
+ return ;
+}
+
+// Memory dump error massage
+void error_print ( unsigned char flg )
+{
+ switch (flg) {
+ case ERR_MODIFY_SIZ :
+ put_r();
+ PRINTF("Reach to out of range");
+ put_rn();
+ break;
+ case ERR_OUT_OF_RANGE :
+ put_r();
+ PRINTF("Not in a memory area");
+ put_rn();
+ break;
+ case ERR_NOTHING :
+ default :
+ ;
+ }
+}
+
+// Print memory contents
+void put_dump (const unsigned char *buff, unsigned long ofs, int cnt)
+{
+ int n;
+
+ PRINTF("%08lX ", ofs);
+ for(n = 0; n < cnt; n++) { // show hex
+ PRINTF(" %02X", buff[n]);
+ }
+ for(; n < 16; n++) { // fullfil remained space
+ PRINTF(" ");
+ }
+ PUTC(' ');
+ for(n = 0; n < cnt; n++) { // show char
+ if ((buff[n] < 0x20)||(buff[n] >= 0x7F)) {
+ PUTC('.');
+ } else {
+ PUTC(buff[n]);
+ }
+ }
+ put_rn();
+}
+
+// dump memory with error check
+void dump_w_err_ckeck ( char **ptr, MEMO * mem )
+{
+ check_range (mem);
+ for (*ptr=(char*)mem->mstr; mem->msiz >= 16; *ptr += 16, mem->msiz -= 16) {
+ put_r();
+ put_dump((unsigned char*)*ptr, (unsigned int)*ptr, 16);
+ }
+ if (mem->msiz) {
+ put_dump((unsigned char*)*ptr, (unsigned int)*ptr, mem->msiz);
+ }
+ error_print(mem->mflg);
+}
+
+static void mem_inf (char *ptr)
+{
+ put_r();
+ PRINTF("Mem. Mode d <address> [<count>], s, <ret> or f, q, ?");
+ put_rn();
+ mem_cnfg_init(0);
+ mem.mstr = mem_range[0][0]; // default start address = Flash
+ mem.msiz =256;
+ mem.mold = 0;
+ mem.mtmp = 0;
+ mem.mflg = 0;
+ for (; mem.mflg != 0xff;) {
+ PRINTF("m>");
+ ptr = linebuf;
+ get_line(ptr, buf_size);
+ put_r();
+ switch(*ptr++) {
+ case 'd' : // d <address> [<count>] - Dump memory
+ mem.mtmp = mem.mstr;
+ if (!xatoi(&ptr, &mem.mstr)) {
+ mem.mstr = mem.mtmp;
+ }
+ if (!xatoi(&ptr, &mem.msiz)) {
+ mem.msiz = 256;
+ }
+ mem.mtmp = mem.msiz;
+ dump_w_err_ckeck(&ptr, &mem);
+ mem.mold = mem.mstr;
+ mem.mstr += mem.mtmp;
+ break;
+ case 'f' : // next
+ case 'n' :
+ case 0x0d :
+ mem.msiz = 256;
+ mem.mtmp = mem.msiz;
+ dump_w_err_ckeck(&ptr, &mem);
+ mem.mold = mem.mstr;
+ mem.mstr += 256;
+ break;
+ case 'q' : // quit
+ mem.mflg = 0xff;
+ break;
+ case 'b' : // Back to more
+ if (mem.mold == 0) {
+ ;
+ } else {
+ mem.mold -= 256;
+ }
+ case 'k' : // keep previous address
+ mem.mstr = mem.mold;
+ mem.msiz = 256;
+ mem.mtmp = mem.msiz;
+ dump_w_err_ckeck(&ptr, &mem);
+ mem.mstr += 256;
+ break;
+ case 'a' : // start RAM top
+ mem.mstr = mem_range[1][0];
+ mem.msiz =256;
+ mem.mold = 0;
+ mem.mtmp = 0;
+ mem.mflg = 0;
+ dump_w_err_ckeck(&ptr, &mem);
+ mem.mstr += 256;
+ break;
+ case 'o' : // start ROM top
+ mem.mstr = mem_range[0][0];
+ mem.msiz =256;
+ mem.mold = 0;
+ mem.mtmp = 0;
+ mem.mflg = 0;
+ dump_w_err_ckeck(&ptr, &mem);
+ mem.mstr += 256;
+ break;
+ case 's' :
+ PRINTF("Memory Configuration");
+ put_rn();
+ PRINTF("%s0x%08lx to 0x%08lx ",
+ rmsg0, mem_range[0][0], mem_range[0][1]);
+ put_rn();
+ PRINTF("%s0x%08lx to 0x%08lx ",
+ rmsg1, mem_range[1][0], mem_range[1][1]);
+ put_rn();
+ PRINTF("%s0x%08lx to 0x%08lx ",
+ rmsg2, mem_range[2][0], mem_range[2][1]);
+ put_rn();
+ PRINTF("%s0x%08lx to 0x%08lx ",
+ rmsg3, mem_range[3][0], mem_range[3][1]);
+ put_rn();
+ PRINTF("%s0x%08lx to 0x%08lx ",
+ rmsg4, mem_range[4][0], mem_range[4][1]);
+ put_rn();
+ PRINTF("%s0x%08lx to 0x%08lx ",
+ rmsg5, mem_range[5][0], mem_range[5][1]);
+ put_rn();
+ break;
+ case '?' :
+ PRINTF("d <address> [<count>] - Dump memory");
+ put_rn();
+ PRINTF("s - Show memory structure ");
+ put_rn();
+ PRINTF("o - Dump memory / start from ROM top");
+ put_rn();
+ PRINTF("a - Dump memory / start from RAM top");
+ put_rn();
+ PRINTF("k - Dump memory / keep same 256bytes");
+ put_rn();
+ PRINTF("b - Dump memory / before 256bytes");
+ put_rn();
+ PRINTF("<RET> or f, n - Dump memory / next 256bytes");
+ put_rn();
+ PRINTF("q - Exit memory mode");
+ put_rn();
+ break;
+ default:
+ PUTC('?');
+ put_rn();
+ }
+ }
+ PRINTF("Return to All Mode");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/9_Monitor/debug_tools/mon_hw_nRF5x.cpp Sat Apr 14 04:56:34 2018 +0000
@@ -0,0 +1,1227 @@
+/*
+ * mbed Application program for the mbed nRF51 series
+ *
+ * Copyright (c) 2016,'18 Kenji Arai / JH1PJL
+ * http://www.page.sannet.ne.jp/kenjia/index.html
+ * https://os.mbed.com/users/kenjiArai/
+ * Created: Feburary 1st, 2016
+ * Revised: Feburary 18th, 2016
+ * Revised: April 14th, 2018
+ *
+ */
+
+#if defined(TARGET_NRF51822)
+
+// Include --------------------------------------------------------------------
+#include "mbed.h"
+#include "mon_hw_config.h"
+#include "mon_hw_common.h"
+#include "TYBLE16_BASE.h"
+
+// Object ---------------------------------------------------------------------
+
+// Definition -----------------------------------------------------------------
+#define SIMPLE_NOT_SHOW 1 // 1=Simple
+
+// RAM ------------------------------------------------------------------------
+uint32_t SystemFrequency;
+#if USE_MEM
+// Memory range data (This is special case: save in RAM area! (others mbed's are in FLASH))
+// follows are only initial data and check FICR data for ROM & RAM size
+uint32_t mem_range[][2] = { // Memory access range
+ // On-chip non-volatile memory //128 or 256KB Flash
+ { 0x00000000, 0x0003ffff },
+ // On-chip SRAM //16 or 32KB RAM
+ { 0x20000000, 0x20007fff },
+ { 0x10000000, 0x1000007f }, // FICR
+ { 0x10001000, 0x100010ff }, // UICR
+ { 0x40000000, 0x400245ff }, // Peripheral
+ { 0x50000500, 0x500007ff } // GPIO
+};
+#endif // USE_MEM
+
+// ROM / Constant data --------------------------------------------------------
+char *const mon_msg =
+ "HW monitor only for mbed nRF51 series created on "__DATE__","__TIME__"";
+
+char *const xmsg0 = "Not implimented yet";
+char *const hmsg0 = "m - Entry Memory Mode";
+char *const hmsg1 = "m>? -> Help ";
+char *const hmsg2 = "r - Show I2C,SPI,UART,Timer,ADC Reg.";
+char *const hmsg3 = "r>? -> Help";
+char *const hmsg4 = "c - CPU information";
+char *const hmsg5 = "f - Show Clock frequency";
+char *const hmsg6 = "p - GPIO information";
+char *const hmsg7 = "w - Power management";
+char *const hmsg8 = "x - Special command for Debug";
+char *const hmsg9 = "q - Quit (back to called routine)";
+
+// Function prototypes --------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// Control Program
+//------------------------------------------------------------------------------
+// No function
+void not_yet_impliment( void )
+{
+ put_r();
+ PRINTF(xmsg0);
+ put_rn();
+}
+
+// No function
+#if (USE_MEM==0)||(USE_PORT==0)||(USE_UART==0)|| \
+ (USE_SPI==0)||(USE_I2C==0)||(USE_SYS==0)
+void not_select( void )
+{
+ PRINTF("Not select the function (refer mon_hw_config.h)");
+ put_rn();
+}
+#endif
+
+// Help Massage
+void msg_hlp_hw (void)
+{
+ PRINTF(mon_msg);
+ put_rn();
+ PRINTF(hmsg0);
+ put_rn();
+ PRINTF(hmsg1);
+ put_rn();
+ PRINTF(hmsg2);
+ put_rn();
+ PRINTF(hmsg3);
+ put_rn();
+ PRINTF(hmsg4);
+ put_rn();
+ PRINTF(hmsg5);
+ put_rn();
+ PRINTF(hmsg6);
+ put_rn();
+ PRINTF(hmsg7);
+ put_rn();
+ PRINTF(hmsg8);
+ put_rn();
+ PRINTF(hmsg9);
+ put_rn();
+}
+
+#if USE_MEM
+char *const rmsg0 = "FLASH ";
+char *const rmsg1 = "SRAM ";
+char *const rmsg2 = "FIR ";
+char *const rmsg3 = "UIR ";
+char *const rmsg4 = "Peripheral ";
+char *const rmsg5 = "GPIO ";
+
+#include "mon_hw_mem.h"
+#endif // USE_MEM
+
+// Show Xbit register contents
+void reg_print(uint16_t size, uint16_t reg)
+{
+ uint16_t i, j, k, n;
+
+ if (size == 8) {
+ PRINTF(" 7, 6, 5, 4, 3, 2, 1, 0");
+ put_rn();
+ i = 8;
+ n = 0x80;
+ } else if (size == 16) {
+ PRINTF( "15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0" );
+ put_rn();
+ i = 16;
+ n = 0x8000;
+ } else {
+ PRINTF("0x%08x", reg);
+ return;
+ }
+ PUTC(' ');
+ for (; i>0; i--) {
+ k = n >> (size-i);
+ j = reg & k;
+ if (j) {
+ PUTC('1');
+ } else {
+ PUTC('0');
+ }
+ PUTC(' ');
+ PUTC(' ');
+ }
+ PRINTF(" (0x%04x)", reg);
+}
+
+uint8_t bit_position(uint32_t x)
+{
+ uint8_t n;
+
+ for (n = 0; n < 32; n++) {
+ x = x >> 1UL;
+ if (x & 0x1) {
+ break;
+ }
+ }
+ return n;
+}
+
+#if USE_FREQ
+void freq_reg(void)
+{
+ uint32_t r0;
+
+// NRF_CLOCK->TASKS_HFCLKSTART = 0xffffffff;
+// NRF_CLOCK->HFCLKRUN = 0x00010001;
+
+ put_r();
+ // Start HFCLK clock source
+ r0 = NRF_CLOCK->TASKS_HFCLKSTART;
+ PRINTF( "TASKS_HFCLKSTART:" );
+ reg_print(SIZE32, r0);
+ put_rn();
+ // Stop HFCLK clock source
+ r0 = NRF_CLOCK->TASKS_HFCLKSTOP;
+ PRINTF( "TASKS_HFCLKSTOP: " );
+ reg_print(SIZE32, r0);
+ put_rn();
+ // Start LFCLK clock source
+ r0 = NRF_CLOCK->TASKS_LFCLKSTART;
+ PRINTF( "TASKS_LFCLKSTART:" );
+ reg_print(SIZE32, r0);
+ put_rn();
+ // Stop LFCLK clock source
+ r0 = NRF_CLOCK->TASKS_LFCLKSTOP;
+ PRINTF( "TASKS_LFCLKSTOP: " );
+ reg_print(SIZE32, r0);
+ put_rn();
+ // Start calibration of LFCLK RC oscillator
+ r0 = NRF_CLOCK->TASKS_CAL;
+ PRINTF( "TASKS_CAL: " );
+ reg_print(SIZE32, r0);
+ put_rn();
+ // Start calibration timer
+ r0 = NRF_CLOCK->TASKS_CTSTART;
+ PRINTF( "TASKS_CTSTART: " );
+ reg_print(SIZE32, r0);
+ put_rn();
+ // Stop calibration timer
+ r0 = NRF_CLOCK->TASKS_CTSTOP;
+ PRINTF( "TASKS_CTSTOP: " );
+ reg_print(SIZE32, r0);
+ put_rn();
+ // HFCLK oscillator started
+ r0 = NRF_CLOCK->EVENTS_HFCLKSTARTED;
+ PRINTF( "EVENTS_HFCLKSTARTED:" );
+ reg_print(SIZE32, r0);
+ put_rn();
+ // LFCLK oscillator started
+ r0 = NRF_CLOCK->EVENTS_LFCLKSTARTED;
+ PRINTF( "EVENTS_LFCLKSTARTED:" );
+ reg_print(SIZE32, r0);
+ put_rn();
+ // Calibration of LFCLK RC oscillator completed
+ r0 = NRF_CLOCK->EVENTS_DONE;
+ PRINTF( "EVENTS_DONE: " );
+ reg_print(SIZE32, r0);
+ put_rn();
+ // Calibration timer timeout
+ r0 = NRF_CLOCK->EVENTS_CTTO;
+ PRINTF( "EVENTS_CTTO: " );
+ reg_print(SIZE32, r0);
+ put_rn();
+ // Interrupt enable set register
+ r0 = NRF_CLOCK->INTENSET;
+ PRINTF( "INTENSET: " );
+ reg_print(SIZE32, r0);
+ put_rn();
+ // Interrupt enable clear register
+ r0 = NRF_CLOCK->INTENCLR;
+ PRINTF( "INTENCLR: " );
+ reg_print(SIZE32, r0);
+ put_rn();
+ // Task HFCLKSTART trigger status
+ r0 = NRF_CLOCK->HFCLKRUN;
+ PRINTF( "HFCLKRUN: " );
+ reg_print(SIZE32, r0);
+ put_rn();
+ // high frequency clock status
+ r0 = NRF_CLOCK->HFCLKSTAT;
+ PRINTF( "HFCLKSTAT: " );
+ reg_print(SIZE32, r0);
+ put_rn();
+ // Task LFCLKSTART trigger status
+ r0 = NRF_CLOCK->LFCLKRUN;
+ PRINTF( "LFCLKRUN: " );
+ reg_print(SIZE32, r0);
+ put_rn();
+ // Low frequency clock status
+ r0 = NRF_CLOCK->LFCLKSTAT;
+ PRINTF( "LFCLKSTAT: " );
+ reg_print(SIZE32, r0);
+ put_rn();
+ // lock source for the LFCLK clock
+ r0 = NRF_CLOCK->LFCLKSRCCOPY;
+ PRINTF( "LFCLKSRCCOPY: " );
+ reg_print(SIZE32, r0);
+ put_rn();
+ // Clock source for the LFCLK clock
+ r0 = NRF_CLOCK->LFCLKSRC;
+ PRINTF( "LFCLKSRC: " );
+ reg_print(SIZE32, r0);
+ put_rn();
+ // Calibration timer interval
+ r0 = NRF_CLOCK->CTIV;
+ PRINTF( "CTIV: " );
+ reg_print(SIZE32, r0);
+ put_rn();
+ // Crystal frequency
+ r0 = NRF_CLOCK->XTALFREQ;
+ PRINTF( "XTALFREQ: " );
+ reg_print(SIZE32, r0);
+ put_rn();
+}
+#endif // USE_FREQ
+
+#if USE_PORT
+void port_all(void)
+{
+ uint32_t p0, p1;
+ uint8_t n;
+
+ put_r();
+ PRINTF( "GPIO registers" );
+ put_rn();
+ p0 = NRF_GPIO->OUTSET;
+ PRINTF( "OUT: " );
+ reg_print(SIZE32, p0);
+ PRINTF( " ;0=L, 1=H" );
+ put_rn();
+ p0 = NRF_GPIO->IN;
+ PRINTF( "IN: " );
+ reg_print(SIZE32, p0);
+ PRINTF(" ;0=L, 1=H");
+ put_rn();
+ p0 = NRF_GPIO->DIRSET;
+ PRINTF("DIR: ");
+ reg_print(SIZE32, p0);
+ PRINTF(" ;0=in,1=out");
+ put_rn();
+ PRINTF("Dc=Disconnect,Cn=Connect,Ot=Out,Dis=Disabled,PU=Pullup,");
+ PRINTF("PD=Pulldown,Hi=High,Lo=Low");
+ for (n=0; n < 32; n++) {
+ put_rn();
+ p0 = NRF_GPIO->PIN_CNF[n];
+ PRINTF("P0_%02d: DIR=", n);
+ if (p0 & 0x1) {
+ PRINTF("Ot");
+ } else {
+ PRINTF("In");
+ }
+ PRINTF(", IN=");
+ if (p0 & 0x2) {
+ PRINTF("Dc");
+ } else {
+ PRINTF("Cn");
+ }
+ PRINTF(", PULL=");
+ p1 = (p0 >> 2) & 0x3;
+ switch (p1) {
+ case 0:
+ PRINTF("Dis");
+ break;
+ case 1:
+ PRINTF("PD ");
+ break;
+ case 3:
+ PRINTF("PU ");
+ break;
+ default:
+ PRINTF("? ");
+ break;
+ }
+ PRINTF(", Drive=");
+ p1 = (p0 >> 8) & 0x7;
+ switch (p1) {
+ case 0:
+ PRINTF("S0S1");
+ break;
+ case 1:
+ PRINTF("H0S1");
+ break;
+ case 2:
+ PRINTF("S0H1");
+ break;
+ case 3:
+ PRINTF("H0H1");
+ break;
+ case 4:
+ PRINTF("D0S1");
+ break;
+ case 5:
+ PRINTF("D0H1");
+ break;
+ case 6:
+ PRINTF("S0D1");
+ break;
+ case 7:
+ PRINTF("H0D1");
+ break;
+ default:
+ PRINTF("? ");
+ break;
+ }
+ PRINTF(", SENSE=");
+ p1 = (p0 >> 16) & 0x3;
+ switch (p1) {
+ case 0:
+ PRINTF("Dis");
+ break;
+ case 2:
+ PRINTF("Hi ");
+ break;
+ case 3:
+ PRINTF("Lo ");
+ break;
+ default:
+ PRINTF("? ");
+ break;
+ }
+ }
+}
+#endif // USE_PORT
+
+#if USE_UART
+void uart_reg(void)
+{
+ uint32_t p0, p1;
+
+ put_r();
+ PRINTF("Registers/UART");
+ put_rn();
+ p0 = NRF_UART0->ENABLE;
+ p1 = p0 & 0x7;
+ PRINTF("UART is ");
+ if (p1 == 4) {
+ PRINTF("enabled");
+ put_rn();
+ p0 = NRF_UART0->BAUDRATE;
+ switch(p0) {
+ case UART_BAUDRATE_BAUDRATE_Baud1200:
+ p1 = 1200;
+ break;
+ case UART_BAUDRATE_BAUDRATE_Baud2400:
+ p1 = 2400;
+ break;
+ case UART_BAUDRATE_BAUDRATE_Baud4800:
+ p1 = 4800;
+ break;
+ case UART_BAUDRATE_BAUDRATE_Baud9600:
+ p1 = 9600;
+ break;
+ case UART_BAUDRATE_BAUDRATE_Baud14400:
+ p1 = 14400;
+ break;
+ case UART_BAUDRATE_BAUDRATE_Baud19200:
+ p1 = 19200;
+ break;
+ case UART_BAUDRATE_BAUDRATE_Baud28800:
+ p1 = 28800;
+ break;
+ case UART_BAUDRATE_BAUDRATE_Baud38400:
+ p1 = 38400;
+ break;
+ case UART_BAUDRATE_BAUDRATE_Baud57600:
+ p1 = 576000;
+ break;
+ case UART_BAUDRATE_BAUDRATE_Baud76800:
+ p1 = 76800;
+ break;
+ case UART_BAUDRATE_BAUDRATE_Baud115200:
+ p1 = 115200;
+ break;
+ case UART_BAUDRATE_BAUDRATE_Baud230400:
+ p1 = 230400;
+ break;
+ case UART_BAUDRATE_BAUDRATE_Baud250000:
+ p1 = 250000;
+ break;
+ case UART_BAUDRATE_BAUDRATE_Baud460800:
+ p1 = 460800;
+ break;
+ case UART_BAUDRATE_BAUDRATE_Baud921600:
+ p1 = 921600;
+ break;
+ case UART_BAUDRATE_BAUDRATE_Baud1M:
+ PRINTF("Baud rate: 1M");
+ p1 = 1;
+ break;
+ default:
+ PRINTF("Baud rate: Unknown");
+ p1 = 0;
+ }
+ if (p1 > 10) {
+ PRINTF("Baud rate: %dbps", p1);
+ }
+ put_rn();
+ p0 = NRF_UART0->PSELTXD;
+ PRINTF("TXD Pin: ");
+ if (p0 == 0xffffffff) {
+ PRINTF("Unknown");
+ } else {
+ PRINTF("P0_%02d", p0);
+ }
+ put_rn();
+ p0 = NRF_UART0->PSELRXD;
+ PRINTF("RXD Pin: ");
+ if (p0 == 0xffffffff) {
+ PRINTF("Unknown");
+ } else {
+ PRINTF("P0_%02d", p0);
+ }
+ put_rn();
+ p0 = NRF_UART0->PSELRTS;
+ PRINTF("RTS Pin: ");
+ if (p0 == 0xffffffff) {
+ PRINTF("Unknown");
+ } else {
+ PRINTF("P0_%02d", p0);
+ }
+ put_rn();
+ p0 = NRF_UART0->PSELCTS;
+ PRINTF("CTS Pin: ");
+ if (p0 == 0xffffffff) {
+ PRINTF("Unknown");
+ } else {
+ PRINTF("P0_%02d", p0);
+ }
+#if SIMPLE_NOT_SHOW
+ put_rn();
+ p0 = NRF_UART0->SHORTS;
+ PRINTF("SHORTS: ");
+ reg_print(SIZE32, p0);
+ put_rn();
+ p0 = NRF_UART0->ERRORSRC;
+ PRINTF("ERRORSRC:");
+ reg_print(SIZE32, p0);
+#endif
+ } else {
+ PRINTF("disabled");
+ }
+ put_rn();
+}
+#endif //USE_UART
+
+#if USE_SPI
+void spi_reg(uint8_t n)
+{
+ uint32_t r0, r1, r2, r3;
+
+ put_r();
+ PRINTF("Registers/SPI");
+ put_rn();
+ if (n == 0) {
+ r0 = NRF_SPI0->ENABLE;
+ PRINTF("SPI0 is ");
+ } else {
+ r0 = NRF_SPI1->ENABLE;
+ PRINTF("SPI1 is ");
+ }
+ r1 = r0 & 0x7;
+ if (r1 == 1) {
+ PRINTF("enabled");
+ put_rn();
+ if (n == 0) {
+ r0 = NRF_SPI0->FREQUENCY;
+ r1 = NRF_SPI0->PSELMOSI;
+ r2 = NRF_SPI0->PSELMISO;
+ r3 = NRF_SPI0->PSELSCK;
+ } else {
+ r0 = NRF_SPI1->FREQUENCY;
+ r1 = NRF_SPI1->PSELMOSI;
+ r2 = NRF_SPI1->PSELMISO;
+ r3 = NRF_SPI1->PSELSCK;
+ }
+ PRINTF("Clock:");
+ switch(r0) {
+ case SPI_FREQUENCY_FREQUENCY_K125:
+ PRINTF("125k");
+ break;
+ case SPI_FREQUENCY_FREQUENCY_K250:
+ PRINTF("250k");
+ break;
+ case SPI_FREQUENCY_FREQUENCY_K500:
+ PRINTF("500k");
+ break;
+ case SPI_FREQUENCY_FREQUENCY_M1:
+ PRINTF("1M");
+ break;
+ case SPI_FREQUENCY_FREQUENCY_M2:
+ PRINTF("2M");
+ break;
+ case SPI_FREQUENCY_FREQUENCY_M4:
+ PRINTF("4M");
+ break;
+ case SPI_FREQUENCY_FREQUENCY_M8:
+ PRINTF("8M");
+ break;
+ default:
+ PRINTF("Unknown");
+ }
+ PRINTF("bps");
+ put_rn();
+ PRINTF("MOSI Pin: ");
+ if (r1 == 0xffffffff) {
+ PRINTF("Unknown");
+ } else {
+ PRINTF("P0_%02d", r1);
+ }
+ put_rn();
+ PRINTF("MISO Pin: ");
+ if (r2 == 0xffffffff) {
+ PRINTF("Unknown");
+ } else {
+ PRINTF("P0_%02d", r2);
+ }
+ put_rn();
+ PRINTF("SCK Pin: ");
+ if (r3 == 0xffffffff) {
+ PRINTF("Unknown");
+ } else {
+ PRINTF("P0_%02d", r3);
+ }
+ } else {
+ PRINTF("disabled");
+ }
+ put_rn();
+}
+#endif //USE_SPI
+
+#if USE_ADC
+#if 0
+void adc_reg(void)
+{
+ uint32_t r0, r1;
+
+ put_r();
+ PRINTF("Registers/ADC");
+ put_rn();
+ r0 = NRF_ADC->ENABLE;
+ r1 = r0 & 0x3;
+ if (r1 == 1) {
+ PRINTF("enabled");
+ put_rn();
+#if 1
+ put_rn();
+ PRINTF("RES : ");
+ reg_print(SIZE32, NRF_ADC->RES);
+ put_rn();
+ PRINTF("INPSEL: ");
+ reg_print(SIZE32, NRF_ADC->INPSEL);
+ PRINTF("REFSEL: ");
+ reg_print(SIZE32, NRF_ADC->REFSEL);
+ put_rn();
+ PRINTF("PSEL : ");
+ reg_print(SIZE32, NRF_ADC->PSEL);
+ PRINTF("EXTREFSEL: ");
+ reg_print(SIZE32, NRF_ADC->EXTREFSEL);
+ put_rn();
+#endif
+ } else {
+ PRINTF("disabled");
+ }
+ put_rn();
+}
+#else
+
+#if 0
+TASKS_START; // Start an ADC conversion. */
+TASKS_STOP; // Stop ADC. */
+EVENTS_END; // ADC conversion complete. */
+INTENSET; // Interrupt enable set register. */
+INTENCLR; // Interrupt enable clear register. */
+BUSY; // ADC busy register. */
+ENABLE; // ADC enable. */
+CONFIG; // ADC configuration register. */
+RESULT; // Result of ADC conversion. */
+POWER; // Peripheral power control.
+#endif
+
+void adc_reg(void)
+{
+ uint32_t r0, r1;
+
+ put_r();
+ PRINTF("Registers/ADC");
+ put_rn();
+ PRINTF("TASKS_START: ");
+ reg_print(SIZE32, NRF_ADC->TASKS_START);
+ put_rn();
+ PRINTF("TASKS_STOP : ");
+ reg_print(SIZE32, NRF_ADC->TASKS_STOP);
+ put_rn();
+ PRINTF("EVENTS_END : ");
+ reg_print(SIZE32, NRF_ADC->EVENTS_END);
+ put_rn();
+ PRINTF("INTENSET : ");
+ reg_print(SIZE32, NRF_ADC->INTENSET);
+ put_rn();
+ PRINTF("INTENCLR : ");
+ reg_print(SIZE32, NRF_ADC->INTENCLR);
+ put_rn();
+ PRINTF("BUSY : ");
+ reg_print(SIZE32, NRF_ADC->BUSY);
+ put_rn();
+ PRINTF("ENABLE : ");
+ reg_print(SIZE32, NRF_ADC->ENABLE);
+ put_rn();
+ PRINTF("CONFIG : ");
+ reg_print(SIZE32, NRF_ADC->CONFIG);
+ put_rn();
+ PRINTF("RESULT : ");
+ reg_print(SIZE32, NRF_ADC->RESULT);
+ put_rn();
+ PRINTF("POWER : ");
+ reg_print(SIZE32, NRF_ADC->POWER);
+ put_rn();
+ // judge each condition
+ r0 = NRF_ADC->ENABLE;
+ r1 = r0 & 0x3;
+ PRINTF("ADC is ");
+ if (r1 == 1) {
+ PRINTF("enabled");
+ } else {
+ PRINTF("disabled");
+ }
+ put_rn();
+ r0 = NRF_ADC->CONFIG;
+ r1 = r0 & 0x03;
+ PRINTF("Resolution : ");
+ if (r1 == 0) {
+ PRINTF("8bit");
+ } else if (r1 == 1) {
+ PRINTF("9bit");
+ } else if (r1 == 2) {
+ PRINTF("10bit");
+ }
+ put_rn();
+ r1 = (r0 & 0x1c) >> 2;
+ PRINTF("INPSEL: ");
+ switch (r1) {
+ case 0:
+ PRINTF("Pin specified by CONFIG.PSEL with no prescaling");
+ break;
+ case 1:
+ PRINTF("Pin specified by CONFIG.PSEL with 2/3 prescaling");
+ break;
+ case 2:
+ PRINTF("Pin specified by CONFIG.PSEL with 1/3 prescaling");
+ break;
+ case 5:
+ PRINTF("VDD with 2/3 prescaling");
+ break;
+ case 6:
+ PRINTF("VDD with 1/3 prescaling");
+ break;
+ default:
+ PRINTF("???");
+ break;
+ }
+ put_rn();
+ r1 = (r0 & 0x60) >> 6;
+ PRINTF("REFSEL: ");
+ switch (r1) {
+ case 0:
+ PRINTF("VBG // Use internal 1.2 V band gap reference");
+ break;
+ case 1:
+ PRINTF("External // Use external ");
+ PRINTF("reference specified by CONFIG. EXTREFSEL");
+ break;
+ case 2:
+ PRINTF("SupplyOneHalfPrescaling // Use VDD with 1/2 prescaling");
+ break;
+ case 3:
+ PRINTF("SupplyOneThirdPrescaling // Use VDD with 1/3 prescaling");
+ break;
+ default:
+ PRINTF("???");
+ break;
+ }
+ put_rn();
+ r1 = (r0 & 0xff00) >> 8;
+ PRINTF("PSEL: ");
+ switch (r1) {
+ case 0:
+ PRINTF("Disabled");
+ break;
+ case 1:
+ PRINTF("AnalogInput0");
+ break;
+ case 2:
+ PRINTF("AnalogInput1");
+ break;
+ case 4:
+ PRINTF("AnalogInput2");
+ break;
+ case 8:
+ PRINTF("AnalogInput3");
+ break;
+ case 16:
+ PRINTF("AnalogInput4");
+ break;
+ case 32:
+ PRINTF("AnalogInput5");
+ break;
+ case 64:
+ PRINTF("AnalogInput6");
+ break;
+ case 128:
+ PRINTF("AnalogInput7");
+ break;
+ default:
+ PRINTF("???");
+ break;
+ }
+ put_rn();
+}
+#endif
+#endif //USE_ADC
+
+#if 0
+TASKS_STARTRX; //Start 2-Wire master receive sequence
+TASKS_STARTTX; //Start 2-Wire master transmit sequence
+TASKS_STOP; //Stop 2-Wire transaction
+TASKS_SUSPEND; //Suspend 2-Wire transaction
+TASKS_RESUME; //Resume 2-Wire transaction
+EVENTS_STOPPED; //Two-wire stopped
+EVENTS_RXDREADY;//Two-wire ready to deliver new RXD byte received
+EVENTS_TXDSENT; //Two-wire finished sending last TXD byte
+EVENTS_ERROR; //Two-wire error detected
+EVENTS_BB; //Two-wire byte boundary
+EVENTS_SUSPENDED;//Two-wire suspended
+SHORTS; //Shortcuts for TWI
+INTENSET; //Interrupt enable set register
+INTENCLR; //Interrupt enable clear register
+ERRORSRC; //Two-wire error source. Write error field to 1 to clear error
+ENABLE; //Enable two-wire master
+PSELSCL; //Pin select for SCL
+PSELSDA; //Pin select for SDA
+RXD; //RX data register
+TXD; //TX data register
+FREQUENCY; //Two-wire frequency
+ADDRESS;// Address used in the two-wire transfer. */
+POWER;//Peripheral power control.
+#endif
+
+#if USE_I2C
+void i2c_reg(uint8_t n)
+{
+ uint32_t r0, r1, r2;
+#if SIMPLE_NOT_SHOW
+ uint32_t r3, r4;
+#endif
+
+ put_r();
+ PRINTF("Registers/TWI(I2C)");
+ put_rn();
+ if (n == 0) {
+ r0 = NRF_TWI0->ENABLE;
+ PRINTF("TWI0 is ");
+ } else {
+ r0 = NRF_TWI1->ENABLE;
+ PRINTF("TWI1 is ");
+ }
+ r1 = r0 & 0x7;
+ if (r1 == 5) {
+ PRINTF("enabled");
+ put_rn();
+ if (n == 0) {
+ r0 = NRF_TWI0->FREQUENCY;
+ r1 = NRF_TWI0->PSELSCL;
+ r2 = NRF_TWI0->PSELSDA;
+#if SIMPLE_NOT_SHOW
+ r3 = NRF_TWI0->SHORTS;
+ r4 = NRF_TWI0->ERRORSRC;
+#endif
+ } else {
+ r0 = NRF_TWI1->FREQUENCY;
+ r1 = NRF_TWI1->PSELSCL;
+ r2 = NRF_TWI1->PSELSDA;
+#if SIMPLE_NOT_SHOW
+ r3 = NRF_TWI1->SHORTS;
+ r4 = NRF_TWI1->ERRORSRC;
+#endif
+ }
+ PRINTF("Clock: ");
+ if (r0 == TWI_FREQUENCY_FREQUENCY_K100) {
+ PRINTF("100KHz");
+ } else if (p0 == TWI_FREQUENCY_FREQUENCY_K250) {
+ PRINTF("250KHz");
+ } else if (p0 == TWI_FREQUENCY_FREQUENCY_K400) {
+ PRINTF("400KHz");
+ } else {
+ PRINTF("Unknown");
+ }
+ put_rn();
+ PRINTF("SCL Pin: ");
+ if (r1 == 0xffffffff) {
+ PRINTF("Unknown");
+ } else {
+ PRINTF("P0_%02d", r1);
+ }
+ put_rn();
+ PRINTF("SDA Pin: ");
+ if (r2 == 0xffffffff) {
+ PRINTF("Unknown");
+ } else {
+ PRINTF("P0_%02d", r2);
+ }
+#if SIMPLE_NOT_SHOW
+ put_rn();
+ PRINTF("SHORTS: ");
+ reg_print(SIZE32, r3);
+ put_rn();
+ PRINTF("ERRORSRC:");
+ reg_print(SIZE32, r4);
+#endif
+ } else {
+ PRINTF("disabled");
+ }
+ put_rn();
+}
+#endif //USE_I2C
+
+#if USE_POWER
+void power_reg(void)
+{
+ put_r();
+ PRINTF("POWER Management");
+ put_rn();
+ // Enable low power mode (variable latency)
+ PRINTF("TASKS_CONSTLAT:");
+ reg_print(SIZE32, NRF_POWER->TASKS_CONSTLAT);
+ put_rn();
+ // Enable low power mode (variable latency)
+ PRINTF("TASKS_LOWPWR: ");
+ reg_print(SIZE32, NRF_POWER->TASKS_LOWPWR);
+ put_rn();
+ // Power failure warning
+ PRINTF("EVENTS_POFWARN:");
+ reg_print(SIZE32, NRF_POWER->EVENTS_POFWARN);
+ put_rn();
+ // Interrupt enable set register
+ PRINTF("INTENSET: ");
+ reg_print(SIZE32, NRF_POWER->INTENSET);
+ put_rn();
+ // Interrupt enable clear register
+ PRINTF("INTENCLR: ");
+ reg_print(SIZE32, NRF_POWER->INTENCLR);
+ put_rn();
+ // Reset reason
+ PRINTF("RESETREAS: ");
+ reg_print(SIZE32, NRF_POWER->RESETREAS);
+ put_rn();
+ // Ram status register
+ PRINTF("RAMSTATUS: ");
+ reg_print(SIZE32, NRF_POWER->RAMSTATUS);
+ put_rn();
+ // System off register
+ PRINTF("SYSTEMOFF: ");
+ reg_print(SIZE32, NRF_POWER->SYSTEMOFF);
+ put_rn();
+ // Power failure configuration
+ PRINTF("POFCON: ");
+ reg_print(SIZE32, NRF_POWER->POFCON);
+ put_rn();
+ // General purpose retention register
+ PRINTF("GPREGRET: ");
+ reg_print(SIZE32, NRF_POWER->GPREGRET);
+ put_rn();
+ // Ram on/off
+ PRINTF("RAMON: ");
+ reg_print(SIZE32, NRF_POWER->RAMON);
+ put_rn();
+ // Ram on/off
+ PRINTF("RAMONB: ");
+ reg_print(SIZE32, NRF_POWER->RAMONB);
+ put_rn();
+ // DCDC converter enable configuration register
+ PRINTF("DCDCEN: ");
+ reg_print(SIZE32, NRF_POWER->DCDCEN);
+ put_rn();
+ // DCDC power-up force register
+ PRINTF("DCDCFORCE: ");
+ reg_print(SIZE32, NRF_POWER->DCDCFORCE);
+ put_rn();
+}
+#endif //USE_TIMER
+
+#if USE_POWER
+void timer_reg(uint8_t n)
+{
+ uint32_t r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10;
+
+ put_r();
+ PRINTF("Registers/TIMER");
+ if (n == 0) {
+ r0 = NRF_TIMER0->SHORTS;
+ r1 = NRF_TIMER0->INTENSET;
+ r2 = NRF_TIMER0->INTENCLR;
+ r3 = NRF_TIMER0->MODE;
+ r4 = NRF_TIMER0->BITMODE;
+ r5 = NRF_TIMER0->PRESCALER;
+ r6 = NRF_TIMER0->CC[0];
+ r7 = NRF_TIMER0->CC[1];
+ r8 = NRF_TIMER0->CC[2];
+ r9 = NRF_TIMER0->CC[3];
+ r10 = NRF_TIMER0->POWER;
+ PRINTF("0");
+ } else if (n == 1) {
+ r0 = NRF_TIMER1->SHORTS;
+ r1 = NRF_TIMER1->INTENSET;
+ r2 = NRF_TIMER1->INTENCLR;
+ r3 = NRF_TIMER1->MODE;
+ r4 = NRF_TIMER1->BITMODE;
+ r5 = NRF_TIMER1->PRESCALER;
+ r6 = NRF_TIMER1->CC[0];
+ r7 = NRF_TIMER1->CC[1];
+ r8 = NRF_TIMER1->CC[2];
+ r9 = NRF_TIMER1->CC[3];
+ r10 = NRF_TIMER1->POWER;
+ PRINTF("1");
+ } else if (n == 2) {
+ r0 = NRF_TIMER2->SHORTS;
+ r1 = NRF_TIMER2->INTENSET;
+ r2 = NRF_TIMER2->INTENCLR;
+ r3 = NRF_TIMER2->MODE;
+ r4 = NRF_TIMER2->BITMODE;
+ r5 = NRF_TIMER2->PRESCALER;
+ r6 = NRF_TIMER2->CC[0];
+ r7 = NRF_TIMER2->CC[1];
+ r8 = NRF_TIMER2->CC[2];
+ r9 = NRF_TIMER2->CC[3];
+ r10 = NRF_TIMER2->POWER;
+ PRINTF("2");
+ } else {
+ return;
+ }
+ put_rn();
+ PRINTF("SHORTS: ");
+ reg_print(SIZE32, r0);
+ put_rn();
+ PRINTF("INTENSET: ");
+ reg_print(SIZE32, r1);
+ put_rn();
+ PRINTF("INTENCLR: ");
+ reg_print(SIZE32, r2);
+ put_rn();
+ PRINTF("MODE: ");
+ reg_print(SIZE32, r3);
+ put_rn();
+ PRINTF("BITMODE: ");
+ reg_print(SIZE32, r4);
+ put_rn();
+ PRINTF("PRESCALER:");
+ reg_print(SIZE32, r5);
+ put_rn();
+ PRINTF("cc[0]: ");
+ reg_print(SIZE32, r6);
+ put_rn();
+ PRINTF("cc[1]: ");
+ reg_print(SIZE32, r7);
+ put_rn();
+ PRINTF("cc[2]: ");
+ reg_print(SIZE32, r8);
+ put_rn();
+ PRINTF("cc[3]: ");
+ reg_print(SIZE32, r9);
+ put_rn();
+ PRINTF("POWER: ");
+ reg_print(SIZE32, r10);
+ put_rn();
+}
+#endif //USE_TIMER
+
+//------------------------------------------------------------------------------
+// Monitor Main Program
+//------------------------------------------------------------------------------
+int mon_hw (void)
+{
+ char *ptr;
+
+ put_r();
+ PRINTF("%s [Help:'?' key]", mon_msg);
+ put_rn();
+ for (;;) {
+ put_r();
+ PUTC('>');
+ ptr = linebuf;
+ get_line(ptr, buf_size);
+ switch (*ptr++) {
+ //--------------------------------------------------------------
+ // Memory
+ //--------------------------------------------------------------
+ case 'm' :
+#if USE_MEM
+ mem_inf(ptr);
+ put_rn();
+#else
+ not_select();
+#endif // USE_MEM
+ break;
+ //--------------------------------------------------------------
+ // POWER
+ //--------------------------------------------------------------
+ case 'w' :
+#if USE_POWER
+ power_reg();
+#else
+ not_select();
+#endif // USE_POWER
+ break;
+ //--------------------------------------------------------------
+ // Frequency(Clock)
+ //--------------------------------------------------------------
+ case 'f' :
+#if USE_FREQ
+ freq_reg();
+#else
+ not_select();
+#endif // USE_FREQ
+ break;
+ //--------------------------------------------------------------
+ // GPIO
+ //--------------------------------------------------------------
+ case 'p' :
+#if USE_PORT
+ port_all();
+ put_rn();
+#else
+ not_select();
+#endif // USE_PORT
+ break;
+ //--------------------------------------------------------------
+ // Register
+ //--------------------------------------------------------------
+ case 'r' :
+ uint8_t r_flg;
+ put_r();
+ PRINTF("Reg. Mode u,i,s,t,a & ?");
+ put_rn();
+ r_flg = 0;
+ for (; r_flg != 0xff;) {
+ PRINTF("r>");
+ ptr = linebuf;
+ get_line(ptr, buf_size);
+ put_r();
+ switch(*ptr++) {
+ case 'u' :
+#if USE_UART
+ uart_reg();
+#else
+ not_select();
+#endif // USE_UART
+ break;
+ case 'i' :
+#if USE_I2C
+ put_r();
+ i2c_reg(0);
+ put_rn();
+ i2c_reg(1);
+#else
+ not_select();
+#endif // USE_I2C
+ break;
+ case 's' :
+#if USE_SPI
+ spi_reg(0);
+ put_rn();
+ spi_reg(1);
+#else
+ not_select();
+#endif // USE_SPI
+ break;
+ case 't' : //
+#if USE_TIMER
+ timer_reg(0);
+ put_rn();
+ timer_reg(1);
+ put_rn();
+ timer_reg(2);
+#else
+ not_select();
+#endif // USE_TIMER
+ break;
+ case 'a' : //
+#if USE_ADC
+ adc_reg();
+#else
+ not_select();
+#endif // USE_SPI
+ break;
+ case 'q' : // quit
+ r_flg = 0xff;
+ break;
+ case '?' :
+ PRINTF("u - UART");
+ put_rn();
+ PRINTF("i - I2C");
+ put_rn();
+ PRINTF("s - SPI");
+ put_rn();
+ PRINTF("t - TIMER");
+ put_rn();
+ PRINTF("a - ADC");
+ put_rn();
+ PRINTF("q - Exit mode");
+ put_rn();
+ break;
+ default:
+ PUTC('?');
+ put_rn();
+ }
+ }
+ PRINTF("Return to All Mode");
+ put_rn();
+ break;
+ //--------------------------------------------------------------
+ // CPU
+ //--------------------------------------------------------------
+ case 'c' : // CPU related information
+#if USE_SYS
+ put_r();
+ cpu_sys();
+#else
+ not_select();
+#endif // USE_SYS
+ break;
+ //--------------------------------------------------------------
+ // Help
+ //--------------------------------------------------------------
+ case '?' :
+ put_r();
+ msg_hlp_hw();
+ break;
+ //--------------------------------------------------------------
+ // Return to main routine
+ //--------------------------------------------------------------
+ case 'q' : // Quit
+ PRINTF("\rReturn to monitor ");
+ return 0;
+ //--------------------------------------------------------------
+ // Special command for DEBUG
+ //--------------------------------------------------------------
+ case 'x' :
+ not_yet_impliment();
+ break;
+ //--------------------------------------------------------------
+ // no support
+ //--------------------------------------------------------------
+ default:
+ PUTC('?');
+ put_rn();
+ break;
+ }
+ }
+}
+
+#endif // defined(TARGET_NRF51822)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/9_Monitor/main.cpp Sat Apr 14 04:56:34 2018 +0000
@@ -0,0 +1,160 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2014 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.
+ */
+
+/*
+ * Modified by Kenji Arai
+ * http://www.page.sannet.ne.jp/kenjia/index.html
+ * https://os.mbed.com/users/kenjiArai/
+ *
+ * Started: January 3rd, 2016
+ * Revised: Feburary 13th, 2016
+ * Revised: April 14th, 2018
+ */
+
+//#define EXAMPLE_9_MONITOR
+#ifdef EXAMPLE_9_MONITOR
+
+// Include --------------------------------------------------------------------
+#include "mbed.h"
+#include "BLE.h"
+#include "BatteryService.h"
+#include "nRF51_Vdd.h"
+#include "BME280.h"
+#include "TYBLE16_BASE.h"
+
+// Definition -----------------------------------------------------------------
+/* 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 1
+
+#if NEED_CONSOLE_OUTPUT
+#define DEBUG(...) { pc.printf(__VA_ARGS__); }
+#else
+#define DEBUG(...) /* nothing */
+#endif /* #if NEED_CONSOLE_OUTPUT */
+
+// Object ---------------------------------------------------------------------
+DigitalOut led1(LED1, 1);
+DigitalIn sw(BUTTON1);
+AnalogIn ana0(A0);
+DigitalIn sw1(A1);
+Serial pc(USBTX, USBRX);
+I2C i2c(I2C_SDA, I2C_SCL);
+BME280 hmtp(i2c);
+SPI spi(SPI_PSELMOSI0, SPI_PSELMISO0, SPI_PSELSCK0);
+nRF51_Vdd vdd(3.6f, 2.6f);
+Ticker t;
+
+// ROM / Constant data --------------------------------------------------------
+const char *deviceName = "mbedMon";
+char *const opngmsg =
+ "\x1b[2J\x1b[H"__FILE__ "\r\n"__DATE__ " " __TIME__ " (UTC)\r\n""\r\n";
+
+// RAM ------------------------------------------------------------------------
+BatteryService *batteryService = NULL;
+uint8_t batteryLevel = 50;
+
+// Function prototypes --------------------------------------------------------
+extern void debug_interface(uint8_t mode);
+
+//------------------------------------------------------------------------------
+// Control Program
+//------------------------------------------------------------------------------
+void disconnectionCallback
+(const Gap::DisconnectionCallbackParams_t *disconnectionParams)
+{
+ DEBUG("Disconnected handle %u!\n\r", disconnectionParams->handle);
+ DEBUG("Restarting the advertising process\n\r");
+ // restart advertising
+ BLE::Instance(BLE::DEFAULT_INSTANCE).gap().startAdvertising();
+}
+
+void blink(void)
+{
+ led1 = !led1;
+}
+
+int main(void)
+{
+ // ******************************************************
+ // Here is a example to impliment the monitor
+ // para: 1 -> goto montor and never comeback
+ // ******************************************************
+#if 0
+ debug_interface(1);
+#endif
+
+ pc.puts(opngmsg);
+ // Application program runs at here
+ t.attach(blink, 1.0f);
+
+ DEBUG("Initialising the nRF5x chip\r\n");
+
+ // Check TYBLE-16 configuration
+ cpu_sys();
+ compile_condition();
+ //
+ BLE& ble = BLE::Instance(BLE::DEFAULT_INSTANCE);
+ ble.init();
+ ble.setDeviceName((const uint8_t *)deviceName);
+ ble.onDisconnection(disconnectionCallback);
+
+ batteryService = new BatteryService(ble, batteryLevel);
+
+ /* 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 *)deviceName,
+ strlen(deviceName));
+ ble.setAdvertisingInterval(1000); /* 1000ms; in multiples of 0.625ms. */
+ ble.startAdvertising();
+
+ while (true) {
+ // this will return upon any system event
+ ble.waitForEvent();
+
+ // the magic battery processing
+ batteryLevel++;
+#if 1
+ if (batteryLevel > 100) {
+ batteryLevel = 20;
+ }
+ DEBUG("Vdd: %4.3f\r\n", vdd.read_real_value());
+#else
+ DEBUG("Vdd: %f\r\n", vdd.read_real_value());
+ batteryLevel = vdd.read();
+#endif
+
+ batteryService->updateBatteryLevel(batteryLevel);
+ DEBUG("battery=%d\r\n", batteryLevel);
+
+ DEBUG("analog input = %f\r\n", ana0.read());
+ DEBUG("Temperature= %+5.2f [degC]\r\n", hmtp.getTemperature());
+
+ // ******************************************************
+ // Here is a example to impliment the monitor
+ // para: 0 -> if Uart RX Data is ready then goto montor
+ // ******************************************************
+ debug_interface(0);
+ Thread::wait(1000);
+ }
+}
+
+#endif
--- a/TYBLE16_os5_BASE.lib Tue Apr 10 12:43:29 2018 +0000 +++ b/TYBLE16_os5_BASE.lib Sat Apr 14 04:56:34 2018 +0000 @@ -1,1 +1,1 @@ -https://os.mbed.com/users/kenjiArai/code/TYBLE16_os5_BASE/#d626609f0029 +https://os.mbed.com/users/kenjiArai/code/TYBLE16_os5_BASE/#3a1ceeab2e20
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/BME280.lib Sat Apr 14 04:56:34 2018 +0000 @@ -0,0 +1,1 @@ +https://mbed.org/users/MACRUM/code/BME280/#c1f1647004c4
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/TextLCD.lib Sat Apr 14 04:56:34 2018 +0000 @@ -0,0 +1,1 @@ +http://developer.mbed.org/users/wim/code/TextLCD/#111ca62e8a59
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/common/nRF51_Vdd.lib Sat Apr 14 04:56:34 2018 +0000 @@ -0,0 +1,1 @@ +https://developer.mbed.org/users/kenjiArai/code/nRF51_Vdd/#faf2e448c15b
--- a/main.cpp Tue Apr 10 12:43:29 2018 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-/*
- * Mbed Application program / Blinky
- *
- * Copyright (c) 2018 Kenji Arai / JH1PJL
- * http://www.page.sannet.ne.jp/kenjia/index.html
- * http://mbed.org/users/kenjiArai/
- * Created: April 10th, 2018
- * Revised: April 10th, 2018
- */
-
-// Include --------------------------------------------------------------------
-#include "mbed.h"
-#include "TYBLE16_BASE.h"
-
-// Definition -----------------------------------------------------------------
-
-// Constructor ----------------------------------------------------------------
-DigitalOut my_led(LED1);
-Serial pc(USBTX, USBRX);
-
-// RAM ------------------------------------------------------------------------
-
-// ROM / Constant data --------------------------------------------------------
-char *const opngmsg =
- "\x1b[2J\x1b[H"__FILE__ "\r\n"__DATE__ " " __TIME__ " (UTC)\r\n""\r\n";
-
-// Function prototypes --------------------------------------------------------
-
-//------------------------------------------------------------------------------
-// Control Program
-//------------------------------------------------------------------------------
-int main()
-{
- uint32_t count = 0;
-
- pc.puts(opngmsg);
- // Check TYBLE-16 configuration
- cpu_sys();
- compile_condition();
- while(true) {
- my_led = !my_led;
- pc.printf("%8u\r\n", count++);
- Thread::wait(1000);
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/select_example.cpp Sat Apr 14 04:56:34 2018 +0000 @@ -0,0 +1,94 @@ +/* + * AE-TYBLE16 Module example programs + * + * Copyright (c) 2018 Kenji Arai / JH1PJL + * http://www.page.sannet.ne.jp/kenjia/index.html + * https://os.mbed.com/users/kenjiArai/ + * Created: April 7th, 2018 + * Revised: April 14th, 2018 + */ + +/* + You can select several examples as followings. + 0. 0_Blinky_LED + LED Blinky + 1. 1_Check_RTC + Check RTC function + -> Time is not so accurate because 32.768KHz is made by Internal RC osc. + 2. 2_EddyStoneBeacon + Demonstration sample program EddyStone Beacon + 3. 3_Heart_Rate + Demonstration sample program Heart Rate + 4. 4_RCBController + Potential usage for Radio Controller (RCB Controller) + 5. 5_SDCard + Demonstration sample program SD Card + 6. 6_Thermo + Demonstration sample program Thermometer + -> If you have I2C temperature sensor, you can connect it. + -> LCD can display the data. + 7 & 8. 7_Uart_Client & 8_Uart_Server + Uart Client(Central) and Server(Peripheral) + -> PLEASE SET VCOM BAUDRATE IS 115200 + 9. 9_Monitor + Check nRF51 CPU functions + */ +#define EXAMPLE_NUMBER 9 +// select 0 to 9 + +//----------------- You don't need any modification ---------------------------- +#if EXAMPLE_NUMBER == 0 +#define EXAMPLE_0_BLINKY_LED +#ifdef EXAMPLE_0_BLINKY_LED +#include "0_Blinky_LED/main.cpp" +#endif +#elif EXAMPLE_NUMBER == 1 +#define EXAMPLE_1_CHECK_RTC +#ifdef EXAMPLE_1_CHECK_RTC +#include "1_Check_RTC/main.cpp" +#endif +#elif EXAMPLE_NUMBER == 2 +#define EXAMPLE_2_EDDYSTONE_BEACON +#ifdef EXAMPLE_2_EDDYSTONE_BEACON +#include "2_EddyStoneBeacon/main.cpp" +#endif +#elif EXAMPLE_NUMBER == 3 +#define EXAMPLE_3_HEART_RATE +#ifdef EXAMPLE_3_HEART_RATE +#include "3_Heart_Rate/main.cpp" +#endif +#elif EXAMPLE_NUMBER == 4 +#define EXAMPLE_4_RCB_CONTROLLER +#ifdef EXAMPLE_4_RCB_CONTROLLER +#include "4_RCBController/main.cpp" +#endif +#elif EXAMPLE_NUMBER == 5 +#define EXAMPLE_5_SDCARD +#ifdef EXAMPLE_5_SDCARD +#include "5_SDCard/main.cpp" +#endif +#elif EXAMPLE_NUMBER == 6 +#define EXAMPLE_6_THERMO +#ifdef EXAMPLE_6_THERMO +#include "6_Thermo/main.cpp" +#endif +#elif EXAMPLE_NUMBER == 7 +#define EXAMPLE_7_UART_CLIENT +#ifdef EXAMPLE_7_UART_CLIENT +#include "7_Uart_Client/main.cpp" +#warning "Please set VCOM baudrate -> 115200 "" +#endif +#elif EXAMPLE_NUMBER == 8 +#define EXAMPLE_8_UART_SERVER +#ifdef EXAMPLE_8_UART_SERVER +#include "8_Uart_Server/main.cpp" +#warning "Please set VCOM baudrate -> 115200 "" +#endif +#elif EXAMPLE_NUMBER == 9 +#define EXAMPLE_9_MONITOR +#ifdef EXAMPLE_9_MONITOR +#include "9_Monitor/main.cpp" +#endif +#else +#error " Please set 0 to 9 number for EXAMPLE_NUMBER!!" +#endif
