Osamu Koizumi / Mbed OS Pelion-GR-LYCHEE-camera-firmware
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 // ----------------------------------------------------------------------------
00002 // Copyright 2016-2019 ARM Ltd.
00003 //
00004 // SPDX-License-Identifier: Apache-2.0
00005 //
00006 // Licensed under the Apache License, Version 2.0 (the "License");
00007 // you may not use this file except in compliance with the License.
00008 // You may obtain a copy of the License at
00009 //
00010 //     http://www.apache.org/licenses/LICENSE-2.0
00011 //
00012 // Unless required by applicable law or agreed to in writing, software
00013 // distributed under the License is distributed on an "AS IS" BASIS,
00014 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015 // See the License for the specific language governing permissions and
00016 // limitations under the License.
00017 // ----------------------------------------------------------------------------
00018 #ifndef MBED_TEST_MODE
00019 #include "mbed.h"
00020 #include "kv_config.h"
00021 #include "mbed-cloud-client/MbedCloudClient.h" // Required for new MbedCloudClient()
00022 #include "factory_configurator_client.h"       // Required for fcc_* functions and FCC_* defines
00023 #include "m2mresource.h"                       // Required for M2MResource
00024 
00025 #include "mbed-trace/mbed_trace.h"             // Required for mbed_trace_*
00026 
00027 // Camera setting
00028 #include "EasyAttach_CameraAndLCD.h"
00029 #include "dcache-control.h"
00030 #include "JPEG_Converter.h"
00031 /**** User Selection *********/
00032 #define VIDEO_PIXEL_HW         (320u)  /* QVGA */
00033 #define VIDEO_PIXEL_VW         (240u)  /* QVGA */
00034 #define JPEG_ENCODE_QUALITY    (75)    /* JPEG encode quality (min:1, max:75 (Considering the size of JpegBuffer, about 75 is the upper limit.)) */
00035 /*****************************/
00036 #define DATA_SIZE_PER_PIC      (2u)
00037 #define FRAME_BUFFER_STRIDE    (((VIDEO_PIXEL_HW * DATA_SIZE_PER_PIC) + 31u) & ~31u)
00038 #define FRAME_BUFFER_HEIGHT    (VIDEO_PIXEL_VW)
00039 
00040 uint8_t user_frame_buffer0[FRAME_BUFFER_STRIDE * FRAME_BUFFER_HEIGHT]__attribute((aligned(32)));
00041 uint8_t JpegBuffer[1024 * 32]__attribute((aligned(32)));
00042 DisplayBase Display;
00043 JPEG_Converter Jcu;
00044 // End camera setting
00045 
00046 const int LED_ON = MBED_CONF_APP_LED_ON;
00047 const int LED_OFF = (!(MBED_CONF_APP_LED_ON));
00048 
00049 // Pointers to the resources that will be created in main_application().
00050 static MbedCloudClient *cloud_client;
00051 static bool cloud_client_running = true;
00052 static NetworkInterface *network = NULL;
00053 
00054 // Fake entropy needed for non-TRNG boards. Suitable only for demo devices.
00055 const uint8_t MBED_CLOUD_DEV_ENTROPY[] = { 0xf6, 0xd6, 0xc0, 0x09, 0x9e, 0x6e, 0xf2, 0x37, 0xdc, 0x29, 0x88, 0xf1, 0x57, 0x32, 0x7d, 0xde, 0xac, 0xb3, 0x99, 0x8c, 0xb9, 0x11, 0x35, 0x18, 0xeb, 0x48, 0x29, 0x03, 0x6a, 0x94, 0x6d, 0xe8, 0x40, 0xc0, 0x28, 0xcc, 0xe4, 0x04, 0xc3, 0x1f, 0x4b, 0xc2, 0xe0, 0x68, 0xa0, 0x93, 0xe6, 0x3a };
00056 
00057 static M2MResource* m2m_get_res;
00058 static M2MResource* m2m_put_res;
00059 static M2MResource* m2m_post_res;
00060 static M2MResource* m2m_deregister_res;
00061 
00062 // Additional resources for camera
00063 static M2MResource* m2m_camera_capture_res;
00064 
00065 // Camera functions
00066 bool take_photo(uint8_t *photo_data, uint32_t *photo_data_len) {
00067     JPEG_Converter::bitmap_buff_info_t buff_info;
00068     JPEG_Converter::encode_options_t   encode_opt;
00069 
00070     if ((photo_data == NULL) || (photo_data_len == NULL)) {
00071         return false;
00072     }
00073 
00074     // Jpeg setting
00075     buff_info.width              = VIDEO_PIXEL_HW;
00076     buff_info.height             = VIDEO_PIXEL_VW;
00077     buff_info.format             = JPEG_Converter::WR_RD_YCbCr422;
00078     buff_info.buffer_address     = (void *)user_frame_buffer0;
00079     encode_opt.encode_buff_size  = *photo_data_len;
00080     encode_opt.input_swapsetting = JPEG_Converter::WR_RD_WRSWA_32_16_8BIT;
00081 
00082     dcache_invalid(photo_data, *photo_data_len);
00083     JPEG_Converter::jpeg_conv_error_t err = Jcu.encode(&buff_info, photo_data, (size_t *)photo_data_len, &encode_opt);    
00084     if(err != JPEG_Converter::JPEG_CONV_OK)
00085     {
00086         return false;
00087     }
00088     return true;
00089 }
00090 
00091 bool take_and_send_photo() {
00092     // Send photo data on button click
00093     uint32_t photo_data_len = sizeof(JpegBuffer);
00094     bool result = take_photo(JpegBuffer, &photo_data_len);
00095     if (result) {
00096         m2m_camera_capture_res->set_value((const uint8_t *)JpegBuffer, photo_data_len);
00097     }
00098 
00099     return result;
00100 }
00101 
00102 /*
00103  * Monitor the network connection. If the network is disconnected, LED4 on the board lights.
00104  */
00105 void monitor() {
00106     static DigitalOut led(LED4, LED_OFF);
00107     nsapi_connection_status status = network->get_connection_status();
00108     if(status != NSAPI_STATUS_GLOBAL_UP) {
00109         led = LED_ON;
00110         printf("Network is disconnected. Status = %d.\n", status);
00111     } else {
00112         led = LED_OFF;
00113     }
00114 }
00115 
00116 
00117 void print_client_ids(void)
00118 {
00119     printf("Account ID: %s\n", cloud_client->endpoint_info()->account_id.c_str());
00120     printf("Endpoint name: %s\n", cloud_client->endpoint_info()->internal_endpoint_name.c_str());
00121     printf("Device Id: %s\n\n", cloud_client->endpoint_info()->endpoint_name.c_str());
00122 }
00123 
00124 void button_press() {
00125     m2m_get_res->set_value(m2m_get_res->get_value_int() + 1);
00126     printf("User button clicked %d times\n", m2m_get_res->get_value_int());
00127 
00128     if(!take_and_send_photo()) {
00129         printf("Failed to send photo.");
00130     }
00131 }
00132 
00133 void put_update(const char* /*object_name*/)
00134 {
00135     printf("Camera shutter triggered. %d\n", (int)m2m_put_res->get_value_int());
00136 
00137     if(!take_and_send_photo()) {
00138         printf("Failed to send photo.");
00139     }
00140 }
00141 
00142 void execute_post(void* /*arguments*/)
00143 {
00144     printf("POST executed\n");
00145 }
00146 
00147 void deregister_client(void)
00148 {
00149     printf("Unregistering and disconnecting from the network.\n");
00150     cloud_client->close();
00151 }
00152 
00153 void deregister(void* /*arguments*/)
00154 {
00155     printf("POST deregister executed\n");
00156     m2m_deregister_res->send_delayed_post_response();
00157 
00158     deregister_client();
00159 }
00160 
00161 void client_registered(void)
00162 {
00163     printf("Client registered.\n");
00164     print_client_ids();
00165     // Turn on LED1 when device is registered.
00166     DigitalOut led(LED1, LED_ON);
00167 }
00168 
00169 void client_unregistered(void)
00170 {
00171     printf("Client unregistered.\n");
00172     (void) network->disconnect();
00173     cloud_client_running = false;
00174     // Turn off LED1 when device is registered.
00175     DigitalOut led(LED1, LED_OFF);
00176 }
00177 
00178 void client_error(int err)
00179 {
00180     printf("client_error(%d) -> %s\n", err, cloud_client->error_description());
00181 }
00182 
00183 void update_progress(uint32_t progress, uint32_t total)
00184 {
00185     uint8_t percent = (uint8_t)((uint64_t)progress * 100 / total);
00186     printf("Update progress = %" PRIu8 "%%\n", percent);
00187 }
00188 
00189 int main(void)
00190 {
00191     int status;
00192 
00193     status = mbed_trace_init();
00194     if (status != 0) {
00195         printf("mbed_trace_init() failed with %d\n", status);
00196         return -1;
00197     }
00198 
00199     // Mount default kvstore
00200     printf("Application ready\n");
00201     status = kv_init_storage_config();
00202     if (status != MBED_SUCCESS) {
00203         printf("kv_init_storage_config() - failed, status %d\n", status);
00204         return -1;
00205     }
00206 
00207     // Connect with NetworkInterface
00208     printf("Connect to network\n");
00209     network = NetworkInterface::get_default_instance();
00210     if (network == NULL) {
00211         printf("Failed to get default NetworkInterface\n");
00212         return -1;
00213     }
00214     status = network->connect();
00215     if (status != NSAPI_ERROR_OK) {
00216         printf("NetworkInterface failed to connect with %d\n", status);
00217         // Turn on LED2 when the network initialization failed.
00218         DigitalOut led(LED2, LED_ON);
00219         return -1;
00220     }
00221 
00222     printf("Network initialized, connected with IP %s\n\n", network->get_ip_address());
00223 
00224     // Run developer flow
00225     printf("Start developer flow\n");
00226     status = fcc_init();
00227     if (status != FCC_STATUS_SUCCESS) {
00228         printf("fcc_init() failed with %d\n", status);
00229         // Turn on LED3 when Pelion Client initialization failed.
00230         DigitalOut led(LED3, LED_ON);
00231         return -1;
00232     }
00233 
00234     // Inject hardcoded entropy for the device. Suitable only for demo devices.
00235     (void) fcc_entropy_set(MBED_CLOUD_DEV_ENTROPY, sizeof(MBED_CLOUD_DEV_ENTROPY));
00236     status = fcc_developer_flow();
00237     if (status != FCC_STATUS_SUCCESS && status != FCC_STATUS_KCM_FILE_EXIST_ERROR && status != FCC_STATUS_CA_ERROR) {
00238         printf("fcc_developer_flow() failed with %d\n", status);
00239         // Turn on LED3 when Pelion Client initialization failed.
00240         DigitalOut led(LED3, LED_ON);
00241         return -1;
00242     }
00243 
00244     printf("Create resources\n");
00245     M2MObjectList m2m_obj_list;
00246 
00247     // GET resource 3200/0/5501
00248     m2m_get_res = M2MInterfaceFactory::create_resource(m2m_obj_list, 3200, 0, 5501, M2MResourceInstance::INTEGER, M2MBase::GET_ALLOWED);
00249     if (m2m_get_res->set_value(0) != true) {
00250         printf("m2m_get_res->set_value() failed\n");
00251         return -1;
00252     }
00253 
00254     // PUT resource 3201/0/5853 (camera trigger resource)
00255     m2m_put_res = M2MInterfaceFactory::create_resource(m2m_obj_list, 3201, 0, 5853, M2MResourceInstance::INTEGER, M2MBase::GET_PUT_ALLOWED);
00256     if (m2m_put_res->set_value(0) != true) {
00257         printf("m2m_led_res->set_value() failed\n");
00258         return -1;
00259     }
00260     if (m2m_put_res->set_value_updated_function(put_update) != true) {
00261         printf("m2m_put_res->set_value_updated_function() failed\n");
00262         return -1;
00263     }
00264 
00265     // POST resource 3201/0/5850
00266     m2m_post_res = M2MInterfaceFactory::create_resource(m2m_obj_list, 3201, 0, 5850, M2MResourceInstance::INTEGER, M2MBase::POST_ALLOWED);
00267     if (m2m_post_res->set_execute_function(execute_post) != true) {
00268         printf("m2m_post_res->set_execute_function() failed\n");
00269         return -1;
00270     }
00271 
00272     // POST resource 5000/0/1 to trigger deregister.
00273     m2m_deregister_res = M2MInterfaceFactory::create_resource(m2m_obj_list, 5000, 0, 1, M2MResourceInstance::INTEGER, M2MBase::POST_ALLOWED);
00274 
00275     // Use delayed response
00276     m2m_deregister_res->set_delayed_response(true);
00277 
00278     if (m2m_deregister_res->set_execute_function(deregister) != true) {
00279         printf("m2m_post_res->set_execute_function() failed\n");
00280         return -1;
00281     }
00282 
00283     // Camera capture resource 3200/0/4014
00284     m2m_camera_capture_res = M2MInterfaceFactory::create_resource(m2m_obj_list, 3200, 0, 4014, M2MResourceInstance::STRING, M2MBase::GET_ALLOWED);
00285     if(m2m_camera_capture_res->set_value(0) != true) {
00286         printf("m2m_camera_capture_res->set_value() failed.\n");
00287         return -1;
00288     }
00289 
00290     // Camera start
00291     EasyAttach_Init(Display);
00292     Display.Video_Write_Setting(
00293         DisplayBase::VIDEO_INPUT_CHANNEL_0,
00294         DisplayBase::COL_SYS_NTSC_358,
00295         (void *)user_frame_buffer0,
00296         FRAME_BUFFER_STRIDE,
00297         DisplayBase::VIDEO_FORMAT_YCBCR422,
00298         DisplayBase::WR_RD_WRSWA_32_16BIT,
00299         VIDEO_PIXEL_VW,
00300         VIDEO_PIXEL_HW
00301     );
00302     EasyAttach_CameraStart(Display, DisplayBase::VIDEO_INPUT_CHANNEL_0);
00303 
00304     // Jpeg setting
00305     Jcu.SetQuality(JPEG_ENCODE_QUALITY);
00306 
00307 
00308     printf("Register Pelion Device Management Client\n\n");
00309     cloud_client = new MbedCloudClient(client_registered, client_unregistered, client_error, NULL, update_progress);
00310     cloud_client->add_objects(m2m_obj_list);
00311     cloud_client->setup(network); // cloud_client->setup(NULL); -- https://jira.arm.com/browse/IOTCLT-3114
00312 
00313     // An event queue is a very useful structure to debounce information between contexts (e.g. ISR and normal threads)
00314     // This is great because things such as network operations are illegal in ISR, so updating a resource in a button's fall() function is not allowed
00315     EventQueue eventQueue;
00316     Thread t;
00317     // Start the event queue
00318     t.start(callback(&eventQueue, &EventQueue::dispatch_forever));
00319 
00320     // Setup the button
00321     InterruptIn btn(USER_BUTTON0);
00322     btn.mode(PullUp);
00323 
00324     // The button fall handler is placed in the event queue so it will run in
00325     // thread context instead of ISR context, which allows safely updating the cloud resource
00326     btn.fall(eventQueue.event(&button_press));
00327 
00328     // Monitor the network connection periodically.
00329     Ticker ticker;
00330     ticker.attach(eventQueue.event(&monitor), 5.0);    // second param is period in seconds
00331 
00332     while(cloud_client_running) {
00333         int in_char = getchar();
00334         if (in_char == 'i') {
00335             print_client_ids(); // When 'i' is pressed, print endpoint info
00336             continue;
00337         } else if (in_char == 'r') {
00338             (void) fcc_storage_delete(); // When 'r' is pressed, erase storage and reboot the board.
00339             printf("Storage erased, rebooting the device.\n\n");
00340             wait_us(1000000);
00341             NVIC_SystemReset();
00342         } else if (in_char > 0 && in_char != 0x03) { // Ctrl+C is 0x03 in Mbed OS and Linux returns negative number
00343             button_press(); // Simulate button press
00344             continue;
00345         }
00346         deregister_client();
00347         break;
00348     }
00349     return 0;
00350 }
00351 
00352 #endif /* MBED_TEST_MODE */