You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

249 lines
7.5 KiB

3 years ago
  1. /*
  2. * ESPRESSIF MIT License
  3. *
  4. * Copyright (c) 2020 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
  5. *
  6. * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case,
  7. * it is free of charge, to any person obtaining a copy of this software and associated
  8. * documentation files (the "Software"), to deal in the Software without restriction, including
  9. * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
  10. * and/or sell copies of the Software, and to permit persons to whom the Software is furnished
  11. * to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in all copies or
  14. * substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  18. * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  19. * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  20. * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. *
  23. */
  24. #include <string.h>
  25. #include "sdkconfig.h"
  26. #include "freertos/FreeRTOS.h"
  27. #include "freertos/task.h"
  28. #include "freertos/semphr.h"
  29. #include "esp_log.h"
  30. #include "esp_wifi.h"
  31. #include "esp_camera.h"
  32. #include "mdns.h"
  33. #include "who_camera.h"
  34. static const char *TAG = "camera mdns";
  35. static const char * service_name = "_esp-cam";
  36. static const char * proto = "_tcp";
  37. static mdns_result_t * found_cams = NULL;
  38. static SemaphoreHandle_t query_lock = NULL;
  39. static char iname[64];
  40. static char hname[64];
  41. static char framesize[4];
  42. static char pixformat[4];
  43. static const char * model = NULL;
  44. static void mdns_query_for_cams()
  45. {
  46. mdns_result_t * new_cams = NULL;
  47. esp_err_t err = mdns_query_ptr(service_name, proto, 5000, 4, &new_cams);
  48. if(err){
  49. ESP_LOGE(TAG, "MDNS Query Failed: %s", esp_err_to_name(err));
  50. return;
  51. }
  52. xSemaphoreTake(query_lock, portMAX_DELAY);
  53. if (found_cams != NULL) {
  54. mdns_query_results_free(found_cams);
  55. }
  56. found_cams = new_cams;
  57. xSemaphoreGive(query_lock);
  58. }
  59. static void mdns_task(void * arg)
  60. {
  61. for (;;) {
  62. mdns_query_for_cams();
  63. //delay 55 seconds
  64. vTaskDelay((55 * 1000) / portTICK_PERIOD_MS);
  65. }
  66. vTaskDelete(NULL);
  67. }
  68. /*
  69. * Public Functions
  70. */
  71. const char * app_mdns_query(size_t * out_len)
  72. {
  73. //build JSON
  74. static char json_response[2048];
  75. char *p = json_response;
  76. *p++ = '[';
  77. //add own data first
  78. tcpip_adapter_ip_info_t ip;
  79. if (strlen(CONFIG_ESP_WIFI_SSID)) {
  80. tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip);
  81. } else {
  82. tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &ip);
  83. }
  84. *p++ = '{';
  85. p += sprintf(p, "\"instance\":\"%s\",", iname);
  86. p += sprintf(p, "\"host\":\"%s.local\",", hname);
  87. p += sprintf(p, "\"port\":80,");
  88. p += sprintf(p, "\"txt\":{");
  89. p += sprintf(p, "\"pixformat\":\"%s\",", pixformat);
  90. p += sprintf(p, "\"framesize\":\"%s\",", framesize);
  91. p += sprintf(p, "\"stream_port\":\"81\",");
  92. p += sprintf(p, "\"board\":\"%s\",", CAMERA_MODULE_NAME);
  93. p += sprintf(p, "\"model\":\"%s\"", model);
  94. *p++ = '}';
  95. *p++ = ',';
  96. p += sprintf(p, "\"ip\":\"" IPSTR "\",", IP2STR(&(ip.ip)));
  97. p += sprintf(p, "\"id\":\"" IPSTR ":80\",", IP2STR(&(ip.ip)));
  98. p += sprintf(p, "\"service\":\"%s\",", service_name);
  99. p += sprintf(p, "\"proto\":\"%s\"", proto);
  100. *p++ = '}';
  101. xSemaphoreTake(query_lock, portMAX_DELAY);
  102. if (found_cams) {
  103. *p++ = ',';
  104. }
  105. mdns_result_t * r = found_cams;
  106. mdns_ip_addr_t * a = NULL;
  107. int t;
  108. while(r){
  109. *p++ = '{';
  110. if(r->instance_name){
  111. p += sprintf(p, "\"instance\":\"%s\",", r->instance_name);
  112. }
  113. if(r->hostname){
  114. p += sprintf(p, "\"host\":\"%s.local\",", r->hostname);
  115. p += sprintf(p, "\"port\":%u,", r->port);
  116. }
  117. if(r->txt_count){
  118. p += sprintf(p, "\"txt\":{");
  119. for(t=0; t<r->txt_count; t++){
  120. if (t > 0) {
  121. *p++ = ',';
  122. }
  123. p += sprintf(p, "\"%s\":\"%s\"", r->txt[t].key, r->txt[t].value?r->txt[t].value:"NULL");
  124. }
  125. *p++ = '}';
  126. *p++ = ',';
  127. }
  128. a = r->addr;
  129. while(a){
  130. if(a->addr.type != IPADDR_TYPE_V6){
  131. p += sprintf(p, "\"ip\":\"" IPSTR "\",", IP2STR(&(a->addr.u_addr.ip4)));
  132. p += sprintf(p, "\"id\":\"" IPSTR ":%u\",", IP2STR(&(a->addr.u_addr.ip4)), r->port);
  133. break;
  134. }
  135. a = a->next;
  136. }
  137. p += sprintf(p, "\"service\":\"%s\",", service_name);
  138. p += sprintf(p, "\"proto\":\"%s\"", proto);
  139. *p++ = '}';
  140. r = r->next;
  141. if (r) {
  142. *p++ = ',';
  143. }
  144. }
  145. xSemaphoreGive(query_lock);
  146. *p++ = ']';
  147. *out_len = (uint32_t)p - (uint32_t)json_response;
  148. *p++ = '\0';
  149. ESP_LOGI(TAG, "JSON: %uB", *out_len);
  150. return (const char *)json_response;
  151. }
  152. void app_mdns_update_framesize(int size)
  153. {
  154. snprintf(framesize, 4, "%d", size);
  155. if(mdns_service_txt_item_set(service_name, proto, "framesize", (char*)framesize)){
  156. ESP_LOGE(TAG, "mdns_service_txt_item_set() framesize Failed");
  157. }
  158. }
  159. void app_mdns_main()
  160. {
  161. uint8_t mac[6];
  162. query_lock = xSemaphoreCreateBinary();
  163. if (query_lock == NULL) {
  164. ESP_LOGE(TAG, "xSemaphoreCreateMutex() Failed");
  165. return;
  166. }
  167. xSemaphoreGive(query_lock);
  168. sensor_t * s = esp_camera_sensor_get();
  169. if(s == NULL){
  170. return;
  171. }
  172. switch(s->id.PID){
  173. case OV2640_PID: model = "OV2640"; break;
  174. case OV3660_PID: model = "OV3660"; break;
  175. case OV5640_PID: model = "OV5640"; break;
  176. case OV7725_PID: model = "OV7725"; break;
  177. default: model = "UNKNOWN"; break;
  178. }
  179. if (strlen(CONFIG_ESP_HOST_NAME) > 0) {
  180. snprintf(iname, 64, "%s", CONFIG_ESP_HOST_NAME);
  181. } else {
  182. if (esp_read_mac(mac, ESP_MAC_WIFI_STA) != ESP_OK) {
  183. ESP_LOGE(TAG, "esp_read_mac() Failed");
  184. return;
  185. }
  186. snprintf(iname, 64, "%s-%s-%02X%02X%02X", CAMERA_MODULE_NAME, model, mac[3], mac[4], mac[5]);
  187. }
  188. snprintf(framesize, 4, "%d", s->status.framesize);
  189. snprintf(pixformat, 4, "%d", s->pixformat);
  190. char * src = iname, * dst = hname, c;
  191. while (*src) {
  192. c = *src++;
  193. if (c >= 'A' && c <= 'Z') {
  194. c -= 'A' - 'a';
  195. }
  196. *dst++ = c;
  197. }
  198. *dst++ = '\0';
  199. if(mdns_init() != ESP_OK){
  200. ESP_LOGE(TAG, "mdns_init() Failed");
  201. return;
  202. }
  203. if(mdns_hostname_set(hname) != ESP_OK){
  204. ESP_LOGE(TAG, "mdns_hostname_set(\"%s\") Failed", hname);
  205. return;
  206. }
  207. if(mdns_instance_name_set(iname) != ESP_OK){
  208. ESP_LOGE(TAG, "mdns_instance_name_set(\"%s\") Failed", iname);
  209. return;
  210. }
  211. if(mdns_service_add(NULL, "_http", "_tcp", 80, NULL, 0) != ESP_OK){
  212. ESP_LOGE(TAG, "mdns_service_add() HTTP Failed");
  213. return;
  214. }
  215. mdns_txt_item_t camera_txt_data[] = {
  216. {(char*)"board" ,(char*)CAMERA_MODULE_NAME},
  217. {(char*)"model" ,(char*)model},
  218. {(char*)"stream_port" ,(char*)"81"},
  219. {(char*)"framesize" ,(char*)framesize},
  220. {(char*)"pixformat" ,(char*)pixformat}
  221. };
  222. if(mdns_service_add(NULL, service_name, proto, 80, camera_txt_data, 5)) {
  223. ESP_LOGE(TAG, "mdns_service_add() ESP-CAM Failed");
  224. return;
  225. }
  226. xTaskCreate(mdns_task, "mdns-cam", 2048, NULL, 2, NULL);
  227. }