diff --git a/Makefile b/Makefile index de2f1a0..e3df53f 100644 --- a/Makefile +++ b/Makefile @@ -25,10 +25,12 @@ INCLUDE_DIRS += -I${FREERTOS_PLUS_DIR}/Source/FreeRTOS-Plus-Trace/strea INCLUDE_DIRS += -I${FREERTOS_PLUS_DIR}/Source/FreeRTOS-Plus-Trace/kernelports/FreeRTOS/include INCLUDE_DIRS += -I${FREERTOS_PLUS_DIR}/Source/FreeRTOS-Plus-Trace/kernelports/FreeRTOS/ + SOURCE_FILES := $(wildcard *.c) SOURCE_FILES += $(wildcard ${FREERTOS_DIR}/Source/*.c) # Memory manager (use malloc() / free() ) SOURCE_FILES += ${KERNEL_DIR}/portable/MemMang/heap_3.c + # posix port SOURCE_FILES += ${KERNEL_DIR}/portable/ThirdParty/GCC/Posix/utils/wait_for_event.c SOURCE_FILES += ${KERNEL_DIR}/portable/ThirdParty/GCC/Posix/port.c @@ -58,12 +60,10 @@ SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/StaticAllocation.c SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/StreamBufferDemo.c SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/StreamBufferInterrupt.c SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/TaskNotify.c -SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/TimerDemo.c - - +SOURCE_FILES += ${FREERTOS_DIR}/Demo/Common/Minimal/TimerDemo.c CFLAGS := -ggdb3 -LDFLAGS := -ggdb3 -pthread +LDFLAGS := -ggdb3 -pthread -lmosquitto CPPFLAGS := $(INCLUDE_DIRS) -DBUILD_DIR=\"$(BUILD_DIR_ABS)\" CPPFLAGS += -D_WINDOWS_ diff --git a/main_blinky.c b/main_blinky.c index 21b39fa..548bf54 100644 --- a/main_blinky.c +++ b/main_blinky.c @@ -1,6 +1,7 @@ #include // printf(), FILE, popen(), pclose() #include // ogólne funkcje standardowe #include // operacje na stringach +#include //bibliotek do bool #include "FreeRTOS.h" #include "task.h" @@ -10,6 +11,19 @@ #include "cJSON.h" // biblioteka do parsowania JSON +#include +#include + +//Dane do mosquitto connect +#define IP_adress "10.255.150.118" +#define port 1883 +#define life_time 60 //Ile ma czekać na brokera (ping) + +//Logowanie się do usera odbierającego mqtt +#define USER_NAME "mosq" +#define PASS "admin" + + // Klucz API z OpenWeatherMap #define OWM_API_KEY "d88799a668f54c560b3f420cd37685fd" @@ -21,8 +35,8 @@ //Punkty Pomiarowe const double latitudes[] = { //szerokości geograficzne 49.000000, - 49.449156, - 49.898311, + //49.449156, + //49.898311, //50.347467, //50.796622, //51.245778, @@ -60,85 +74,123 @@ TaskHandle_t send_data = NULL; //Handler od Timera TimerHandle_t myTimer = NULL; +//Handler kolejki +QueueHandle_t jsonQueue; + //Semafor do wysłania danych SemaphoreHandle_t czekaj_na_dane = NULL; static SemaphoreHandle_t dataReadySem = NULL; -// Funkcja pobiera surowy JSON z OpenWeatherMap dla zadanej długości i szerokości geograficznej +// Funkcja pobiera surowych JSON z OpenWeatherMap dla zadanej długości i szerokości geograficznej static int fetch_owm_json(char *json_buf, size_t buf_size, float latitudes, float longitudes) { - char cmd[4096]; + char cmd[1024]; FILE *fp; size_t total = 0; // liczba wczytanych bajtów - snprintf( - cmd , - sizeof(cmd), - "curl -s \"https://api.openweathermap.org/data/2.5/weather" - "?lat=%f&lon=%f&appid=%s&units=metric&lang=pl\"", - latitudes, longitudes, OWM_API_KEY - ); + snprintf( + cmd , + sizeof(cmd), + "curl -sS -f \"https://api.openweathermap.org/data/2.5/weather" + "?lat=%f&lon=%f&appid=%s&units=metric&lang=pl\"", + latitudes, longitudes, OWM_API_KEY + ); - //Sprawdzenie czy dobrze się wszytsko zapisuje fp = popen(cmd, "r"); - if (fp == NULL) - { - return -1; - } - while (!feof(fp) && total < buf_size - 1) - { + if (fp == NULL){ + printf("Blad uruchomienia procesu curl fp == NULL \n"); + exit(EXIT_FAILURE); + } + + while (!feof(fp) && total < buf_size - 1){ size_t n = fread(json_buf + total, 1, buf_size - 1 - total, fp); total += n; } + printf("-------------------------------------------"); + printf("\n"); + printf("Ilość pobranych danych to %d \n", (int)total); // Dodanie znaku końca stringa json_buf[total] = '\0'; // Zamknięcie strumienia po cur - pclose(fp); + int status = pclose(fp); - if (total == 0) - { - return -2; + if(status != 0){ + printf("curl zakonczyl sie bledem status != 0, status = %d\n", status); + exit(EXIT_FAILURE); + } + + else{ + printf("Poprawnie zakończono proces odczytów danych z strony OWM \n"); + return 0; } - return 0; } + void get_data_from_parse_JSON(cJSON *parseJSON, cJSON *newJSON, const char *nazwa_obiektu, const char *dana){ + + if (parseJSON != NULL){ + + cJSON *obiekt = cJSON_GetObjectItemCaseSensitive(parseJSON, nazwa_obiektu); + + if(cJSON_IsObject(obiekt)){ + cJSON *zmienna = cJSON_GetObjectItemCaseSensitive(obiekt, dana); + if(cJSON_IsNumber(zmienna)){ + + printf("%s: %.5f \n",dana, zmienna -> valuedouble); + //Dopisanie do JSONA + + cJSON_AddNumberToObject(newJSON, dana, zmienna -> valuedouble); + } + else{ + printf("BŁAD W ODCZYCIE ZMIENNEJ: %s \n",dana); + } + } + else{ + printf("Element %s nie jest obiektem w %s \n",dana , nazwa_obiektu); + } + } + else{ + printf("Bład oczytu danych z JSONA z OWM \n"); + } +} + + // Funkcja FreeRTOS odpowiedzialny za pobieranie i parsowanie pogody void vWeatherTask(void *pvParameters){ (void)pvParameters; char json[JSON_BUF_SIZE]; // bufor na odpowiedź JSON //Wielkości tablic z pomiarami - int count_lat = ((int)sizeof(latitudes)/sizeof(latitudes[0])); - int count_long = ((int)sizeof(longitudes)/sizeof(longitudes[0])); + int count_lat = (sizeof(latitudes)/sizeof(latitudes[0])); + int count_long = (sizeof(longitudes)/sizeof(longitudes[0])); printf("Ilość pomiarów: %d \n", count_lat * count_long); - - // Nieskończona pętla taska for (;;){ ulTaskNotifyTake(pdTRUE, portMAX_DELAY); //Czekanie na callback timera + printf("Task vWeatherTask wybudzony przez timer \n"); + + if(xSemaphoreTake(czekaj_na_dane, portMAX_DELAY) == pdTRUE){ - xSemaphoreTake(czekaj_na_dane, portMAX_DELAY); printf("Odczyt danych z OMW \n"); - cJSON *data = cJSON_CreateArray(); + cJSON *data = cJSON_CreateArray(); //Tablica na wybrane dane if (data == NULL) { - continue; + printf("Nie udało się zrobić tablicy do zapisu danych \n"); + exit(EXIT_FAILURE); } - printf("Task vWeatherTask wybudzony przez timer \n"); - for(int i = 0; i < count_lat; i++){ for(int j = 0; j < count_long; j++){ cJSON *item = cJSON_CreateObject(); if (item == NULL){ - continue; + printf("Nie udało się zrobić objektu do zapisu danych \n"); + exit(EXIT_FAILURE); } // Pobranie JSON-a z OpenWeatherMap @@ -146,47 +198,15 @@ void vWeatherTask(void *pvParameters){ // Parsowanie tekstu JSON do struktury cJSON cJSON *root = cJSON_Parse(json); - if (root != NULL){ - // Pobranie obiektu "main","coord" i "wind" z JSON-a - cJSON *coord = cJSON_GetObjectItemCaseSensitive(root, "coord"); - cJSON *main_obj = cJSON_GetObjectItemCaseSensitive(root, "main"); - cJSON *wind = cJSON_GetObjectItemCaseSensitive(root, "wind"); - // Pobranie tablicy "weather" do opisu pogody - cJSON *weather_arr = cJSON_GetObjectItemCaseSensitive(root, "weather"); - - // Pobieranie lot i lan - if(cJSON_IsObject(coord)){ - cJSON *lon = cJSON_GetObjectItemCaseSensitive(coord, "lon"); - cJSON *lat = cJSON_GetObjectItemCaseSensitive(coord, "lat"); - - if (cJSON_IsNumber(lon) && cJSON_IsNumber(lat)){ - - printf("Długość geograficzna: %.5f \t Szerokość geograficzna: %.5f \n", lon -> valuedouble, lat -> valuedouble ); - //Dopisanie do JSONA - cJSON_AddNumberToObject(item, "latitudes", lat ->valuedouble); - cJSON_AddNumberToObject(item, "longitudes", lon ->valuedouble); - } - } - //Pobieranie temp - if (cJSON_IsObject(main_obj)){ - cJSON *temp = cJSON_GetObjectItemCaseSensitive(main_obj, "temp"); - - if (cJSON_IsNumber(temp)){ - printf("Temperatura: %.1f C\n", temp->valuedouble); - cJSON_AddNumberToObject(item, "temp", temp ->valuedouble); - } - } - //Pobieranie wind - if (cJSON_IsObject(wind)){ - cJSON *speed = cJSON_GetObjectItemCaseSensitive(wind, "speed"); - - if (cJSON_IsNumber(speed)){ - printf("Wiatr: %.2f m/s \n", speed -> valuedouble); - cJSON_AddNumberToObject(item, "wind speed", speed -> valuedouble); - } - } + get_data_from_parse_JSON(root, item, "coord", "lon"); + get_data_from_parse_JSON(root, item, "coord", "lat"); + get_data_from_parse_JSON(root, item, "main", "temp"); + get_data_from_parse_JSON(root, item, "wind", "speed"); + if (root != NULL){ + cJSON *weather_arr = cJSON_GetObjectItemCaseSensitive(root, "weather"); + // Pobieranie opisu if (cJSON_IsArray(weather_arr)){ // Pobieranie pierwszego element tablicy weather[0] @@ -227,9 +247,9 @@ void vWeatherTask(void *pvParameters){ printf("%s\n", json_text); free(json_text); } - - cJSON_Delete(data); - data = NULL; + + xQueueSend(jsonQueue, &data, portMAX_DELAY); + xSemaphoreGive(czekaj_na_dane); printf("Przekazanie semafora do send_data \n"); @@ -238,32 +258,85 @@ void vWeatherTask(void *pvParameters){ //vTaskDelay(pdMS_TO_TICKS(PERIOD_ASK)); - } // nieskończony for + } + else{ + printf("Bład z pobraniem Semaphora: SemaphoreHandle_t czekaj_na_dane"); + } + } // nieskończony for } - - -//Funckja odpowiedzialna za przesyłanie danych do C2 +//Funkcja odpowiedzialna za przesyłanie danych do C2 void vSendData(void *pvParameters){ (void)pvParameters; - for(;;){ + cJSON *data; + int rc; + for(;;){ xSemaphoreTake(dataReadySem, portMAX_DELAY); printf("Można wysyłać dane \n"); + + if (xQueueReceive(jsonQueue, &data, portMAX_DELAY) == pdPASS){ + printf("Przekazano dane \n"); if (xSemaphoreTake(czekaj_na_dane, portMAX_DELAY) == pdTRUE){ printf("Przesyłanie danych do C2 \n"); - vTaskDelay(pdMS_TO_TICKS(2000)); + struct mosquitto *mosq = mosquitto_new("publisher-test", true, NULL); + if(mosq == NULL){ + printf("Blad tworzenia klienta\n"); + exit(EXIT_FAILURE);; + } + + rc = mosquitto_username_pw_set(mosq, USER_NAME, PASS); + if(rc != MOSQ_ERR_SUCCESS){ + printf("Blad ustawiania loginu i hasla: %s \n", mosquitto_strerror(rc)); + mosquitto_destroy(mosq); + exit(EXIT_FAILURE); + } + + do { + errno = 0; + rc = mosquitto_connect(mosq, IP_adress, port, life_time); + } while(rc == MOSQ_ERR_ERRNO && errno == EINTR); + + if(rc!= 0){ + printf("Problem z połączeniem z brokrem, error code %d \n", rc); + printf("mosquitto rc=%d (%s), errno=%d (%s) \n", rc, mosquitto_strerror(rc), errno, strerror(errno)); + mosquitto_destroy(mosq); + exit(EXIT_FAILURE); + } + + else{ + printf("Udało się połączyć z brokerem \n"); + + char *json_text = cJSON_PrintUnformatted(data); + + rc = mosquitto_publish(mosq, NULL, "projekt/pogoda/C2", strlen(json_text), json_text, 0, false); + + if(rc != MOSQ_ERR_SUCCESS){ + printf("Blad publish: rc=%d (%s)\n", rc, mosquitto_strerror(rc)); + } + else{ + mosquitto_loop(mosq, 100, 1); + mosquitto_disconnect(mosq); + mosquitto_destroy(mosq); + printf("Publish OK \n"); + + } + } + //kasowanie pamięci / usuwanie wybranych danych + cJSON_Delete(data); + data = NULL; xSemaphoreGive(czekaj_na_dane); printf("Przekazanie semafora do take_dane \n"); } - } + } + } } @@ -276,10 +349,17 @@ static void TimerCallback(TimerHandle_t xTimer) void main_blinky(void){ + //Uruchomienie mqtt + mosquitto_lib_init(); + czekaj_na_dane = xSemaphoreCreateMutex(); dataReadySem = xSemaphoreCreateBinary(); + jsonQueue = xQueueCreate(5, sizeof(cJSON *)); + + BaseType_t ok; + ok = xTaskCreate( vWeatherTask, // funkcja taska "Weather", // nazwa taska