Skocz do zawartości

Użyteczność Github VS Code Copilot w embedded


Gieneq

Pomocna odpowiedź

Jakie macie zdanie na ten temat, może się to do czegoś przydać w naszej specyficznej branży?

Fibbonaci

image.thumb.png.95d74651610afc951a007e780024046f.png

Specyficzne dla ESP-IDF

image.thumb.png.f180004f95bc0bb3848f00abbdc2af13.png

Tu już nie wie co to gpio, ale ciekawe że wiedział jak użyć falling/rising edge

image.thumb.png.906a1c484acfdd4db555a6f2fdb0cf63.png

Tu bardziej opisowo i ogarnął, moze dlatego że kod był już gdzieś 

image.thumb.png.e26b9a5ff35d9f553376ca18f730473b.png

image.thumb.png.6b4325255a84148e55d95a712c407067.png

Link do komentarza
Share on other sites

To jeszcze Copilot Labs, też ciekawa sprawa - sidebar z narzęziami do modyfikacji kodu: https://marketplace.visualstudio.com/items?itemName=GitHub.copilot-labs

Przykładowo dla wcześniej wygenerowanego kodu:

image.thumb.png.3bac76338587a42ddfaab3036f8dd2de.png

Add types wyciągneło zmienną jako nowąlinię:

esp_timer_handle_t oneshot_timer;
esp_timer_create(&oneshot_timer_args, &oneshot_timer);

Debug wrzuciło komentarze ESP-IDF, czasem wrzuca printf - tu akurat trochę się gubi ale i tak będzie działać:

//callback function for one-shot timer
void oneshot_timer_callback(void* arg)
{
    ESP_LOGI(TAG, "Timer callback executed");
}

//initialize one-shot esp_timer with 2 seconds delay and callback function oneshot_timer_callback
void init_oneshot_timer()
{
    esp_timer_create_args_t oneshot_timer_args = {
            .callback = &oneshot_timer_callback,
            /* argument specified here will be passed to timer callback function */
            .arg = NULL,
            .name = "oneshot"
    };
    esp_timer_create(&oneshot_timer_args, &oneshot_timer);
    ESP_LOGI(TAG, "Starting timer");
    esp_timer_start_once(oneshot_timer, 2000000);
}

Make robust dodało obsługę błędów ESP-IDF:

//callback function for one-shot timer
void oneshot_timer_callback(void* arg)
{
    //do something here
}

//initialize one-shot esp_timer with 2 seconds delay and callback function oneshot_timer_callback
void init_oneshot_timer()
{
    esp_err_t err;
    esp_timer_create_args_t oneshot_timer_args = {
            .callback = &oneshot_timer_callback,
            /* argument specified here will be passed to timer callback function */
            .arg = NULL,
            .name = "oneshot"
    };
    err = esp_timer_create(&oneshot_timer_args, &oneshot_timer);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Failed to create one-shot timer: %s", esp_err_to_name(err));
        return;
    }

    err = esp_timer_start_once(oneshot_timer, 2000000);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "Failed to start one-shot timer: %s", esp_err_to_name(err));
        return;
    }
}

List steps raz ucieło program... ale raz dodało opis funkcji:

    //Create timer, set callback to oneshot_timer_callback
    //and start it once after 2,000,000 us (2 seconds)
    esp_timer_create_args_t oneshot_timer_args = {
            .callback = &oneshot_timer_callback,
            .arg = NULL,
            .name = "oneshot"

Opisu tego co robi funkcja:

void AnimationController::tick(float dt) {
    if(running) {
        accumulator += dt;
        if(accumulator > interval) {
            accumulator -= interval;
            if(!looping){
                accumulator = 0;
                stop();
            }
        }

        float progress_norm = accumulator / interval;
        progress_norm = std::max(0.0F, progress_norm);
        progress_norm = std::min(1.0F, progress_norm);
        on_animation_frame(progress_norm);
    }
}

Wygenerowany opis:

/* Here is the explanation for the code above:
1. We check if the animation is running. If not, we do nothing.
2. We increase the accumulator by the time delta.
3. If the accumulator is bigger than the interval, we subtract the interval from it and check if the animation is looping.
4. If it is not, we reset the accumulator and stop the animation.
5. We calculate the normalized progress, which is the accumulator divided by the interval.
6. We make sure that the normalized progress is between 0 and 1.
7. We call the on_animation_frame() method, which is a virtual method that we will implement in a subclass of AnimationController. */

Ciekawe że wie że dt to time delta, szok.

 

  • Lubię! 1
Link do komentarza
Share on other sites

IMHO... nie warto. Często zanim się namyśli to napiszę kod kilka razy... No i na dodatek lubi robić bugi w bardziej skomplikowanych zagadnieniach. Gdyby był za free to bym skorzystał, ale 100$ za rok za coś, co było szkolone na otwartych repozytoriach... Nie. Po pierwsze za problemy, po drugie za wykorzystanie czyjejś pracy do stworzenia produktu, który nie ma nawet wersji darmowej (poza EDU).

1 godzinę temu, Gieneq napisał:

Ciekawe że wie że dt to time delta, szok.

To wie z repozytoriów gier 😉 Tam w co drugim skrypcie jest linijka

var dt = Time.deltaTime; 

lub podobna.

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Ja tam bym niespecjalnie wierzył w te jego kody...

Cytat

Oto funkcja w C, która sprawdza, czy dany znak jest literą w kodowaniu ISO-8859-2:

#include <stdio.h>
#include <ctype.h>

int is_ISO_8859_2_letter(char c) {
   if (c >= 0xA1 && c <= 0xA6) return 1; // diacritical uppercase letters
   if (c >= 0xA9 && c <= 0xAE) return 1; // diacritical lowercase letters
   if (c >= 0xC0 && c <= 0xDE) return 1; // uppercase letters
   if (c >= 0xE0 && c <= 0xFE) return 1; // lowercase letters
   return 0; // not an ISO-8859-2 letter
}

int main() {
   char c = 'ł'; // example character
   if (is_ISO_8859_2_letter(c)) {
      printf("%c is an ISO-8859-2 letter\n", c);
   } else {
      printf("%c is not an ISO-8859-2 letter\n", c);
   }
   return 0;
}

Czy aby na pewno?

Link do komentarza
Share on other sites

I jeszcze jeden kwiatuszek:

int is_unicode_letter(char c) {
    return (c >= 0x0041 && c <= 0x005A) || (c >= 0x0061 && c <= 0x007A) || 
           (c >= 0x00C0 && c <= 0x00D6) || (c >= 0x00D8 && c <= 0x00F6) || 
           (c >= 0x00F8 && c <= 0x01BA) || (c >= 0x01BB && c <= 0x01BF) || 
           (c >= 0x01C0 && c <= 0x01C3) || (c >= 0x01C4 && c <= 0x0293) || 
           (c >= 0x0294 && c <= 0x0295) || (c >= 0x0296 && c <= 0x02AF) || 
           

(tu przerwałem generowanie)

Link do komentarza
Share on other sites

19 minut temu, ethanak napisał:

I jeszcze jeden kwiatuszek:

Ale to ChatGPT czy copilot? Bo ten pierwszy nie był szkolony do pisania kodu źródłowego i takie problemy są dość częste.

Link do komentarza
Share on other sites

ChatGPT używam w pracy równolegle z googlem i generalnie jest super. Tematy embed zna całkiem dobrze, czasem się myli ~20% i czasem nie wie co się dzieje. Ale te same problemy są z innymi mniej znanymi bibliotekami/frameworkami itp np w GLFW (Opengl dla C++) miałem problem żeby wygenerował działający przykład głównie dlatego że w GLFW jest dość nietypowy sposób linkowania biblioteki.

Ale zapytany o konkretny problem - np. wczoraj nie działał mi ISR i zagadkowo dodanie jednego dzielenia więcej było granicą działania/nie działania. Zapytany co może być przyczyną podał sensowne propozycje.

Ale znajomość niuansów samego języka, architektur na plus. Przykładowo ChatGPT bardzo mnie zaskoczył podając design pattern Entity-Component-System do gamedevu z przykładem w którym użył templating. Wrzuciłem na githuba https://github.com/Gieneq/GLFW_Game

#pragma once
#include <iostream>
#include <vector>
#include "../component/Component.h"

class Entity {
public:
    void addComponent(Component* component);
    // void removeComponent(Component* component);

    template<typename T>
    bool hasComponent() const {
        for (auto component : components) {
            T* t = dynamic_cast<T*>(component);
            if (t) {
                return true;
            }
        }
        return false;
    }

    template<typename T>
    T* getComponent() const {
        for (auto component : components) {
            T* t = dynamic_cast<T*>(component);
            if (t) {
                return t;
            }
        }
        return nullptr;
    }
    
    template<typename T>
    std::vector<T*> getComponents() const {
        std::vector<T*> result;
        for (auto component : components) {
            T* t = dynamic_cast<T*>(component);
            if (t) {
                result.push_back(t);
            }
        }
        return result;
    }
private:
    std::vector<Component*> components;
};

Jest to pewnie oklepany temat więc może to nie być rewelacja.

4 godziny temu, H1M4W4R1 napisał:

To wie z repozytoriów gier 😉 Tam w co drugim skrypcie jest linijka

Popracowałem dziś kilka godzin z Copilotem i euforia opada. Zaskoczył mnie znając:

  • jak zamienić radiany na stopnie....
  • i co to error w PID.

Poza tymi odkryciami pomaga kończyć linie, czasem oszczędza troche pisania ale na duży minus to że często trzeba klikać escape bo rzuca strasznymi śmieciami że się dziwię skąd to bierze.

Link do komentarza
Share on other sites

Dziś copilot pozytywnie mnie zaskoczył. Pisałem zapis/odczyt stanu na pendiva z ESP IDF. Wymarzyłem sobie format pliku json i użyłem do tego bibliotekę cJSON.

Wymyśliłem strukturę Storage do reprezentacji stanu:

struct Storage {
    int type{0};
    std::string version{"0.0.0"};
    float animation_interval{5000.0F};

    bool load_from_nvs();
    static Storage& get_global();
};

Żeby zapisać dane do pliku trzeba przekonwertować strukturę (serializacja) i tu copilot domyślił się po wpisaniu pierwszych kilku znaków i wygenerował cały kod serializacji. Jedyny błąd to zła struktura, ale mógł się nie domyśleć że chcę zagłębić fragment jsona jak tu:

image.thumb.png.a6a212076f7a9cb69c3b6d6b8c86e28f.png

Po drobnej poprawce postało to:

std::string Storage::to_json_str() {
    cJSON *root = cJSON_CreateObject();
    cJSON_AddStringToObject(root, "version", version.c_str());
    
    cJSON *animation = cJSON_CreateObject();
    cJSON_AddNumberToObject(animation, "type", type);
    cJSON_AddNumberToObject(animation, "interval", animation_interval);

    cJSON_AddItemToObject(root, "animation", animation);

    char *json_str = cJSON_Print(root);
    std::string result(json_str);
    free(json_str);
    cJSON_Delete(root);
    return result;
}

Co ciekawe, kolejna funkcja deserializacji była już bezbłędna:

bool Storage::from_json_str(const std::string& json_str) {
    cJSON *root = cJSON_Parse(json_str.c_str());
    if(root == NULL) {
        ESP_LOGE("Storage", "Failed to parse json");
        return false;
    }

    cJSON *version_json = cJSON_GetObjectItemCaseSensitive(root, "version");
    if(cJSON_IsString(version_json) && (version_json->valuestring != NULL)) {
        version = version_json->valuestring;
    }

    cJSON *animation = cJSON_GetObjectItemCaseSensitive(root, "animation");
    if(cJSON_IsObject(animation)) {
        cJSON *type_json = cJSON_GetObjectItemCaseSensitive(animation, "type");
        if(cJSON_IsNumber(type_json)) {
            type = type_json->valueint;
        } else {
            ESP_LOGE("Storage", "Failed to parse animation type");
            return false;
        }

        cJSON *interval_json = cJSON_GetObjectItemCaseSensitive(animation, "interval");
        if(cJSON_IsNumber(interval_json)) {
            animation_interval = interval_json->valuedouble;
        } else {
            ESP_LOGE("Storage", "Failed to parse animation interval");
            return false;
        }
    } else {
        ESP_LOGE("Storage", "Failed to parse animation");
        return false;
    }

    cJSON_Delete(root);
    return true;
}

 

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.