eddy_em: (Default)
Репозиторий с кодом.
Сначала избавился от нескольких багов. Потом решил добавить сетевой функционал. Ну, а коль сеть — то и кольцевой буфер нужен. В общем, теперь там — не просто макросы и функционал, который в 99% случаев нужен (тот же разбор параметров командной строки), но и дополнительные облегчалки.
Подробней )
Теперь как минимум все, что пользуется этой библиотекой, надо обновить. Ну, а сетевые демоны роботелескопов вообще радикально так переделать: чтобы "шапкой" с метеоданными не демон монтировки занимался (что вообще нелогично), а демон погоды; чтобы демоны купола, монтировки и телескопа "слушались" демона погоды. Скажем, если стоит prohibited=1, то прекращать наблюдения, когда они идут, или не давать наблюдателю открыться. Вот на БТА такую функцию АСУшник выполняет (правда, некоторые из рук вон плохо работают, позволяя наблюдателям-вредителям открывать телескоп при влажности свыше 90%, облачности или даже тумане). А на Ц-1000 почему-то до сих пор нет такого "супердемона", который бы "давал по шапке" наблюдателям-вредителям. Иначе угробят телескоп, а за это даже никакого наказания не понесут (я бы отстранял наблюдателей минимум на полгода от наблюдений, если они открывают телескоп тогда, когда этого делать ни в коем случае нельзя).
eddy_em: (Default)
Собрал в одну кучу для разных линеек, чтобы можно было, не парясь особо (разве что для F2/F3 чуть руками надо будет подправить, т.к. там внутри одной линейки черт-те что творится), быстренько CDC поднимать — сниппет. А началось с того, что неделю назад, ковыряясь с multistepper, наткнулся на косяк с выводом справки (а там она жутко длинная). Оказалось — проблема гонки: пока из суперлупа в буфер пишут, внезапно может возникнуть прерывание и попытаться этот буфер прочитать. Ввел блокировки — получилось. Правда, как я уже писал, пришлось таки использовать поллинг.
Скорость — почти 6Мбит/с. Выше — только если использовать двойную буферизацию. Но сел я эти три странички даташита читать, и понял, что нафиг оно мне не нужно. Разве что если вдруг когда-нибудь упрусь в то, что 6Мбод не хватает… А то ведь получается, что памяти надо в 2 раза больше выделять!
Кстати, насчет памяти: чуть застрял на своем сниппете, когда пытался на F103 запустить. Там дескрипторы отдавались, а вот только начнешь туда что-то писать, ошибка. Отладчик показал, что точки EP2/EP3 не инициализировались. И тут-то до меня дошло: ведь раньше я явно размер в байтах проверял, а сейчас этот размер указан для буфера, а потом он делится на 1 или 2 (в зависимости от того, выравнивание на 16 или на 32 бита используется). И несчастные 512 байт у F103 еще и надвое поделились, так что места элементарно не хватило. Очень уж кривой USB у STM32. Да и буфер какой-то дико мелкий: в том же Seven_CDCs (7 CDC устройств в одном микроконтроллере) используются все 8 конечных точек. И по-хорошему, даже с эмуляцией interrupt-EP на 7 CDC нужно минимум 640 байт. При том, что зачастую 256 байт буфера обобщены с CAN. И зачастую выравнивание идет на 32 бита, т.е. даже буфер 1кБ без использования CAN превращается в несчастные 512 байт. Ну и какая ж тут двойная буферизация еще?..
eddy_em: (Default)
В очередной раз надо "старый новый" автогид делать (практически то же самое, что и на инасановский оптоволоконный спектрограф, но с другим исполнительным механизмом). Решил, что хватит уже одни и те же куски кода туда-сюда таскать, рискуя выдернуть более старую версию с багами. Завел репу improclib и понемногу оформляю код в виде библиотеки. Кстати, с удивлением обнаружил, что у меня уже есть рабочая библиотека для работы с FITS-файлами ☺ Но таки подумал, что не стоит мешать эту библиотеку и ту (лучше в случае необходимости буду с тремя сразу линковать - ведь usefull_macros у меня уже стала обязательной библиотекой).
Read more... )
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)).
eddy_em: (Default)
Нарисовал очередной сниппет для работы с сокетами. Надо писать сервер для утилиты обслуживания ПЗС/КМОП матриц, а приличного сниппета у меня что-то под рукой не оказалось. Вот и решил написать.
Умеет локальные INET сокеты и UNIX-сокеты (в т.ч. безымянные — у которых первым символом идет нуль). Содержит простейший метод парсинга сообщений вида ключ[=значение], по одному сообщению на строку (разделение как обычно: '\n').
На сей раз с поддержкой неполных строк: если последняя строка сообщения не заканчивается '\n', она не выбрасывается, а к ней в следующий раз "дочитывается" новая порция данных.
Простой обработчик полей "ключ" принимает NULL-terminated массив структур
typedef struct{
    mesghandler handler;
    const char *key;
} handleritem;

Если поле "key" совпадает с ключом, вызывается handler. В него передаются fd, key и val:
typedef hresult (*mesghandler)(int fd, const char *key, const char *val);

fd — дескриптор сокета — нужен для возможности написать индивидуальное сообщение клиенту; key — на тот случай, если один обработчик будет несколько разных ключей обслуживать (скажем, сеттер целых чисел); val — значение, которое может быть и NULL, если ключ - простая команда.
Поллинг клиентов выполняю через poll(), так что нет нужды париться с синхронизацией потоков (как в случае, когда каждому клиенту один поток), да и меньше шансов, что ресурсов не хватит, если клиентов слишком много. Правда, все равно выделяется по буферу на клиента — чтобы сохранять останки предыдущих сообщений.
В моем случае максимальное количество клиентов — 30, так что буферы выделены статически. Но если их будет мегадофига, надежней будет аллокатором на каждого нового клиента буфер выделять, а после отключения — освобождать память. Правда, файловых дескрипторов может не хватить, но желающие иметь больше 4096 дескрипторов знают, что нужно делать.
Провел несколько проверок (в т.ч. заваливал мусором) — вроде не падает. Буду на следующей неделе добавлять в CCD_Capture.
eddy_em: (Default)
Сел сейчас переделать утилитку, вычисляющую моменты восхода/захода Солнца (ну и заодно полудня). Она нужна для того, чтобы не писать вручную, во сколько времени автоматом закрыть телескоп при наблюдениях. Ну и решил, чтобы не плодить сущности, просто сделать симлинки 'sunrise' и 'sunset' на основную утилиту 'noon'.
Для этого основными целями делаем создание ссылок, а уже их ставим в зависимость от основной цели. Вот такой Makefile получился:
# run `make DEF=...` to add extra defines
PROGRAM = noon
LDFLAGS := -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,--discard-all
LDFLAGS += -lnova
SRCS := $(wildcard *.c)
DEFINES := $(DEF) -D_GNU_SOURCE -D_XOPEN_SOURCE=1111
CFLAGS += -O2 -Wno-trampolines -std=gnu99
CC = gcc

LINKS := sunrise sunset

all : $(LINKS)

$(LINKS) : $(PROGRAM)
        @echo "make links"
        ln -s $< $@ || true

$(PROGRAM): sun.c
        @echo -e "\t\tCC $<"
        $(CC) $(LDFLAGS) $(CFLAGS) $(DEFINES) -o $@ $<

А внутри просто проверяем, что собой представляет basename(argv[0]), выбирая соответствующие действия.
eddy_em: (Default)
Работает, но где-то я накосячил: во-первых, иногда при активном обмене МК зависает (т.е. явно где-то что-то недоработал). Во-вторых, предельная скорость всего-то в районе 3Мбод! Либо это — из-за ограничения кернельного модуля PL2303, либо, опять же, я что-то накосячил.
Нужно попробовать с чистым CDC.
eddy_em: (Default)
Промучился вчера часов пять с непонятной проблемой: вроде бы периферия USB у F303 такая же убогая, как у F103, т.е. можно 1-в-1 перенести. А не работала, зараза! Уже дошел до скрупулезной проверки тактирования, пока не увидел косяк в своем коде: в отличие от F0x2, здесь нужно инициализировать ноги. И вот, что я нарисовал:
    GPIOA->MODER = (GPIOA->MODER & (~GPIO_MODER_MODER15_Msk | GPIO_MODER_MODER11_Msk | GPIO_MODER_MODER12_Msk)) |
            GPIO_MODER_MODER11_AF | GPIO_MODER_MODER12_AF | GPIO_MODER_MODER15_O;
    // USB - alternate function 14 @ pins PA11/PA12
    GPIOA->AFR[1] = (GPIOA->AFR[1] & ~(GPIO_AFRH_AFRH4_Msk | GPIO_AFRH_AFRH5_Msk)) |
            (14 << (4 * 4)) | (14 << (5 * 4));

Т.е., чтобы вычислить смещение в битах второго байта, я вместо 8 вычел из 11 и 12 семерку! А правильно — так:
    GPIOA->AFR[1] = (GPIOA->AFR[1] & ~(GPIO_AFRH_AFRH3_Msk | GPIO_AFRH_AFRH4_Msk)) |
            (14 << (3 * 4)) | (14 << (4 * 4));

Т.е. инициализировал я только USB_DP, а нога DM оставалась неинициализированной — вот оно дальше USB reset и не шло! Как только поменял — все заработало.
Но мне не нравится эта реализация: довольно-таки тупая, буду делать большой кольцевой буфер с автоотправкой очередных 64 байт после каждого прерывания EP3IN.
eddy_em: (Default)
Нарисовал еще одну реализацию.
И прием, и передача идет через DMA. Используется двойная буферизация как на передачу, так и на прием (чтобы не копировать приемный буфер куда-то еще). Концом приема строки считается получение символа '\n' (используется прерывание character match), либо же переполнение буфера (тогда выставляется флаг overflow и буфер заполняется заново).
eddy_em: (Default)
Как и обещал, написал-таки функцию вывода флоатов в строку. Вот, что получилось:
Read more... )
На мой взгляд, сгодится.
eddy_em: (Default)
Пока телескоп елозит по небу, я помаленьку начал оформлять кучу своих сниппетов в одну библиотеку. Для начала — самое востребованное: разбор аргументов командной строки, проверка на уникальность запущенного процесса и мелочевка из usefull_macros.h.
Небольшой рефакторинг, чтобы объединить все это в библиотеку (а также немного причесать), занял не так уж и много времени. Другое дело — написание примеров, чтобы как можно больше упростить использование библиотеки.
eddy_em: (Default)
Помаленьку я начал осуществлять свою давнюю мечту: оформить все сниппеты в одну библиотеку, а обработку фитсов — в другую. Чтобы не тягать каждый раз уйму файлов из проекта в проект (что сильно затрудняет контроль исправления багов и добавления фич). А так — будет две библиотеки, исправление багов будет вообще без вмешательства в использующие их утилиты пройдет, добавление фич тоже облегчится.
Для начала сделал элементарную заготовку: библиотека с одной-единственной функцией helloworld(), которая может благодаря геттексту "говорить" на двух языках. И сразу же поддиректория examples с примерами. Понятно, что в данном случае пример только один. А так их можно будет толпу наделать...

P.S. Qt-creator мне все больше и больше нравится: он сканирует CMakeLists.txt и на основе его определений макросов меняет подсветку синтаксиса (затеняет скобки с отсутствующими макросами). Еще и ошибки высвечивает! Глядишь, эдак и gdb с валгриндом начну использовать!..

P.P.S. Поржал насчет "лучше день потерять": общий объем файлов для генерирования одной строчки текста... Зато дальше все будет очень просто. Заодно сделал еще один шаблон CMakeLists.txt - более удачный, чем предыдущие два (но все равно еще кое-какие косяки остались).
eddy_em: (Default)
Теперь - сетевой демон для управления всякими устройствами через последовательный порт (но можно и выкинуть код, касающийся железа для других видов обработки сетевых запросов).
eddy_em: (Default)
Для этой операции, необходимой довольно-таки часто (особенно для микроконтроллеров: скажем, мелкую картинку во флеш записать или кусочек звукового файла), обычно пишутся велосипеды вроде такого:
hexdump -e '20/1 "0x%02x, " "\n"' testbin
0x0d, 0x19, 0x32, 0x44, 0xc9, 0xc9, 0xc9, 0x92, 0x24, 0x3b, 0x3b, 0x3b, 0x45, 0x46, 0x46, 0x6a, 0xc4, 0x88, 0x11, 0x84,
....

потом это ручками правится и все здорово.
Однако, наткнулся на SO на замечательный совет: использовать vim (точнее, утилиту, идущую с ним):дальше )
eddy_em: (Default)
Второй вечер вожусь с эмуляцией EEPROM во флеш-памяти STM32F0. Раньше как-то не парился, и стирал страницу каждый раз, как менял настройки. Теперь решил поаккуратней сделать. Завел новую директорию Snippets в репозитории на гитхабе.
Работает очень просто: начиная с заданного адреса (я выделяю последнюю, с номером 15) выделяется одна килобайтная страница. По команде сохранения ищется первая пустая ячейка и в нее записываются данные; если все пустые ячейки кончились, страница стирается и процесс начинается с нулевого индекса. Для чтения настроек процесс проходит аналогично: ищем первую пустую запись, возвращаем индекс предыдущей; если индекс неотрицательный (-1 означает девственно чистую флеш, -2 — повреждение данных), memcpy записывает в текущий конфиг данные из флеша, если же индекс отрицательный, оставляется дефолтное значение конфига.

Потихоньку клепаю прошивку ММФП. Пока что отлаживаю на девборде китайской, как будет более-менее похоже на рабочий код, прошью чипы в платах системы управления.
eddy_em: (Костерок)
Бета-версия мультипортового сниффера готова! Пока он умеет немногое, но основное свое предназначение выполняет.
Подробней )
eddy_em: (Костерок)
В поисках парсера ini-файлов наткнулся на эту библиотечку. Форкнул себе (в т.ч. и на гитлаб с битбакетом). Но мне не понравилась структура хранения данных и то, что каждый раз при необходимости увеличить размер хранилища его удваивают.
Сделал хранение раздельным: для каждой секции ключи хранятся в своем массиве данных.
Добавил сортировку по хэшам (для бинарного поиска в больших ini) и сортировку по именам (для красивого сохранения в файл).
Вроде бы работает.

Кому интересно — попробуйте потестировать.
eddy_em: (Костерок)
Решил я добавить в свой вебсокет-сниппет еще и авторизацию, чтобы уж точно им можно было в реальной жизни пользоваться.
Происходит все достаточно просто. Сервер хранит MD5 пароля (в примере — просто как строковую константу). При соединении генерируется "соль" и вычисляется MD5 от строки "соль + MD5 пароля". Эта "соль" отсылается клиенту. Клиент запрашивает у пользователя пароль, вычисляет MD5 от него, присовокупляет к "соли" и отправляет серверу MD5 результата. Если все ОК, сервер посылает сообщение "authOK", если же пароль неправильный, отсылается "badpass" → клиент опять запрашивает пароль у пользователя.
MD5 введенного пароля сохраняется в localStorage (или куках, если localStorage отсутствует), чтобы не вводить пароль каждый раз. В принципе, можно добавить кнопочку "forget me", но смысла в этом не вижу. Теперь у моих веб-морд будет хоть какая-то условная безопасность.

August 2025

S M T W T F S
     12
345 6789
10111213141516
17181920212223
24252627282930
31      

Syndicate

RSS Atom

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Aug. 6th, 2025 05:45 pm
Powered by Dreamwidth Studios