All streams
Search
Write a publication
Pull to refresh
206
0.4
Send message

Сами же и ответили. Не пришлось искать нормального разработчика. Был только ненормальный без знания cmake. И все получилось.

Я думаю, что ошибка с семафором осталась только от того что была маленькая квота на запросы. И приходилось пока не пройдет заданное время ожидания самому глазами проверять код. Я не мог просто последовательно ему командовать перепроверить все функции. Да и файл инструкций не применял. На скорую руку все делал.

Семафоры, кстати, мне потом Coipilot предложил убрать и убрал. А это, как понимаете, замах на архитектуру. Сэкономил намного Flash памяти.

Копнул еще глубже.
И оказывается на момент 1821 года, когда Харрис пошел со своей заявкой еще не был открыт закон Ома. И еще десятки лет спустя этот закон не применяли.
Т.е. Харрис по сути в те времена действительно был шарлатаном и никак не мог доказать что медь лучше цепей в плане пропускания больших токов.
Это просто удивительный факт, что инспектора просекли лучше Харриса и Ома что действительно работает. Поскольку все видели как одинаково горят и цепи и медь от молний. Учтем, что медь в те времена могла иметь в два раза худшую электропроводность. Промышленное производтсво меди для проводов и шин еще не началось.

Какой толщины должна была быть медь, как ее клепать, как защитить от коррозии, как защитить от гальванической коррозии другие металлы соединенные с медью?
Это что, всё Харрис знал?

Не всё так просто. Молнии до сих пор уничтожают электронику, несмотря на то, что всё напичкано молниеотводами. Даже если основная часть разряда попадает в молниеотвод, отдельные каналы могут расходиться в стороны.

Молниеотводы приняли не потому, что Харрис был таким настойчивым, а потому что случаи стали лучше документировать. То есть флот проводил эксперименты на себе и в итоге нашёл приемлемый вариант. После установки молниеотводов Харриса тяжёлые повреждения от молний всё ещё происходили примерно в 30% случаев.

Словом, настоящие герои здесь — флотские инспекторы. Именно благодаря их работе и наблюдениям была выбрана система Харриса.

Это довольно странно качать в Zip, а потом за свои же деньги заставлять GPT это распаковывать при этом потерять историю коммитов. Лучше смотреть прямо на GitHub-е. Там GPT дополнительно посмотрит как юзер активничал.

Но мой o3 пошел дальше и все же думает, что автор втихую использовал один из корпоративных генераторов сорсов:

- Vector DaVinci Configurator Classic / Pro
- EB tresos Studio
- ETAS ISOLAR-A, Mentor VSTAR, Artop

Но только потом он исходники еще сильно кастрировал.

Вот что сказал об этом ChatGPT o3

Короткий вывод

В репозитории фактически лежит лишь набор «заготовок» для системы MCAL-драйверов: несколько Makefile/CMake-скриптов и пустой read_me.txt. Исходников, которые можно прямо собрать и запустить, там нет — большинство файлов, на которые ссылаются скрипты, отсутствуют. То есть «из коробки» использовать ничего не получится: придётся либо дописывать недостающие модули, либо подключать внешний MCAL-код.

Это что-то новое - выкладывать шлак и по его мотивам писать статьи по теме микрокнтроллеров.

Откуда тогда столько файлов?

MCAL-слой часто собирают скриптом-генератором, читающим YAML/Kconfig с конфигурацией проекта. Такой скрипт:

  1. делает копии общих template-файлов в каталог проекта;

  2. проставляет нужные #define и CMake/Make-флаги;

  3. генерирует _commands.c для CLI-оболочки, _diag.c для диагностики и т. д.

В коммите как раз видны одинаково оформленные пары файлов («general», «diag», «commands») для каждого переферийного блока — это типичный вывод такого инструмента.

Да, нынче трудно стало водить за нос.

У меня GitHub Copilot работает лучше всего утром по европейскому времени, когда, видимо, в Америке ещё не начался рабочий день.
К вечеру работа дико деградирует.
Файлы инструкций, несмотря на обещания, нагло игнорируются.
Даже если несколько раз переспрашиваешь, понял ли он файл инструкций — всё равно частично игнорит.
Помогает сброс и начало нового чата. Накопление контекста чата выше какого-то уровня, похоже, вредит.
А так, руками уже пару месяцев ничего не пишу. Забыл, как выглядит бумага. Подписываюсь с трудом — разучился писать. Плохо умножаю в уме.

Но код на уровне файлов получаю чистейший, в жизни сам никогда такого чистого кода не писал.
Могу теперь позволить себе не придумывать имена — GPT 4.1 придумывает имена лучше меня.
Могу применять более безопасные функции из стандартных либ, которые раньше избегал просто потому, что у них больше аргументов (например, повсеместно использовал небезопасный sprintf вместо snprintf).
Могу теперь не идти на компромисс с надежностью и логированием, потому что экономил силы и не ставил проверки, не соблюдал консистентность логов.
Полностью отпала проблема с комментированием и актуальностью комментариев.

Но да, иногда у Copilot сносит крышу, и он может взять и удалить нужную функцию ни с того ни с сего. Поэтому каждый шаг нужно коммитить. План - Copilot Pro+

При чем тут упорство и тем более труд?
Весь код сгенерен с помощью ИИ.
Самый писк - диалог построенный в скрипте на PowerShell с жесткими неадаптивными размерами.

VBA не был использован скорее всего по тому, что там надо гораздо больше двигать мышкой для создаия и вызова таких модулей.

А Python не был выбран потому, что отладка автора не волновала, не он же кодирует.

Словом предпочтения и рейтинг языков в скором времени причудливо будут меняться.


Почти все популярные фреймворки для микроконтроллеров на сегодня имеют RNDIS.
Windows 11 подхватывает RNDIS также без всяких бубнов с драйверами.
Но при этом имеет и загрузку через FTP более чем удобную и стандартную, и тот же терминал что и через COM порт, и сам порт искать не надо, и еще с десяток сервисов.
А с USB-COM вы определенно лишаете себя кучи удовольствий.

Я даже больше скажу.
Вот прямо сейчас я сделал на Python загрузчик. Буквально за пять минут и через две итерации:

Он реально работает!
Только что проверил на своем дивайсе. Конвертирует HEX в бинарник и загружает через FTP сервер реализованый в моем модуле.
А вот весь текст скрипта:

Скрытый текст
import os
import ftplib
import tempfile
import sys
from intelhex import IntelHex
import wx


def convert_hex_to_bin(hex_path, bin_path):
    """
    Convert Intel HEX file to a binary file using IntelHex library.
    """
    ih = IntelHex()
    ih.loadhex(hex_path)
    # Write binary file; fill gaps with 0xFF
    # The tobinfile signature is (filename, start=None, end=None, pad=0xFF)
    ih.tobinfile(bin_path, pad=0xFF)


class FTPUploaderFrame(wx.Frame):
    def __init__(self, parent=None, title="FTP HEX->BIN Uploader"):
        super().__init__(parent, title=title, size=(500, 400))
        panel = wx.Panel(self)
        vbox = wx.BoxSizer(wx.VERTICAL)

        # FTP Connection
        gb_conn = wx.StaticBox(panel, label="FTP Connection")
        sbs_conn = wx.StaticBoxSizer(gb_conn, wx.VERTICAL)
        fgs = wx.FlexGridSizer(4, 2, 10, 10)
        fgs.AddGrowableCol(1, 1)
        fgs.Add(wx.StaticText(panel, label="Host:"), 0, wx.ALIGN_CENTER_VERTICAL)
        self.host_txt = wx.TextCtrl(panel, value="192.168.16.137")
        fgs.Add(self.host_txt, 1, wx.EXPAND)
        fgs.Add(wx.StaticText(panel, label="Port:"), 0, wx.ALIGN_CENTER_VERTICAL)
        self.port_txt = wx.TextCtrl(panel, value="21")
        fgs.Add(self.port_txt, 1, wx.EXPAND)
        fgs.Add(wx.StaticText(panel, label="Username:"), 0, wx.ALIGN_CENTER_VERTICAL)
        self.user_txt = wx.TextCtrl(panel, value="ftp_login")
        fgs.Add(self.user_txt, 1, wx.EXPAND)
        fgs.Add(wx.StaticText(panel, label="Password:"), 0, wx.ALIGN_CENTER_VERTICAL)
        self.pass_txt = wx.TextCtrl(panel, value="pass", style=wx.TE_PASSWORD)
        fgs.Add(self.pass_txt, 1, wx.EXPAND)
        sbs_conn.Add(fgs, 1, wx.ALL|wx.EXPAND, 10)
        vbox.Add(sbs_conn, 0, wx.ALL|wx.EXPAND, 10)

        # HEX File Selection
        gb_file = wx.StaticBox(panel, label="HEX File")
        sbs_file = wx.StaticBoxSizer(gb_file, wx.HORIZONTAL)
        self.file_txt = wx.TextCtrl(panel, value="Test.hex", style=wx.TE_READONLY)
        file_btn = wx.Button(panel, label="Browse...")
        file_btn.Bind(wx.EVT_BUTTON, self.on_browse)
        sbs_file.Add(self.file_txt, 1, wx.ALL|wx.EXPAND, 5)
        sbs_file.Add(file_btn, 0, wx.ALL, 5)
        vbox.Add(sbs_file, 0, wx.LEFT|wx.RIGHT|wx.EXPAND, 10)

        # Progress Gauge
        self.gauge = wx.Gauge(panel, range=100, size=(450, 25))
        vbox.Add(self.gauge, 0, wx.ALL|wx.CENTER, 10)

        # Upload Button
        upload_btn = wx.Button(panel, label="Convert & Upload")
        upload_btn.Bind(wx.EVT_BUTTON, self.on_upload)
        vbox.Add(upload_btn, 0, wx.ALL|wx.CENTER, 10)

        panel.SetSizer(vbox)
        self.Centre()

    def on_browse(self, event):
        with wx.FileDialog(
            self,
            "Select HEX file",
            wildcard="HEX files (*.hex)|*.hex|All files (*.*)|*.*",
            style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST
        ) as dlg:
            if dlg.ShowModal() == wx.ID_OK:
                path = dlg.GetPath()
                self.file_txt.SetValue(path)

    def on_upload(self, event):
        host = self.host_txt.GetValue().strip()
        port_str = self.port_txt.GetValue().strip()
        username = self.user_txt.GetValue().strip()
        password = self.pass_txt.GetValue().strip()
        hex_path = self.file_txt.GetValue()

        if not host or not hex_path:
            wx.MessageBox(
                "Please specify both FTP host and HEX file.",
                "Error",
                wx.OK | wx.ICON_ERROR
            )
            return
        try:
            port = int(port_str)
        except ValueError:
            wx.MessageBox(
                "Port must be a number.",
                "Error",
                wx.OK | wx.ICON_ERROR
            )
            return

        bin_path = os.path.splitext(hex_path)[0] + ".bin"
        try:
            convert_hex_to_bin(hex_path, bin_path)
        except Exception as e:
            wx.MessageBox(
                f"Failed to convert HEX to binary:\n{e}",
                "Conversion Failed",
                wx.OK | wx.ICON_ERROR
            )
            return

        try:
            filesize = os.path.getsize(bin_path)
            uploaded = 0
            import time
            start_time = time.time()

            def callback(data):
                nonlocal uploaded
                uploaded += len(data)
                percent = int(uploaded / filesize * 100)
                wx.CallAfter(self.gauge.SetValue, percent)

            with ftplib.FTP() as ftp:
                ftp.connect(host, port)
                ftp.login(username, password)
                with open(bin_path, 'rb') as f:
                    ftp.storbinary(
                        f'STOR {os.path.basename(bin_path)}',
                        f,
                        blocksize=8192,
                        callback=callback
                    )
            elapsed = time.time() - start_time
            speed = filesize / elapsed if elapsed > 0 else 0
            # Show dialog with bytes and speed
            dlg = wx.MessageDialog(
                self,
                f"Uploaded {filesize} bytes in {elapsed:.2f} s\nSpeed: {speed:.1f} bytes/sec",
                "Upload Complete",
                wx.OK
            )
            dlg.SetOKLabel("Close")
            dlg.ShowModal()
            dlg.Destroy()
            self.gauge.SetValue(0)
        except Exception as e:
            wx.MessageBox(
                f"FTP upload error:\n{e}",
                "Upload Failed",
                wx.OK | wx.ICON_ERROR
            )
            return

        # Optionally cleanup
        # os.remove(bin_path)


def main():
    app = wx.App(False)
    frame = FTPUploaderFrame()
    frame.Show()
    app.MainLoop()


# Unit tests for conversion
import unittest
class TestHexConversion(unittest.TestCase):
    def test_simple_conversion(self):
        # Create a minimal Intel HEX file with 2 lines of data (16 bytes each)
        content = (
            ":020000040000FA\n"
            ":100000000C9423000C944E000C944E000C944E00A6\n"
            ":00000001FF\n"
        )
        with tempfile.NamedTemporaryFile('w+', suffix='.hex', delete=False) as tmp_hex:
            tmp_hex.write(content)
            tmp_hex.flush()
            bin_path = tmp_hex.name.replace('.hex', '.bin')
            convert_hex_to_bin(tmp_hex.name, bin_path)
            self.assertTrue(os.path.exists(bin_path))
            size = os.path.getsize(bin_path)
            # Expect 16 bytes of data
            self.assertEqual(size, 16)
            os.remove(bin_path)
        os.remove(tmp_hex.name)

    def test_conversion_with_empty_file(self):
        # Create an empty HEX file should result in 0-byte binary
        with tempfile.NamedTemporaryFile('w+', suffix='.hex', delete=False) as tmp_hex:
            tmp_hex.write("")
            tmp_hex.flush()
            bin_path = tmp_hex.name.replace('.hex', '.bin')
            convert_hex_to_bin(tmp_hex.name, bin_path)
            self.assertTrue(os.path.exists(bin_path))
            size = os.path.getsize(bin_path)
            self.assertEqual(size, 0)
            os.remove(bin_path)
        os.remove(tmp_hex.name)

if __name__ == "__main__":
    if len(sys.argv) > 1 and sys.argv[1] == '--test':
        unittest.main(module=__name__, argv=sys.argv[:1])
    else:
        main()

Даже юнит-тест прикручен!

Тему с загрузчиками можно закрывать полностью

Десктоп утилиты для пршивки - плохая идея. Даже писать приложение для смартфона плохая идея. Придется заниматься их поддержкой и постоянным переносом на новые апгрейды OS и тестированием. Но не для того делают загрузчики чтобы получить головную боль.

Что важнее для инфраструктуры загрузчика - это кастомная упаковка, надежная шифрация и гибкость способов доставки.
Даже WEB интерфейс не лучший вариант. Лучше иметь просто открытый WEB API для загрузчика. А уж "морду" вам нарисует ChatGPT какую хотите и итегрирует в систему заказчика. Никаких артефактов производителя чипов не будет.

Вот в этом загрузчике доставка прошивки сделана даже по MQTT протоколу через любого MQTT брокера, даже самого примитивного. Это в добавок к FTP, HTTP, и просто USB Mass Storage Class, и в крайнем случае можно передать через SD карту с аппаратным паролем.

Решение с аргументами в командной строке утилиты тоже уже архаичное.
ИМХО, но лучшее решение - конфигурационный файл. Как в утилите упаковщика из проекта этого загрузчика.
Это гораздо мощнее и гибче.
А вот сам конфигурационный файл вы можете создавать хоть на Python хоть на Bash.
На это есть GitHub Copilot, который вам наваяет любых сборщиков конфигов за секунды.
Python и Bash знать при этом не нужно. Copilot пишет код на на них с первого раза и без ошибок. Потому что он умеет их сам компилировать, запускать и перепроверять.

А какую пользу приносят песни и пляски?
Один факт что на Хабре статьи идут потоком и не уменьшаются уже внушает спокойствие.
Это игра под названием жизнь. Да пускай пишут тут о чем угодно.
Я просто читаю названия и уже умнею.
Никогда особо не надеялся тут узнать что-то сильное практически полезное.
Но зато здесь всегда находятся идеи, научпоп или новости про которые потом можно рассказать приятелям за обедом.
А могут и спровоцировать на реакцию в коментах. Тоже приятно и структурирование времени и эрудиция растет.
Словом хабр торт, чтобы тут не писали. Слава модераторам!

Не думаю. Быстрая электронная защита типа такой - AOZ1380DI-01 стоит копейки, и должна стоять везде. И наверняка стоит. Обеспечивает скорость отключения в сотню микросекунд. И все бы нормально.
Но потому это и челендж, что просто так замкнуть и грохнуть USB порт с возникновением внутреннего замыкания не удастся.
Это последствия пробоя именно силовых транзисторов электронной защиты от нерегулярных, очень частых глитчей на границе срабатывания. Поэтому грифели должны работать лучше чем скрепки. И елозить по разъему надо очень долго чтобы добиться "успеха". Если у вас на руках статика, то процесс ускорится. Но это уже самые умные ребятишки догадываются.

Но что еще печальней, таким образом можно убить любую электронную защиту на любых разъемах. И судя по видео, детвора реально не стесняется в любых разъемах шурудить.


Так этого как раз автор статьи и боится.
Если почитать его внимательней.

Прям копытами бъет вступить в конкурентную схватку за оставшиеся места.
Он надеется что станет бежать еще быстрее. Он же такой сообразительный и любопытный, с интуицией (интуиция - это всего лишь забытые знания) Освоит новые направления, не то что эти ленивые джуны. Но они не ленивые, они просто не имели доступа к хорошему обучению. Теперь имеют. ИИ - великий уравнитель.И начнется чистая рулетка.

И что интересно, гуманного решения нет.
ChatGPT несет ту же пургу что и автор, смысл которой в неизбежности жестокой конкуренции и переквалификации.
Если экономические власти не примут программы по расширению рабочих мест, то наступит ад. Будет шок безработицы в IT, какой был у ресторанов при ковиде, только длится будет дольше.

Про то что утверждал Рональд Коуз тут немного неправильно. Он одним из главных условий ставил точное определение прав собственности. Там у него собственность распростарнялась даже на воздух. Вообще на всё!
Иначе как можно сделать мгновенный автоматизированный договор по поводу чистоты воздуха если не знаем у кого права собственности на него.

А тут в реальности имеем кучу войн за собственность.
Так что Рональд Коуз отдыхает и интересен просто своим парадоксом нулевых фрикций.

Про большие генераторы все очевидно. Сам делал по молодости разрыватель для малой гидростанции. И сломал лопасти генератора, когда внезапно отлючил его от сети. Тот пошел раскручиваться, ушел в разнос.

Но с возобновляемой энергетикой все хитрее.
Все европейские сетевые инверторы обязаны иметь собственную автоматику защиты от островного режима (anti-islanding)
Но в Испании есть еще регламент Real Decreto 647/2020 обязывающий ставить внешние расцепители управляемые централизованно оператораями электрсетей.
Есть спецификация их компании оператора Endesa e-Distribución для всех генераторов, когда и как отключать автоматичеки и за какое время. Там речь о 200 мс макс.
Но расцепление происходит физически за ~50 мс. Зависит от свойств контактора. На самом деле от свойств искры в контакторе.

Современная цифровые релейная защита работают с частотой сэмплирования до 64 сэмплов/на цикл частоты. Команды передаются по Ethernet LAN за 200 мкс в худшем случае.

Так что возобновляемая генерация вполне и жестко управляемая. В Европе проблема не в недостатке энергии, а в импульсах ее избытка. Обратите внимание что событие случилось в полдень, а не ночью.

Я так понял ситуацию, что сначала импульсы перенапряжения удалось погасить подав команду отключения некоторых генераций, а потом гашение пошло неконтролируемое из-за anti-islanding. А все из-за флуктуаций прозрачности атмосферы и диэлектричекой проницаемости.

Ну как неуправляемую. Сеть на первом событии восстановилась за миллисекунды!

А как известно один период частоты 50 Гц длится аж 20 миллисекунд.
Т.е. скорость реакции регулятора невероятная.

Однако, как известно, скорость распространения сигнала в проводах зависит от диэлектрической проницаемости атмосферы и может колебаться от 200 до 300 тыс. км в сек.

Вот вам и непредсказуемый лаг в 2 мс на масштабе Испании, который не смогла отработать система.
Мощные генерации такой лаг задавят, а солнечные генераторы сбойнули. Фирмваре однако надо править.

Солнечные инверторы сделаны примитивно и синхронизируются к сети с помощью PLL, которым нужно несколько периодов сетевого напряжения для синхронизации. Там еще от стабильности их PID контуров зависит. Вероятно поймав расхождение в 2 мс они сразу отключаются, чтобы синхронизировать заново и ждут перехода через ноль. А регулятор реагирующий за миллисекунды такого не понял.

События в real time системе в принципе зло. Они мешают точному расчету времени реакции. Они могут зацикливаться. Они могут переполняться. У них могут быть гонки.
Словом отладка систем с событиями очень сложна. Но как раз про это ни слова в статье.

Создатели  IEC 61131-3 были не дураки, и были в курсе о событиях. Однако их не реализовали.

Я так понимаю, что события притянули для необходимости рисования SM выполняющихся распределенно на медленных недетерминированных шинах типа MODBUS по TCP.
Если бы был EtherCAT, TSN, Profinet IRT и т.п. события бы не понадобились.

Т.е. по сути вот такая реализаци IEC 61499 - это декларация технологической отсталости.

Простенькое приложение с событиями где еще нет рисков запутаться может и ChatGPT нагенерить в VS Code. Для этого не нужны специальные IDE.

По статьям разработчиков можно только понять что они рассматривают ИИ в первую очередь как оружие в борьбе за их ценности и их только волнует чтобы у ИИ не появилась мораль. Потому что никто не знает существует ли универсальная мораль.

Information

Rating
2,060-th
Registered
Activity