eddy_em: (Default)
Пока добавлял работу с SI7005, подумал: а ведь датчики AHTxx практически ничем не отличаются (если не заморачиваться, то вообще одним и тем же кодом можно "обслуживать" и AHT1x, и AHT2x), и если у меня их N на шине одинаковых, то будет проблема со статическими переменными в файле → все это нужно вынести в "класс". А как скрыть члены "класса" от пользователя? Объявить typedef на некую структуру, которая будет объявлена "с подробностями" лишь в "private-header". Собственно, даже в glibc такое делают!
Правда, пришлось достаточно "порефакторить". Еще и в "класс" добавить void*, чтобы туда запихивать все нужные калибровки, промежуточные данные и прочее.
Сильно надеюсь, что больше значимых полей (которые нужно будет не нулем проинициализировать) добавлять не придется. Все-таки, с наследованием в С вообще плохо (хотя, можно заморочиться: при "наследовании" от одного "класса" его можно прямо в начало производного подсунуть, а если нескольких - воткнуть union'ы). А вот указателя this вообще нет! Поэтому во все функции "класса" приходится первым аргументом писать ссылку на сам "класс"…
Вот такая дичь получилась.
eddy_em: (Default)
Еще в самом начале нулевых, когда В.С. Шергин писал систему управления БТА, особо библиотек для координат/времени и т.п. не было, поэтому ему пришлось при помощи f2c из фортрановской SLA сделать сишную библиотеку. Оно до сих пор так и работает, но жутко неточно. Вот я сравнил намедни результаты с SOFA/ERFA, и если по видимому месту без атмосферы оно как-то более-менее пойдет, то рефракцию (особенно на больших Z) считает очень криво. В принципе, сравнение SLA/SOFA я делал еще несколько лет назад. И на рисечгейте наткнулся на человека, который то же самое делал в свое время, еще и с NOVA/NOVAS (исходники на гитхабе). И у него тоже вышло, что SOFA/ERFA (это — одна и та же библиотека, просто ERFA идет с опозданием, т.к. копирует SOFA, но зато не имеет ограничений использования) наиболее точные результаты дает. Я уже в ЖЖшке об этом писал в 2019 году. Автор мне ответил в рисечгейте, скинул свою статью. Вывод: SOFA/ERFA дает правильные результаты, остальные врут.

Управление монтировками 10micron я сделал на SOFA→ERFA, собственно, и софт при работе с БТА/Z1000 у меня ERFA для преобразования координат использует (хотя, осталось еще что-то старое со SLA, постепенно переделываю). Однако, хочется ведь еще и в шапку писать расстояние до Луны и Солнца, фазу Луны, а то и даже параметры простенького калькулятора экспозиций…
Начали с коллегой писать управление оставшимися нашими тремя 50-см телескопами (увы, там не крутая 10micron, а убогая sidereal servo, для которой в природе не существует готовой системы управления). Сегодня наткнулись еще на одну библиотеку: SuperNOVAS (основанную на NOVAS, а та, в свою очередь, основана на NOVA, но, в отличие от NOVA, которую 7 лет назад авторы забросили, эти библиотеки развиваются). И здесь даже пишут о "full support for the IAU 2000/2006 standards for sub-microarcsecond position calculations" (интересно: врут или нет?).
Я-то потестирую эту библиотеку как-нибудь, но вот таки интересно было бы у людей, которые занимаются разработкой систем управления телескопами, спросить (где бы их найти?). Вдруг есть что-то более точное, надежное и развивающееся? Не хочется, чтобы оно померло, как SLA в свое время.

// кстати, как ни странно, astropy пользуется именно ERFA. Как они там с Луной, Солнцем и т.п. — непонятно... Но змеюкой я даже под угрозой расстрела пользоваться не буду, тем более, там даже компилятора до сих пор нет.
eddy_em: (Default)
Репозиторий с кодом.
Сначала избавился от нескольких багов. Потом решил добавить сетевой функционал. Ну, а коль сеть — то и кольцевой буфер нужен. В общем, теперь там — не просто макросы и функционал, который в 99% случаев нужен (тот же разбор параметров командной строки), но и дополнительные облегчалки.
Подробней )
Теперь как минимум все, что пользуется этой библиотекой, надо обновить. Ну, а сетевые демоны роботелескопов вообще радикально так переделать: чтобы "шапкой" с метеоданными не демон монтировки занимался (что вообще нелогично), а демон погоды; чтобы демоны купола, монтировки и телескопа "слушались" демона погоды. Скажем, если стоит prohibited=1, то прекращать наблюдения, когда они идут, или не давать наблюдателю открыться. Вот на БТА такую функцию АСУшник выполняет (правда, некоторые из рук вон плохо работают, позволяя наблюдателям-вредителям открывать телескоп при влажности свыше 90%, облачности или даже тумане). А на Ц-1000 почему-то до сих пор нет такого "супердемона", который бы "давал по шапке" наблюдателям-вредителям. Иначе угробят телескоп, а за это даже никакого наказания не понесут (я бы отстранял наблюдателей минимум на полгода от наблюдений, если они открывают телескоп тогда, когда этого делать ни в коем случае нельзя).
eddy_em: (Default)
Чуть ли не с месяц назад сделал конкретный рефакторинг и багфикс моей библиотечки сниппетов. А сегодня вроде бы добил добавление простого сетевого функционала (tcp INET и UNIX сокеты) — сколько ж можно один и тот же код годами копипастить из проекта в проект? Еще и обработчик команд клиента "встроенный" сделал. С реакцией на команду "help" (точно так же, как в микроконтроллерах, выводится перечень команд со справкой). Пока отлаживал, заметил маленький баг в парсере key/value (если в строке был только "ключ", то последний символ обрезался), исправил.
С поллингом разрывался: сначала скопировал код с poll, потом подумал, и начал на select переделывать (думал, что это не потребует двигать туда-сюда громадные вложенные структуры, если клиент закрылся). Однако, не понравилось мне там то, что нужно считать вплоть до максимально имеющегося файлового дескриптора, а как его узнать? Количество клиентов у меня всегда ограничено числом, куда меньшим, чем предельное количество открытых fd. Но зато с select не нужно было бы структуры туда-сюда двигать. Однако, таки вернулся к poll. И если отключился единственный или же последний клиент - только изменяю количество подключенных, иначе же после закрывания текущего, меняю его местами с последним подключенным. В итоге цикл всегда идет по N+1 (N - количество подключенных, 1 - дескриптор слушающего сокета).

Надо завтра еще хорошенько поотлаживать при разных условиях. Уж больно странно, что оно у меня за полчаса "взлетело". Обычно после недели кодописания баги еще пару-тройку дней вылавливаешь.
eddy_em: (Default)
Пока с заглушками, ковыряюсь. Читаю исходник модуля ядра и не понимаю: функция usb_xfer принимает массив структур i2c_msg. У каждой структуры есть поле адреса, соответственно, подразумевается, что каждая такая посылка должна начинаться со START, потом отправка адреса, а заканчиваться выставлением STOP. По крайней мере, именно так я и реализовывал все функции работы с I2C на STM32. А тут — в начале выставляют START, потом пишут/читают все N сообщений, и лишь затем STOP! Неужели оно так будет работать? Что-то сомневаюсь… Посмотрел исходники "robotfuzz" — там та же бодяга, только, похоже, START выставляют на каждое сообщение, а вот STOP — только в самом конце.
Полезу ка, почитаю мануал на МК: вдруг так правда можно?
tl;dr )
В общем, ближе к выходным еще повожусь с железякой. Основная задумка — попытаться на ее VID/PID поднять CDC. Понятно, что эмуляцию PL2303, увы, уже так не сделать, но вот "обычный унылый" /dev/ttyACMx, возможно, получится. Вот тогда все будет замечательно. А если нет, то хорошо бы поискать, существуют ли вообще среди простых STM32 МК, которые не приколачивают гвоздями в регистры USB номер, полученный при энумерации — чтобы можно было на них эмулировать USB hub.

P.S. Кстати, слышал обидную новость: нацик выкинул из ядра поддержку reiserfs. Уныло, однако. Теперь уж точно придется до определенной версии ядро заморозить. А когда уже HDD или SDD с корнем помрут — ставить систему почти с нуля, но уже на другую ФС. Правда, я понятия не имею, какую ФС сейчас для корня использовать. Не ублюдскую же ext4! Да и где гарантии, что с той же ZFS не поступят аналогично, как с reiserfs?
eddy_em: (Default)
Как уже писал, код закончил утром, а только что закончил Readme.md дописывать. Вот и сделал пуш во все свои кодохранилища.
Издевался над парочкой из более свежей партии:

Самый первый почему-то перестал "общаться" по RS-232 (однако, по модбасу и кэну работает - видимо, преобразователь уровней помер).
Получилось очень даже приличное устройство (в отличие от оригинала, который вообще хрен запрограммируешь нормально). Если нужно кастомизировать, а базовых возможностей не хватает, любой может открыть исходники и добавить нужный ему код. Быстро, удобно и не требует изучать всякие левые недоЯПы (а то и вообще мышей надрачивать дичь какую-нибудь).
Более-менее подробно документация изложена по ссылке, поэтому здесь лишь немного прокомментирую.
tl;dr )

В общем, я доволен. И еще больше буду доволен, если таки нарисую полную схему в кикаде.
Единственным недостатком при переделке этих недорогих модулей является то, что для прошивки нужно подпаять проводок к резистору на BOOT0 и при подаче питания подцепить его на +3.3В. Затем при помощи stm32flash отключается защита, стирается флеш, и можно записывать свою прошивку. Под CAN я просто два проводка припаял, но хорошо бы туда впаять такой же разъем, как соседний - где 485 и аналоговые входы/выходы.
Разъем SWD в своей версии я бы сделал, как и в прочих железяках - нераспаянная гребенка с шагом 1.27мм, куда очень удобно вставляются контакты "прищепки".
Ну и, понятное дело, в своей версии сделал бы независимыми оба полюса каждого входа и каждого выхода. Иначе получается уж больно узкий круг задач, которые можно решить этой фиговиной. Ну или если оставлять входы с общим, то хотя бы биполярные опторазвязки воткнуть…
eddy_em: (Default)
Решил было сэкономить объем text-секции в микроконтроллере и используемые по нескольку раз строковые константы объявить именно как константы. Однако, gcc, зараза такая, не хочет при компиляции в массив, использующий эти строки, подставить именно переменные, несмотря на то, что они - константы. Вот простой пример:
#include <stdio.h>

static const char * text1 = "One";
static const char * text2 = "Two";
static const char * text3 = "Three";

static const char * const array[3] = {text1, text2, text3};

int main(){
	for(int i = 0; i < 3; ++i) printf("%d: %s\n", i, array[i]);
	return 0;
}

Выхлоп:
gcc 2.c 
2.c:7:39: ошибка: элемент инициализатора не является константой
    7 | static const char * const array[3] = {text1, text2, text3};
      |                                       ^~~~~
2.c:7:39: замечание: (где-то рядом с инициализацией для «array[0]»)
2.c:7:46: ошибка: элемент инициализатора не является константой
    7 | static const char * const array[3] = {text1, text2, text3};
      |                                              ^~~~~
2.c:7:46: замечание: (где-то рядом с инициализацией для «array[1]»)
2.c:7:53: ошибка: элемент инициализатора не является константой
    7 | static const char * const array[3] = {text1, text2, text3};
      |                                                     ^~~~~
2.c:7:53: замечание: (где-то рядом с инициализацией для «array[2]»)

Однако, вот так прокатывает:
#include <stdio.h>

static const char * text1 = "One";
static const char * text2 = "Two";
static const char * text3 = "Three";

static const char ** const array[3] = {&text1, &text2, &text3};

int main(){
        for(int i = 0; i < 3; ++i) printf("%d: %s\n", i, *array[i]);
        return 0;
}


Ну, значит, придется делать массив указателей на указатели…
eddy_em: (Default)
Код на гитхабе.
Пока не тестировал. Убил на это полтора рабочих дня (включая "чаегоняние" часа на 3-4).
Постарался учесть спецификации из интернетов + что в вики написано.
В режиме господина будет тупо посылать все, что вводишь в терминал аргументами соответствующей команды (как посылка чего угодно в CAN), а при приеме пакета-ответа - расшифровывать его в терминале (без CRC).
В режиме раба будет принимать лишь пакеты, направленные на соответствующий идентификатор (а также широковещательные, но не отвечать на них), с выполнением нужных действий и отправкой ответа (или сообщения об ошибке).
eddy_em: (Default)
Добавил в ccd_capture плагин для "генерирования звезд". Пока он совершенно тупой, и не факт, что я все баги обнаружил, но уже кое-что: можно, не дожидаясь собирания стенда, тестировать алгоритмы автогида в разных условиях. "Звезды" генерируются по функции Моффата, всего их может быть до 32 штук в кадре (задаются координаты в угловых секундах и аппаратные звездные величины такие, что 0m соответствует интегральный поток в 65535/255 ADU в секунду в зависимости от выбора - 16 или 8 бит).
При желании добавляется пуассонов шум (медленно работает, зараза, надо будет, наверное, еще что-то попроще придумать). В принципе, весь алгоритм максимум на openmp, поэтому жутко медлительный — сто кадров 1000×1000 пикселей в секунду никак не получить. Возможно, надо будет как-то оптимизировать.
Еще умеет добавлять аддитивный фон (любое 8-битное монохромное изображение) - можно эмулировать всякие нехорошие условия с фоном (типа бликов, кривой подложки и т.д., и т.п.). Ну и бинарная маска - чтобы эмулировать щечки щели.
Можно задать скорость вращения (типа, не работает деротатор) и смещения (как бы общий дрейф) всего "звездного поля". Плюс флуктуации изображения в рамках заданных. С флуктуациями сиинга и взаимных положений, а уж тем более со спеклами я не связывался. И так все жутко тормозное получилось: хотелось бы, чтобы эмуляция 10мс экспозиции генерировалась не больше этих самых 10мс, а тут все 20 с хорошим шумом и всем фаршем выходит.
Заодно в improclib кое-какие косяки подправил (правда, не все: так, оказалось, что я читаю изображения как 8-битные, независимо от их реальной битности; на будущее надо бы это подправить). Косяки в usefull_macros тоже нашел, но пока не рискнул править: еще по разработке tty_term назрело перейти на termios2, умеющий произвольные скорости tty; ну а сейчас обнаружил некоторые неудобные косяки с парсером аргументов командной строки (просто раньше у меня нигде их не было в таком бешеном количестве, да чтобы еще и часть с короткими вариантами, а часть - только с длинными). В общем, как-нибудь потом…
Со следующей недели уже закончу эти игрища с ccd_capture и перейду на разработку ядра автогида. Уже четвертый вариант будет… Авось, на этот раз им и закончится: аналогично ccd_capture, к ядру будут подключаться внешние плагины, что в теории позволит цеплять его на любой прибор без изменения кода ядра. Как будет на практике - посмотрим. А то меня уже попинывают, мол, когда ж я займусь новой СУ БТА, да еще и СУ тремя новыми телескопами комплекса "Астро-М" (пока там все совсем уныло, СУ надо будет вообще с нуля рисовать).
eddy_em: (Default)
Давно уже надо было добавить всяких полезностей в терминальный клиент и пофиксить кое-какие баги. Основное — режимы ввода и отображения данных. При вводе доступны такие режимы.
  • TEXT — все, что ввели, отправляется; строки завершаются заданным в параметрах командной строки EOL. Непечатаемые символы можно через escape-последовательности вводить.

  • RAW — пробелы не учитываются; текст отправляется как текст; числа в пределах 0..255 распознаются в системах по основанию 2, 8, 10 и 16.

  • HEX — все числа трактуются как шестнадцатеричные; если число длинное, оно разбивается на пары и считается одним байтом; пробелы игнорируются.

  • RTU RAW — тот же RAW, но каждый раз в конце посылки вставляется контрольная сумма.

  • RTU HEX — тот же HEX, но с контрольной суммой.


При выводе доступны режимы TEXT (непечатаемые символы выдаются как "0xXX"), RAW (в 16-й форме с разделением пробелами) и HEX (в формате hexdump -C).
Учитывая то, что в скором времени придут китайские частотники, с которыми надо будет экспериментировать (понимаю ли они широковещательный адрес, или придется каждый оснащать переходником CAN-modbus), очень даже вовремя я это все доделал.
Read more... )
eddy_em: (Default)
В прошлый четверг мы поставили новую метеостанцию. Целый день с Амирычем возились, а я вспоминал, как электросваркой пользоваться (уродливо, конечно, надо как-нибудь потренироваться на ненужных железяках).
Таки дописал код демона, буду следить: надо проверить, как вычисляется среднее направление ветра, когда будет более-менее северный.
Read more... )
eddy_em: (Default)
Как уже и писал, очень удобно различать устройства по неиспользуемым текстовым полям. Так, что, теперь USB-CAN появляется нонче как /dev/can-usbX. Ну и, заодно, более свежую версию USB-CDC воткнул (из вчерашнего), еще и подправил кое-какие свежезамеченные баги.
По-хорошему, конечно, стоит разделить более правильно: один файл для железоспецифичных вещей, второй — общий для всего USB, ну и отдельно обособленные под конкретную задачу. Но, боюсь, нескоро это будет. Сегодня на работе весь день убил опять под долбаный ccd_capture, чтобы от багов избавитсья (правда, все равно в некоторых случаях при завершении работы клиента выскакивает сегфолт — работать еще, и работать!). Все более склоняюсь к тому, что надо на С++ переходить в разработке десктопных приложений. И все меньше — что нужно делать GUI. А вообще, хотелось бы радикально отказаться уже от десктопных приложений: все равно с ними у меня ничего хорошего не получается.
eddy_em: (Default)
В возне с прототипом спектрографа ESPriF, наткнулся на то, что все мои три железяки (контроллер восьми шаговиков, контроллер объектива Canon и контроллер узла калибровки) абсолютно никак в системе не различаются: те же самые VID/PID/Manufacturer (собственно, эмулирую PL2303). Подсказали мне, что можно завести текстовое поле Interface, которое поможет в дальнейшей идентификации. И вот на "заполнялке азотом" я решил поиграться. Заодно лишний раз оптимизировал USB, выкинув ненужные флаги. Все индексы текстовых дескрипторов задаются в дескрипторе устройства и конфигурационном дескрипторе. Скажем: iManufacturer, iProduct, iSerialNumber и тот самый iInterface. Чтобы не запутаться, проще завести enum, его поля и использовать как индексы. Если мы не хотим отдавать дескрипторы, задаем вместо индекса нуль. Ну, а дальше компьютер запрашивает нужный индекс и получает текстовую строку, которую и можно использовать в правиле udev, чтобы вместо кучи /dev/ttyUSBx создать более понятные (например, /dev/nitrogen_flooding0 или /dev/canusb0).
Вот с правилами UDEV пришлось повозиться подольше: благо, есть udevadm test, так что не пришлось постоянно шнурок туда-сюда втыкать/вытыкать. Сложность вызвало то, что поле Interface лежит в одном "устройстве", а поля VID/PID — в "родительских". Как обычно, SO помог в решении этой проблемы (что бы мы без Stack Overflow делали вообще? Я, например, по латеху там кучу проблем решил, ну и сам немного людям помог; да и по C, линуксу, башу…).
Одним словом, чтобы различить устройства с одинаковым VID/PID, нам нужно это правило:
ACTION=="add", DRIVERS=="usb", ENV{USB_IDS}="%s{idVendor}:%s{idProduct}"
ACTION=="add", ENV{USB_IDS}=="067b:2303", ATTRS{interface}=="?*", SYMLINK+="$attr{interface}%n"

Т.е. когда udev будет пробегаться по всем "родительским устройствам", на стадии добавления в систему USB он заведет переменную USB_IDS, а когда пройдется по "дочернему" устройству, проверит, соответствует ли эта переменная нужному VID:PID. Если соответствует — проверит, есть ли поле iInterface (нам не нужно "настоящие" PL2303 там именовать, да и у них все равно нет этого поля), и если оно есть — создаст нужную ссылочку.
В простейшем же случае (в данном) наше устройство отличается от всех остальных полем "DRIVERS" (которое как раз является свойством "подустройства" с полем interface), поэтому можно упростить правило:
DRIVERS=="pl2303", ACTION=="add", ATTRS{interface}=="?*", SYMLINK+="$attr{interface}%n"

Все, как только добавили устройство с нужным полем DRIVERS и существующим атрибутом interface, создастся нужная символическая ссылка.
Теперь достаточно для каждого USB-устройства только лишь менять название этого поля. И в системе теперь не придется перебирать из кучи /dev/ttyUSBx, чтобы найти свое устройство — на него будет удобный симлинк. Да и все демоны будут элементарно стартовать (не нужно будет перебирать устройства и запрашивать "ТЫ ХТО, Э?").

CCD_Capture

Apr. 7th, 2023 02:29 pm
eddy_em: (Default)
Исправил кое-какие баги в CCD_Capture, но таки часть еще осталась: иногда подвисает передача по сети (особенно когда окно двигаешь — видимо, потоки между собой начинают "драться"); в standalone режиме сегфолтится при отключении камеры (т.е. где-то я что-то прошляпил); возможно, еще какие-то невыявленные пока баги есть (а пока баг не выявлен, обозвать его "фичей" не выйдет).
Почему-то получилось, что использование openmp только тормозило: при openmp выполнение эквализации изоображения в 1Мпиксель занимало 20мс, а без нее — 1мс. Ну, понятно, там требуется синхронизация потоков. Однако, элементарные операции преобразования в псевдоцвета тоже ускорились (!!!), когда я выкинул openmp (а там-то вообще независимо каждый пиксель обрабатывается — ничего синхронизировать не нужно). Еще косяк — с отображением (почему-то без эквализации гистограммы вообще сплошной синий фон, надо будет изменить "линеаризацию": вычислять на масштабе 0..максимальная яркость кадра, а не 0..65536 — в 8-битном режиме вообще черт знает что выходит).
Провел тесты по скорости. Экспозиция — 1мс, сначала проверил на "dummy" — эмуляторе светоприемника: кадр 1050×1050: 34..62 в режиме standalone, 35..42 — по сети; кадр 100×100: 83..103 — standalone, 36..48 — network.
И на Basler: кадр 1928×1208: 18..19 — standalone, 18..19 — network; 100×100: 30..35 — standalone, 28..31 — network.
Ну, по крайней мере, не 2 кадра в секунду, как было у меня с использованием "куска автогида" от предыдущего спектрографа. Будем запускать напрямую ccd_capture и смотреть хоть локально, хоть по сети (с туннелированием портов посредством ssh). Жаль, что биннинг вообще никак не отражается на скорости считывания (хотя, казалось бы: если биннинг выполняется средствами DSP самой камеры, то даже 2×2 уже должен в 4 раза скорость считывания повысить). Ну, все равно нужно будет включать биннинг 4×4, т.к. уж слишком огромная звезда получается.
Пока забью на некоторые баги и вернусь к improclib — таки надо быстрей сделать автогид для ESPriF.
eddy_em: (Default)
В очередной раз надо "старый новый" автогид делать (практически то же самое, что и на инасановский оптоволоконный спектрограф, но с другим исполнительным механизмом). Решил, что хватит уже одни и те же куски кода туда-сюда таскать, рискуя выдернуть более старую версию с багами. Завел репу improclib и понемногу оформляю код в виде библиотеки. Кстати, с удивлением обнаружил, что у меня уже есть рабочая библиотека для работы с FITS-файлами ☺ Но таки подумал, что не стоит мешать эту библиотеку и ту (лучше в случае необходимости буду с тремя сразу линковать - ведь usefull_macros у меня уже стала обязательной библиотекой).
Read more... )
eddy_em: (Default)
Добавил в коллекцию сниппетов. От других серий отличие в том, что во flash пишется не словами по 16 бит, а кусками по 64! Причем, последовательно по 32 бита за один присест. И МК не устанавливает флаг EOP, поэтому нельзя без итератора проверять его (у меня в тестовой версии и вообще без этого работало, но там был отладочный выхлоп, так что я добавил паузу в 9999 бессмысленных тактов). Интересно, как эти рукожопы в калокубе реализовали данную процедуру, но мне в исходники этого адового быдлокода лезть вообще никакого желания нет. Просто поражаюсь: каким нужно быть идиотом, чтобы калокуб использовать (особенно в серьезных разработках)! Там не только оверхед адов, но еще и быдлокод такой степени, что непонятно: какая адова смесь индусов и китайцев эту дичь писала!
eddy_em: (Default)
Понемногу вожусь с "дофигамоторным" контроллером. Решил сразу протокол делать не с кучей самописных аналогов strcmp, а на основе switch с хешем команды. Для этого взял свой "хешегенератор" и немного переделал: добавил в коды возврата отрицательные ("функция не найдена" и "неверный формат команды"). Функция parsecmd теперь не портит входную строку, что позволяет давать команды с номерами, не отделяя их от команды пробелом (например, goto0=-400, stop5 и т.п.). Старая возможность — номер через пробел — тоже осталась. А в файл test.c я поместил пример работы, когда для нескольких обработчиков используется одна функция (в этом-то случае и нужно в нее hash передавать — чтобы она знала, кто именно ее вызвал). Скажем, есть команды-геттеры вообще без параметров (типа vdd, time или temp) — обрабатываем их одной функцией. Для тех, что с параметрами и номером, сначала вызываем функцию разделения "хвоста" на номер и параметр, а потом, если все ОК, вызываем дальше уже нужную функцию, куда передаем лишь эти найденные номера и строку (которую сразу в число в этой же функции нужно превратить, если у всей группы в качестве параметра int используется). Скажем, move_motor(uint8_t nmotor, int32_t nsteps)
eddy_em: (Default)
Хоть true inline — и хорошо, но больно уж неудобно пользоваться и есть шанс, что сгенерировав код, затрешь свои изменения. Поэтому я решил функции делать "слабыми синонимами": __attribute__ ((weak, alias ("__f1"))) на функцию __f1, которая просто возвращает 1. Функцию parsecmd упростил (теперь она не выкидывает пробелы, чтобы разработчик мог сложные команды типа "set ip" или "set param" отправить, вычленять команду из строки ввода — задача разработчика).
Заодно добавил проверку на совпадение имен функций для разных команд (скажем, "sim-key", "sim_key", "sim key" и "sim'key" дадут одну и ту же функцию fn_sim_key). В таком случае утилита выдаст матюк:
Have two similar function names for 'sim key' and 'sim-key': 'fn_sim_key'
Have two similar function names for 'sim-key' and 'sim'key': 'fn_sim_key'
Have two similar function names for 'sim'key' and 'sim_key': 'fn_sim_key'
Can't generate code when names of some functions matches

И благополучно отвалится.
tl;dr )
eddy_em: (Default)
Закинул код на гитхаб. Помимо старого hashtest добавил еще hashgen, который может генерировать по заданной таблице команд заголовочный файл и исходник, принимающий пользовательскую строку на вход, вычисляющий хеш команды (первое слово) и запускающий соответствующую функцию. Можно проверить это при помощи test.c.
Read more... )
eddy_em: (Default)
И опять я со своим текстовым протоколом для МК, где крутить в цикле strcmp совсем неинтересно (особенно если команд под сотню). И со stackoverflow попал я на страничку, где приведено три варианта хеш-функций. Я набросал простенький код для проверки
Код )
Для проверки выдрал 43001 английское слово из файла русско-английского словаря (который у меня в веб-морде словаря используется: перевод между русским, английским и карачаевским).
Естественно, "простейший" алгоритм K&R дал огромное количество совпадений хешей. А вот оба оставшихся алгоритма ни одного совпадения не дали! По времени получилось совершенно одинаково: всего лишь 6мс на все про все, хоть в sdbm больше вычислений. У djb2 есть еще вариант с умножением (понятно, что на МК лучше это не тащить, ведь сдвиги гораздо быстрей). На ПК скорость была все те же 6мс. Я попробовал разные простые числа, и вот можно не 33 туда воткнуть, а 19 — уже с ним ни одного совпадения.
Наткнулся на интересную штуку: я и не подозревал, что strncpy и snprintf так разительно отличаются по скорости: если вместо strncpy я использую второй, то время увеличивается аж до 21 секунды!
Теперь надо еще сделать кодогенератор, который по заданному словарю будет мне генерировать заголовочный файл с хэшами (типа #define CMD_LIST (число), а число будет вычислять как hash("list");) и кусок сишного кода со switch'ем (и в пункте, соответствующем CMD_LIST, будет запускаться функция handler_list(str)).

October 2025

S M T W T F S
   1234
567 89 1011
121314 15161718
19202122232425
2627 28293031 

Syndicate

RSS Atom

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Dec. 10th, 2025 01:20 am
Powered by Dreamwidth Studios