Connect to the internet and play songs from a web app

Dependencies:   mbed Socket lwip-eth lwip-sys lwip

Revision:
0:f7c60d3e7b8a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed May 18 19:06:32 2016 +0000
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2015 ARM Limited. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+#include "mbed.h"       // this tells us to load mbed OS related functions
+#include "tones.h"                   // list of all the tones and their frequencies
+#include "simpleclient.h"
+#include <string>
+#include <sstream>
+#include <vector>
+
+Serial output(USBTX, USBRX);
+
+PwmOut buzzer(D3);                   // our buzzer is a PWM output (pulse-width modulation)
+
+static int BPM = 35;
+
+EthernetInterface eth;
+
+// These are example resource values for the Device Object
+struct MbedClientDevice device = {
+    "Manufacturer_String",      // Manufacturer
+    "Type_String",              // Type
+    "ModelNumber_String",       // ModelNumber
+    "SerialNumber_String"       // SerialNumber
+};
+
+// Instantiate the class which implements LWM2M Client API (from simpleclient.h)
+MbedClient mbed_client(device);
+
+// this is our function that plays a tone. 
+// Takes in a tone frequency, and after duration (in ms.) we stop playing again
+static void playTone(int tone, int duration) {
+
+    buzzer.period_us(1000000/tone);  //period in us
+    buzzer.write(0.10f); // 10% duty cycle, otherwise it's too loud
+    wait_us(1000*duration/2);  //play for half the length
+    buzzer.write(0.0f);
+    wait_us(1000*duration/2);  //silence for half the length
+
+}
+
+static void play_song(std::vector<int>* melody, std::vector<int>* duration) {
+    
+	output.printf("play_song\n\r");
+	for (int i = 0; i < melody->size(); i++) {
+        int tone = melody->at(0);
+        // BPM is quarter notes per minute, so length in milliseconds is:
+        int length = static_cast<int>(static_cast<float>(1000 / duration->at(0)) * (60000.0f / static_cast<float>(BPM * 1000)));
+        
+        // printf("tone %d, length %d, duration %d\r\n", tone, length, duration->at(0));
+        
+        if (melody->at(i) != 0) {
+            playTone(melody->at(i), length);
+        }
+        else {
+            buzzer = 0.0f;
+            wait_ms(length);
+        }
+    }
+}
+
+
+/*
+ * The buzzer contains two properties (notes, duration) and a function (play).
+ * When the function play_song_from_cloud is executed, the notes and duration patterns are read,
+ * and the song will be played.
+ */
+class BuzzerResource {
+public:
+    BuzzerResource() {
+        // create ObjectID with metadata tag of 'buzzer', which is not defined by the LWM2M standard but we can use it for this demo
+        buzzer_object = M2MInterfaceFactory::create_object("buzzer");
+        M2MObjectInstance* buzzer_inst = buzzer_object->create_object_instance();
+
+        // notes resource
+        M2MResource* notes_res = buzzer_inst->create_dynamic_resource("notes", "",
+            M2MResourceInstance::STRING, true); //observable
+
+        // read and write
+        notes_res->set_operation(M2MBase::GET_PUT_ALLOWED);
+        
+		// set initial pattern
+        char notes_buffer[100];
+        int notes_size = sprintf(notes_buffer,"262:277");
+                    
+        notes_res->set_value((const uint8_t*)notes_buffer,
+                             (uint32_t)notes_size);
+    
+        // duration resource
+        M2MResource* duration_res = buzzer_inst->create_dynamic_resource("duration", "",
+            M2MResourceInstance::STRING, true);  //observable
+
+        duration_res->set_operation(M2MBase::GET_PUT_ALLOWED);
+        
+		// set initial pattern
+        char dur_buffer[100];
+        int dur_size = sprintf(dur_buffer,"4:4");
+                                
+        duration_res->set_value((const uint8_t*)dur_buffer,
+                                (uint32_t)dur_size);
+
+        // play resource
+	    M2MResource* play_res = buzzer_inst->create_dynamic_resource("play", "",
+	        M2MResourceInstance::STRING, false);  //not observable
+
+        play_res->set_operation(M2MBase::POST_ALLOWED);
+                    
+		play_res->set_execute_function(execute_callback(this, &BuzzerResource::play_song_cloud));
+
+
+}
+
+    M2MObject* get_object() {
+        return buzzer_object;
+    }
+
+	/*TODO - move the actual call to play_song_cloud to the main function, to avoid
+	  running it in interrupt context.  Use a flag or semaphore set by the callback and checked for
+	  in the main function */
+	  
+    void play_song_cloud(void *) {
+
+		output.printf("play song cloud triggered!\r\n");
+
+        // read the object storing resources 'notes' and 'duration'
+        M2MObjectInstance* inst = buzzer_object->object_instance();
+
+        M2MResource* n_res = inst->resource("notes");
+
+        // values in mbed Client are all buffers, and we need a vector of int's
+        uint8_t* n_buffIn = NULL;
+        uint32_t n_sizeIn;
+        n_res->get_value(n_buffIn, n_sizeIn);
+
+		output.printf("notes = %s\n\r",n_buffIn);
+		
+    	std::stringstream notesPattern((char*)n_buffIn, n_sizeIn);
+    	
+    	std::vector<int>* notes = new std::vector<int>;
+    	{
+        	std::string n_item;
+        	while (std::getline(notesPattern, n_item, ':')) {
+            	notes->push_back(atoi((const char*)n_item.c_str()));
+         	}
+     	}
+    
+        M2MResource* d_res = inst->resource("duration");
+
+        // values in mbed Client are all buffers, and we need a vector of int's
+        uint8_t* d_buffIn = NULL;
+        uint32_t d_sizeIn;
+        
+        d_res->get_value(d_buffIn, d_sizeIn);
+        
+		output.printf("durations = %s\n\r",d_buffIn);
+        
+        //TODO: investigate why passing in d_sizeIn causes it to think there are always 0 durations 
+    	//std::stringstream durationPattern((char*)d_buffIn, d_sizeIn);
+    	std::stringstream durationPattern((char*)d_buffIn, 100);
+    	    		
+    	std::vector<int>* durations = new std::vector<int>;
+    	{
+        	std::string d_item;
+           	while (std::getline(durationPattern, d_item, ':')) {
+            	durations->push_back(atoi((const char*)d_item.c_str()));
+        	}
+    	}
+   	
+    	if (notes->size() != durations->size()) {
+        	output.printf("Notes and duration have different sizes (%d vs %d), abort!\r\n", notes->size(), durations->size());
+        	return;
+    	}
+    
+    	play_song(notes, durations);
+	}
+
+private:
+    M2MObject* buzzer_object;
+
+
+};
+
+// Entry point to the program
+int main() {
+ 
+    green = 1; // turn green off
+    
+    // This sets up the network interface configuration which will be used
+    // by LWM2M Client API to communicate with mbed Device server.
+    eth.init(); //Use DHCP
+    eth.connect();
+
+    output.printf("[ETH] IP address %s\r\n", eth.getIPAddress());
+    output.printf("[ETH] Device name %s\r\n", MBED_ENDPOINT_NAME);
+
+    // Create LWM2M Client API interface to manage register and unregister
+    mbed_client.create_interface();
+
+	// Create resource for interactions between the device and server
+	BuzzerResource * buzzer_resource = new BuzzerResource();
+
+    // Create LWM2M server object specifying mbed device server
+    // information.
+    M2MSecurity* register_object = mbed_client.create_register_object();
+
+    // Add all the objects that you would like to register
+    // into the list and pass the list for register API.
+    M2MObjectList object_list;
+    object_list.push_back(buzzer_resource->get_object());
+
+    mbed_client.set_register_object(register_object);
+
+    // Register with mbed Device Connector
+    mbed_client.test_register(register_object, object_list);
+
+    //TODO: should check for play command received and play song from main
+    //      to avoid doing too much in interrupt context.
+    	
+    while (true) {
+    	
+    	wait_ms(25000);  //wait 25 seconds
+    	output.printf("Updating registration\n\r");
+    	mbed_client.test_update_register();  //update registration
+    	
+    }
+      
+ }
+