Увидел сегодня очень показательный пример того, как ChatGPT «пишет» программы. В общем, очередной раз читаю курс по программированию всяких встраиваемых устройств, и ближе к концу семестра, осознав весь зашитый в формулу для оценок фашизм, нарисовалась студентка с желанием сдать все и сразу, включая задания, по которым дедлайн уже прошел. Решил посмотреть код — и заподозрил неладное. Но сначала — давайте я покажу его вам в слегка сокращенном виде, найдете ли вы здесь какие-то ошибки?
#include <stdio.h> #include "periph/i2c.h" #include "periph/gpio.h" #include "periph_conf.h" #include "bme280.h" int main(void) { /* Инициализация датчика BME280 */ bme280_t bme280_dev; int bme280_res = bme280_init(&bme280_dev, I2C_DEV(0), BME280_I2C_ADDRESS); if (bme280_res != 0) { printf("Ошибка инициализации BME280: %d\n", bme280_res); return 1; } /* Получение и вывод показаний датчиков */ while (1) { /* Получение показаний BME280 */ bme280_measure(&bme280_dev); float bme280_temperature = bme280_temp_comp_2(&bme280_dev, bme280_dev.temperature); float bme280_humidity = bme280_humid_comp(&bme280_dev, bme280_dev.humidity); float bme280_pressure = bme280_pres_comp(&bme280_dev, bme280_dev.pressure); printf("BME280: температура=%.1f°C, влажность=%.1f%%, давление=%.1f мбар\n", (double)bme280_temperature, (double)bme280_humidity, (double)bme280_pressure); } xtimer_sleep(5); } return 0; }
Меня сразу смутил используемый для работы с датчиком (банальный BME280) API — он очень отдаленно напоминал реализованный в Riot OS, не говоря уж о библиотеке для Arduino или ARM mbed, или о «фирменном» бошевском драйвере. Но еще больше удивил соседний файл (с кодом, который якобы написан той же самой студенткой!), где работа с датчиком выглядела примерно так (опять же, в максимально сокращенном виде):
#include "xtimer.h" #include "bme280.h" #define BME280_DEV I2C_DEV(0) static bme280_t dev_bme280; int main(void) { int8_t res; res = bme280_init(&dev_bme280, BME280_DEV); if (res != BME280_OK) { puts("Could not initialize BME280 sensor"); return 1; } while (1) { float temperature_bme280; bme280_read_temperature(&dev_bme280, &temperature_bme280); printf("BME280 temperature: %0.1f C\n", temperature_bme280); xtimer_sleep(5); } return 0; }
Видите что-то общее? Вот и я не вижу. При этом в принципе оба варианта API мне представляются вполне обоснованными (во всяком случае, я мог бы сказать, зачем я так сделал), но этот код очевидно не скомпилируется и работать не будет. Но внешне — все выглядит довольно неплохо, названия функций, какое-то подобие семантики вызовов — все правдоподобно, но…
В общем, вы понимаете то чувство, когда ты думаешь, что со студенткой разговаривал, а на самом деле — с большим тараканом, с жуком-оборотнем.
Решил проверить догадку самостоятельно и задал ChatGPT вот такую задачу: Write a C language program for RIOT OS that uses a BME280 sensor connected by I2C bus, reads temperature, pressure and humidity values from the sensor and outputs them into UART each 10 seconds. Also, if the temperature is higher than 100 degrees Fahrenheit, a LED connected to one of GPIO pins must be switched on. When the temperature lowers, the LED is switched off.
Я думаю, вы уже догадались, что было ответом — правильно, третий вариант API! (но с градусами Фаренгейта я хорошую подставу придумал):
#include "bme280.h" #include "periph/gpio.h" #include "periph/i2c.h" #include "periph/uart.h" #include "xtimer.h" #define I2C_DEV (I2C_DEV(0)) #define BME280_ADDR (0x76) #define LED_PIN (GPIO_PIN(PORT_A, 5)) #define LED_ON (0) #define LED_OFF (1) static bme280_t dev; static gpio_t led; static void init(void) { i2c_init(I2C_DEV); bme280_init(&dev, I2C_DEV, BME280_ADDR); uart_init(UART_DEV(0), 115200, UART_FLAG_NONE); gpio_init(LED_PIN, GPIO_OUT); } int main(void) { init(); while (1) { bme280_read_fixed(&dev); printf("Temperature: %ld.%02lu C\n", dev.temperature / 100, dev.temperature % 100); printf("Pressure: %lu.%02lu hPa\n", dev.pressure / 100, dev.pressure % 100); printf("Humidity: %lu.%02lu %%\n", dev.humidity / 1024, (dev.humidity * 100) / 1024 % 100); if (dev.temperature > 100 * 100) { gpio_write(led, LED_ON); } else { gpio_write(led, LED_OFF); } xtimer_sleep(10); } return 0; }
Но вот что интересно — так это время, которое пройдет между написанием кода и обнаружением наебалова. Принято считать, что одна из сложностей в эмбеддеде всех мастей — это долгий цикл обратной связи между написанием кода и получением результата — работает/не работает/надо переделать. Так вот, для наебалова в таком вот духе он сокращается до одной команды в консоли — наберите make flash
и тут же, не отходя от кассы, получите тугую струю ссанины в ебало в виде совершенно невнятных ошибок компилятора. А вот если у вас модный язык вроде Javascript или Python — то с вот таким синтаксически корректный бредом можно долго и плодотворно заниматься debugging into existence. Программист программировает, получька капает.
Будующее такое яркое.
1. «Принято считать, что одна из сложностей в эмбеддеде всех мастей — это долгий цикл обратной связи между написанием кода и получением результата — работает/не работает/надо переделать.»
Если это касается исправления багов вылезших у конечного пользователя, соглашусь, хотя формулировка и корявая.
2. «Текст песни «The Scientist» группы Coldplay обнаружился в прошивке SKC2000_S2681103 для контроллера SSD Kingston.» Тоже чатгпт небось виноват.
Нет, это скорее про Computer Turnaround Time из COCOMO:
This reflects the level of computer response time experienced by the project team developing the software product. The response time is the average time from when the developer submits a job to be run until the results are back in the developer’s hands (hey — quit laughing — that was important back then).
Вот у меня сейчас студентка лепит mesh-сеточку поверх BLE, там полный набор тестов на оборудовании FIT IoT-Lab (20 штук nrf52-dk и nrf52840-dk) прогоняется примерно за 7-8 часов, интерактивной отладки практически нет, «на столе» некоторые эффекты увидеть невозможно.
Ок, согласен. Тем не менее фраза «эмбеддед всех мастей» тут вводит в заблуждение. У меня в совсем неумном пылесосе движком старый PIC управляет (плавный пуск хуе-мое) — тоже вроде эмбеддед, но ни за что не поверю, что там нужно 100500 человекочасов на реализацию и отладку.
Кароч, чего только эмбеддедом ни назовут.
Да не, даже у сраного пика в пылесосе цикл «написал код-запустил-не работает» в разы длиннее, чем у сопоставимого десктопного приложения. Тут ты компилируешь, прошиваешь (ЕМНИП, у пиков внутрисхемное программирование хероватое, поэтому берешь, суешь его в панельку программатора, потом ставишь в панельку на целевой плате), дальше запускаешь на «стенде», смотришь на поведение этого пика осциллографом и логическим анализатором, …
Не, есть, конечно, симуляторы вроде Proteus или встроенного в MPLAB, но там тоже есть свои заморочки.