Timothy Beight / Mbed 2 deprecated 6_songs-from-the-cloud

Dependencies:   mbed Socket lwip-eth lwip-sys lwip

Fork of 6_songs-from-the-cloud by MakingMusicWorkshop

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /*
00002  * Copyright (c) 2015 ARM Limited. All rights reserved.
00003  * SPDX-License-Identifier: Apache-2.0
00004  * Licensed under the Apache License, Version 2.0 (the License); you may
00005  * not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  * http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
00012  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016  
00017 #include "mbed.h"       // this tells us to load mbed OS related functions
00018 #include "tones.h"                   // list of all the tones and their frequencies
00019 #include "simpleclient.h"
00020 #include <string>
00021 #include <sstream>
00022 #include <vector>
00023 
00024 Serial output(USBTX, USBRX);
00025 
00026 PwmOut buzzer(D3);                   // our buzzer is a PWM output (pulse-width modulation)
00027 
00028 static int BPM = 35;
00029 
00030 EthernetInterface eth;
00031 
00032 // These are example resource values for the Device Object
00033 struct MbedClientDevice device = {
00034     "Manufacturer_String",      // Manufacturer
00035     "Type_String",              // Type
00036     "ModelNumber_String",       // ModelNumber
00037     "SerialNumber_String"       // SerialNumber
00038 };
00039 
00040 // Instantiate the class which implements LWM2M Client API (from simpleclient.h)
00041 MbedClient mbed_client(device);
00042 
00043 // this is our function that plays a tone. 
00044 // Takes in a tone frequency, and after duration (in ms.) we stop playing again
00045 static void playTone(int tone, int duration) {
00046 
00047     buzzer.period_us(1000000/tone);  //period in us
00048     buzzer.write(0.10f); // 10% duty cycle, otherwise it's too loud
00049     wait_us(1000*duration/2);  //play for half the length
00050     buzzer.write(0.0f);
00051     wait_us(1000*duration/2);  //silence for half the length
00052 
00053 }
00054 
00055 static void play_song(std::vector<int>* melody, std::vector<int>* duration) {
00056     
00057     output.printf("play_song\n\r");
00058     for (int i = 0; i < melody->size(); i++) {
00059         int tone = melody->at(0);
00060         // BPM is quarter notes per minute, so length in milliseconds is:
00061         int length = static_cast<int>(static_cast<float>(1000 / duration->at(0)) * (60000.0f / static_cast<float>(BPM * 1000)));
00062         
00063         // printf("tone %d, length %d, duration %d\r\n", tone, length, duration->at(0));
00064         
00065         if (melody->at(i) != 0) {
00066             playTone(melody->at(i), length);
00067         }
00068         else {
00069             buzzer = 0.0f;
00070             wait_ms(length);
00071         }
00072     }
00073 }
00074 
00075 
00076 /*
00077  * The buzzer contains two properties (notes, duration) and a function (play).
00078  * When the function play_song_from_cloud is executed, the notes and duration patterns are read,
00079  * and the song will be played.
00080  */
00081 class BuzzerResource {
00082 public:
00083     BuzzerResource() {
00084         // create ObjectID with metadata tag of 'buzzer', which is not defined by the LWM2M standard but we can use it for this demo
00085         buzzer_object = M2MInterfaceFactory::create_object("buzzer");
00086         M2MObjectInstance* buzzer_inst = buzzer_object->create_object_instance();
00087 
00088         // notes resource
00089         M2MResource* notes_res = buzzer_inst->create_dynamic_resource("notes", "",
00090             M2MResourceInstance::STRING, true); //observable
00091 
00092         // read and write
00093         notes_res->set_operation(M2MBase::GET_PUT_ALLOWED);
00094         
00095         // set initial pattern
00096         char notes_buffer[100];
00097         int notes_size = sprintf(notes_buffer,"262:277");
00098                     
00099         notes_res->set_value((const uint8_t*)notes_buffer,
00100                              (uint32_t)notes_size);
00101     
00102         // duration resource
00103         M2MResource* duration_res = buzzer_inst->create_dynamic_resource("duration", "",
00104             M2MResourceInstance::STRING, true);  //observable
00105 
00106         duration_res->set_operation(M2MBase::GET_PUT_ALLOWED);
00107         
00108         // set initial pattern
00109         char dur_buffer[100];
00110         int dur_size = sprintf(dur_buffer,"4:4");
00111                                 
00112         duration_res->set_value((const uint8_t*)dur_buffer,
00113                                 (uint32_t)dur_size);
00114 
00115         // play resource
00116         M2MResource* play_res = buzzer_inst->create_dynamic_resource("play", "",
00117             M2MResourceInstance::STRING, false);  //not observable
00118 
00119         play_res->set_operation(M2MBase::POST_ALLOWED);
00120                     
00121         play_res->set_execute_function(execute_callback (this, &BuzzerResource::play_song_cloud));
00122 
00123 
00124 }
00125 
00126     M2MObject* get_object() {
00127         return buzzer_object;
00128     }
00129 
00130     /*TODO - move the actual call to play_song_cloud to the main function, to avoid
00131       running it in interrupt context.  Use a flag or semaphore set by the callback and checked for
00132       in the main function */
00133       
00134     void play_song_cloud(void *) {
00135 
00136         output.printf("play song cloud triggered!\r\n");
00137 
00138         // read the object storing resources 'notes' and 'duration'
00139         M2MObjectInstance* inst = buzzer_object->object_instance();
00140 
00141         M2MResource* n_res = inst->resource("notes");
00142 
00143         // values in mbed Client are all buffers, and we need a vector of int's
00144         uint8_t* n_buffIn = NULL;
00145         uint32_t n_sizeIn;
00146         n_res->get_value(n_buffIn, n_sizeIn);
00147 
00148         output.printf("notes = %s\n\r",n_buffIn);
00149         
00150         std::stringstream notesPattern((char*)n_buffIn, n_sizeIn);
00151         
00152         std::vector<int>* notes = new std::vector<int>;
00153         {
00154             std::string n_item;
00155             while (std::getline(notesPattern, n_item, ':')) {
00156                 notes->push_back(atoi((const char*)n_item.c_str()));
00157             }
00158         }
00159     
00160         M2MResource* d_res = inst->resource("duration");
00161 
00162         // values in mbed Client are all buffers, and we need a vector of int's
00163         uint8_t* d_buffIn = NULL;
00164         uint32_t d_sizeIn;
00165         
00166         d_res->get_value(d_buffIn, d_sizeIn);
00167         
00168         output.printf("durations = %s\n\r",d_buffIn);
00169         
00170         //TODO: investigate why passing in d_sizeIn causes it to think there are always 0 durations 
00171         //std::stringstream durationPattern((char*)d_buffIn, d_sizeIn);
00172         std::stringstream durationPattern((char*)d_buffIn, 100);
00173                     
00174         std::vector<int>* durations = new std::vector<int>;
00175         {
00176             std::string d_item;
00177             while (std::getline(durationPattern, d_item, ':')) {
00178                 durations->push_back(atoi((const char*)d_item.c_str()));
00179             }
00180         }
00181     
00182         if (notes->size() != durations->size()) {
00183             output.printf("Notes and duration have different sizes (%d vs %d), abort!\r\n", notes->size(), durations->size());
00184             return;
00185         }
00186     
00187         play_song(notes, durations);
00188     }
00189 
00190 private:
00191     M2MObject* buzzer_object;
00192 
00193 
00194 };
00195 
00196 // Entry point to the program
00197 int main() {
00198  
00199     green = 1; // turn green off
00200     
00201     // This sets up the network interface configuration which will be used
00202     // by LWM2M Client API to communicate with mbed Device server.
00203     eth.init(); //Use DHCP
00204     eth.connect();
00205 
00206     output.printf("[ETH] IP address %s\r\n", eth.getIPAddress());
00207     output.printf("[ETH] Device name %s\r\n", MBED_ENDPOINT_NAME);
00208 
00209     // Create LWM2M Client API interface to manage register and unregister
00210     mbed_client.create_interface();
00211 
00212     // Create resource for interactions between the device and server
00213     BuzzerResource * buzzer_resource = new BuzzerResource();
00214 
00215     // Create LWM2M server object specifying mbed device server
00216     // information.
00217     M2MSecurity* register_object = mbed_client.create_register_object();
00218 
00219     // Add all the objects that you would like to register
00220     // into the list and pass the list for register API.
00221     M2MObjectList object_list;
00222     object_list.push_back(buzzer_resource->get_object());
00223 
00224     mbed_client.set_register_object(register_object);
00225 
00226     // Register with mbed Device Connector
00227     mbed_client.test_register(register_object, object_list);
00228 
00229     //TODO: should check for play command received and play song from main
00230     //      to avoid doing too much in interrupt context.
00231         
00232     while (true) {
00233         
00234         wait_ms(25000);  //wait 25 seconds
00235         output.printf("Updating registration\n\r");
00236         mbed_client.test_update_register();  //update registration
00237         
00238     }
00239       
00240  }
00241