Фух! Таки управился!
Протестировал все варианты компиляции: и с SGREAD, и без него, и с ASYNCWRITE. Не знаю, чем эти методы отличаются, но скорость считывания во всех трех случаях была примерно одинаковой — около 3.5с на весь кадр 4k×4k. По сравнению с apogee, конечно, это очень шустро. Но вот использовать для USB'шного устройства модуль ядра в 21 веке — дикость какая-то!!!

Обновил архив с модулем на гитхабе в репе "mytakepic" (вот такое дурацкое название осталось у читалки). Теперь надо будет переделать этот mytakepic, чтобы он работал с фокусером и турелью от тех же FLI (надо будет для отладочно-юстировочных работ, пока не запустим RTS2).
Модуль проверен на ядрах 4.9.4 и 4.12.5.
Окончательно сверившись со схемами и тем, что вчера прозвонил коллега, я закончил (вроде бы) альфа-версию прошивки системы управления платформой SCORPIO.
На ардуине протестировал — работает. Теперь надо проверять на самой платформе...
Сел я сегодня разбираться, почему после перестановки магнита из позиции 'A' колеса фильтров в позицию 'B' турель не опознала его. Оказалось банально — пока я его запихивал, не заметил, как он перевернулся. В итоге датчик Холла не срабатывал. Все заработало, но как я попытался своей утилиткой HSFW_management переименовать позиции фильтров в EEPROM турели, наткнулся на пару багов. И пришлось открывать старый код и исправлять. Напомню, это управлялка турелью High Speed Filter Wheel от Edmunds Optics. Я даже видео на тытрубу выкладывал.
Как же сложно ориентироваться даже в своем коде после того, как его больше полугода не видел! И более свежим взором смотришь, и видишь иной раз прямо-таки откровенный быдлокод! Кстати, из-за этого я, когда нужно будет сделать очередной автогид к очередному прибору, буду делать по максимуму с нуля; я уже и придумал, как более качественно смещения вычислять — по аналогии с алгоритмом astrometry.net (только будет все намного проще, т.к. постоянный масштаб и смещения незначительные). Это позволит избавиться от проблем на переполненных полях.
Ковыряясь в коде управлялки турелью, нашел кучу совершенно алогичных и противоречивых конструкций в разборе параметров командной строки. Исправил. Вроде работает нормально — по крайней мере, я проверил все возможные комбинации выбора нужной позиции, все было ОК. И переименование работает — но почему-то турель сыплет ошибками при попытке переименования колес G и H, хотя их фильтры переименовываются. Ну да черт с ними — мы будем работать только с A…E — это колеса на 5 50-мм фильтров (а оставшиеся три — на 8 более мелких).
Все, можно вечером с чистой совестью пить пиво.
Ребятки, работая с сокетами, учитывайте, что это вам не файлы!
Мне пришлось забульбенить логгер, чтобы понять эту простую истину: если клиент закрыл со своей стороны сокет, то read() вернет 0, как если бы данных не было, а select() спокойно отработает. Вывод таков. Нельзя писать
if(!(rd = read(sock, buff, BUFLEN-1))) continue;

после вызова select(), надеясь, что ошибка произойдет в select() и соответствующим образом будет выявлена. Ни в коем разе! select() скажет, что данные на входе есть. А вот read() в этом случае вернет не отрицательное значение, а 0!
В общем, писать надо так:
if(!(rd = read(sock, buff, BUFLEN-1))){
    putlog("socket closed. Exit");
    break;
}
и все никак не добью чертовых демонов мониторинга неба! Перезапуск по крону 1 раз в сутки — не вариант, т.к. почему-то клиент, слушающий сокет, не отмирает, а продолжает висеть на закрытом сокете.
А у демона другая проблема, вот этот кусок кода:
        if(pthread_create(&handler_thread, NULL, handle_socket, (void*) &newsock))
            WARN("pthread_create()");
        else{
            DBG("Thread created, detouch");
            pthread_detach(handler_thread); // don't care about thread state
        }

запускает поток для очередного клиента. Но по непонятной причине после того, как клиент отвалится, поток продолжает висеть в качестве зомби!
Думаю, надо временно логгирование действий забульбенить с таймаутами, чтобы выяснить наконец-то, где же кроется косяк. Вот такой из меня рукожопый горе-погромист.

INDI C API

Mar. 23rd, 2017 05:32 pm
Товарищи астрономы (и не только), вопрос: где бы найти примеры клиентов на сишных API библиотеки INDI?
Дело в том, что у этой библиотеки уже довольно-таки широкая поддержка всякого железа, и есть реальная возможность перейти, наконец, от велосипедов под каждый тип ПЗС и т.п. к единой оболочке. Но что-то с С++ связываться вообще не хочется. Хочу продолжать писать на кошерной сишечке.
В корне исходников библиотеки есть заголовочные файлы с сишными API, да и сам indiserver на С написан. Что их побудило С++ пихать в библиотеку — непонятно.
Для начала раздобыть бы примеров клиента CCD под INDI. Хочу прослойку сделать для ATIK'овской камеры цейссовского гида (да, на цейссовском гиде через какое-то время появится нормальная камера): на телескопе будет висеть одноплатник с запущенным на нем indiserver'ом, а клиент — управляющий компьютер или еще один посредник — будет собирать и обрабатывать картинки.
"Скрестить ужа с ежом" оказалось непросто, учитывая все косяки cfitsio. Но, все-таки, получилось. Я решил этого демона не выносить в отдельную репу, а засунул в директорию внутри репы с болтвудом.
Очень много времени убил, не понимая, какого черта inotify, как только обновится файл, перестает отслеживать. А все оказалось просто: cfitsio вместо того, чтобы сделать truncate имеющегося файла (когда имени файла предваряет "!") делает unlink. Понятно, что тут inotify уже не поможет. Сделал обновление дескрипторов каждый раз, как обновится файл.
Другим косяком cfitsio было то, что целые "записи" она пишет в зипованый фитс (using fits_write_record), а вот fits_write_key не хочет — говорит, что в зипованные файлы не может.
Я все больше и больше склоняюсь к тому, что нужно свою библиотеку писать для работы с фитсами! Как лет 5 (если не больше) назад начал в ней проблемы находить, так все не покидает мысля... А еще добавить туда мой fits_filter… В общем, мечты-мечты! Если клонироваться в 10 раз (и послать половину клонов работать там, где деньги платят), то, возможно, это все и будет реализовано.
А, совсем забыл! )
Потихоньку, поковырявшись в скудной документации и коде на крестах, написал простой терминальный монитор. Уже закинул код на гитхаб (а также, как обычно, битбакет, сосфорж и гитлаб).
Поток данных от датчика потрясает избыточностью.
Я убил пару часов, чтобы понять, как запоминать пороговые настройки, а потом обратил внимание на то, что они вообще не нужны: все данные есть в стандартном отчете, а уж посчитать, превышает ли некое значение порог, я могу и сам.
Фактически, можно было бы даже CRC не проверять и не слать ACK (для поллинга достаточно периодически засылать "\x01\n", даже не подтверждая целостности данных).
Данные идут довольно-таки редко — оно и понятно: бешеные вычисления были возложены не на компьютер, а на микроконтроллер. С другой стороны, если бы не так, пришлось бы все калибровки выдумывать самому, и процесс затянулся бы на годы!
Датчик ветра греется где-то до 60°C, а из-за того, что он довольно-таки массивный, инерционность у него очень высокая: чуть ли не в полминуты! Кратковременные порывы ветра он будет сильно занижать, и по сути выдавать усредненную за некоторый интервал времени скорость ветра.
Датчик освещенности (для определения день/ночь) смотрит вниз, т.е. при помещении этой штуки на битумную крышу он будет прилично врать. Там же, внизу, находится датчик измерения температуры окружающей среды. Понятно, что ночью измерения будут проводиться, но все равно какое-то время, пока крыша остынет, показания будут очень сильно врать!

Ковыряясь в коде и документации я потихоньку разобрался с принципом работы всех узлов (разве что есть сомнения по поводу датчика дождя, но, скорее всего, он работает по емкостному принципу). Теперь остается дописать серверную часть, чтобы регулярно получаемые данные отсылать клиенту, а потом и самую неудобную — клиентскую — часть, которая должна будет как-то обрабатывать эти данные (скажем, усреднять за минуту и считать статистику) и сохранять в БД (наверное, даже 1 раза в 15 минут хватит, не знаю пока). Возможно, логгер надо будет общий сделать: чтобы и фитсы с all-sky сохранять (и им в шапку писать данные по температурам и влажности). В любом случае, пройдут еще годы, прежде чем появится какая-то практическая польза от этих железяк (например, в процентах считать облачность по данным болтвудовского датчика; но сдается мне, что проще будет в all-sky звезды считать…).
Благодаря помощи [profile] alextutubalin, код утилиты для работы с all-sky теперь полностью свободен. Я добавил дебайеризацию посредством libraw. Вот такие jpeg'и теперь может генерировать сетевой клиент (помимо сохранения "сырых данных" в tiff, fits и raw dump):

Камеру можно будет водрузить на ее законное место, временная заглушка для информационных панелей уже будет работать, останется настроить сервер БД для хранения данных (чтобы иметь возможность оценить небо в любой момент времени из архивных данных).
Еще остается подключить болтвудовский датчик, но это не так критично, как нормальный all-sky.

Глюки

Feb. 17th, 2017 06:05 pm
Поставил на кубитрак армбиан (нет уже сил с гентой: собирать пакеты можно лишь на компьютере, несерьезно это). Почти час убил в попытках понять, почему же у меня перестало работать считывание изображения с all-sky. Затык обнаружился здесь:
size_t read_tty(uint8_t *buff, size_t length){
    ssize_t L = 0;
    fd_set rfds;
    struct timeval tv;
    int retval;
    FD_ZERO(&rfds);
    FD_SET(comfd, &rfds);
    tv.tv_sec = 0; tv.tv_usec = 50000; // wait for 50ms
    retval = select(comfd + 1, &rfds, NULL, NULL, &tv);
    if (!retval) return 0;
    if(FD_ISSET(comfd, &rfds)){
        if((L = read(comfd, buff, length)) < 1) return 0;
    }
    return (size_t)L;
}

Строчка "wait for 50ms". Функция эта выполняется до тех пор, пока полностью нужное количество байт не считается, или не выйдет таймаут. Почему-то на компьютере все нормально работало, а на кубитраке стали "теряться" данные. Пришлось увеличить tv.tv_usec до 500мс.

А еще я намучился с форматом для printf: на компьютере uint64_t выводится как %lu, а кубитрак хочет %llu. Неужто нет нормальных обозначений printf, общих для любых архитектур? Идиотизм какой-то...
Сегодня, несмотря на то, что меня неоднократно отрывали от работы, я таки добил получение изображения с камеры. Теперь можно уже с преальфы переназвать альфой. Но, конечно, еще сильно сырая: нужно оставшиеся команды управления камерой реализовать, да добавить "демонизацию" с управлением через сокет или еще какой-нибудь IPC (надо, кстати, книжечку по IPC с дома на работу принести).
Вот такая картиночка получается (исходный tiff пришлось в gif сжать):
outp

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

Но, все-таки, 16 секунд на считывание несчастной картинки 640х480 на максимальной скорости — это финиш! А если провод подлинней сделать, скорость в 4 раза меньше должна быть! В документации сказано, что есть возможность одновременно копить и считывать, но как это сделать, учитывая, что во время накопления камера не реагирует на внешние раздражители, непонятно!
Geany вполне способен работать с автодополнением — нужно лишь сгенерировать для него файлы с тегами. Его формат не совсем совместим с ctags, но здесь доступно описывается, что geany -g генерирует файлы с тегами, которые затем можно вставить в проект. Можно добавить в Makefile правило для автоматической перезаписи этого файла.

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

Вот так генерируется файл для libopencm3 под F0:
CFLAGS="-DSTM32F0 -DSTM32F042x6 -I/usr/local/arm-none-eabi/include" geany -g opencm3f0.c.tags /usr/local/arm-none-eabi/include/libopencm3/stm32/*.h /usr/local/arm-none-eabi/include/libopencm3/stm32/f0/* /usr/local/arm-none-eabi/include/libopencm3/cm3/*.h  /usr/local/arm-none-eabi/include/libopencmsis/core_cm3.h /usr/local/arm-none-eabi/include/libopencmsis/stm32/f0/irqhandlers.h /usr/local/arm-none-eabi/include/libopencm3/stm32/common/*.h 2>/dev/null


Жаль только, что при щелчке с ctrl по функциям/переменным файл с их определением не открывается. В перечнях плагинов я такой вещи не встречал. Будем ждать реализации...

Makefile

Jan. 11th, 2017 11:08 am
В мелких проектах совершенно не хочется мучиться с cmake, но и Makefile в том виде, что у меня был, далек от совершенства. Полтора часа убил, чтобы автоматом генерировать зависимости. До этого у меня было правило, делающее @touch сишному файлу, если изменился соответствующий заголовочный файл, и это вызывало проблемы с другими сишными файлами, включающими этот же заголовок. Другой проблемой было постоянное напоминание geany, что файл был обновлен извне (то, что содержимое после touch не изменилось, его не волнует).
Множество решений с SO выдавало всякие разные проблемы. Основной было то, что как только я изменю какой-нибудь файл (.h или .c — в разных вариантах по-разному), как make переставал удовлетворяться предыдущей сборкой после обновления и постоянно пересобирал совершенно все!
Вот это решение вроде как спасает ситуацию.
Makefile )
(оно, правда, тоже пересобирает все подряд, но уже не постоянно, а лишь несколько последующих запусков).
Потратив часть вечера на патч модуля ядра нетбука (вчера я сдуру думал вообще ядро обновить, но сегодня одумался и только ch341.ko пересобрал; странно, кстати, что этот патч тянется еще с третьего ядра, но даже в моем 4.4.21 его "из коробки" нет).
А потом руки таки дошли до STM32F042. Структуру репозитория я переделал, раскидав примеры по поддиректориям (в F0 лежат примеры для нулевой серии, в F1, соответственно, для F103). Сдуру забыл, что в гите нет удобной "ртутной" штучки под названием addremove, после коммита и пуша старые файлы остались. Пришлось делать
git add -A
и еще раз коммит и пуш.
Примерчик совсем простой: мигает зеленым светодиодом с частотой 4Гц или 1Гц (если установить перемычку между землей и ногой PA12). Дальше надо заняться ШИМом, I2C и UART. Очень жаль, что не разведен USB на платке. Придется колхозить на проводках.

P.S. Дропбокс, на котором я храню все эти вещи (для синхронизации между компьютерами) сдулся. Видимо, я переполнил доступный объем. Яндодиск тормозит жутчайшим образом, а гуглодрайв надо вручную синхронизировать. Но, что поделать — больше дропбоксоподобных вещей, но со значительно большим лимитом я не знаю.

P.P.S. В очередной раз подумал, что geany сильно не хватает плагина, позволяющего работать автодополнению по файлам, указанным в каком-нибудь конфиг-файле. Чтобы не нужно было 100500 файлов держать открытыми. Можно, конечно, свернуть подавляющее большинство нужных мне вещей из opencm3 в один файл, но он же будет совершенно нечитабельным!
Закончил железяку и оформил в коробочку из-под селедки. Вот такая штука получилась:

Дальше )
Позор мне! Гугол не дал мне ответа на этот вопрос...
Суть проблемы: ни UNIX-time, ни юлианская дата не учитывают високосных секунд (юлианская дата еще и некоторых високосных дней не учитывает). Поэтому отняв время события А из времени события Б мы не получим реальной разницы во времени между ними.
Неужто нет такой сишной системной функции, которая это считает, используя tzdata и нужно парсить этот файл самому?

UPD. Решение было у меня под носом: это умеет libSOFA.
Я всегда думал, что это одно и то же, однако, оказалось, что совсем не так! Обратил внимание, что код из предыдущей записи как-то неоптимально компилируется: в ассемблерном листинге в операции деления на 2 вместо сдвига было реальное деление. "Что за нафиг?" — подумал я, и заменил деление на сдвиг. Благо, коммит не делал — решил сначала проверить. И вот, вместо ожидаемого периода в 10мс (6000 об/мин) получаю какую-то чертовщину! Меняю обратно на деление: вуаля!

Что за … ?
куски кода )
Как и ожидалось, причиной всему — рукожопость. Мне вот только оператором термоядерных станций работать (пусть это фантастика, но будем считать, что все-таки в будущем "холодный термояд" появится): к середине смены ничего в радиусе пары сотен километров вокруг станции не останется ☺
Такие как я забывают наручные часы/скальпели/зажимы/etc внутри пациентов во время операции, не доворачивают гайки на колесах при "переобувке", выезжают в гололед на летней резине и просыпают время посадки на свой рейс...

Ошибка была элементарной: зачем-то int16_t я поменял на int32_t, в результате чего вся котовасия и началась!
Теперь код выглядит так:
Код )
В этом месяце технические ночи по "причинческим технинам" разносятся на вторые половины 12-13 и/или (в зависимости от погоды) 16-17 ноября. Уже второй месяц у меня лежит гироскоп MPU-5060, который Гриша предложил прицепить в СПФ, чтобы логгировать реальные вибрации — тогда точно будет понятна причина дрожания изображений (если вибрации не будут наблюдаться, то явно виноват воздух, а не железо; vice versa). Но пока эта железяка упорно отказывается работать. Хотя даташит исчитан вдоль и поперек...
Скучные подробности )
Бета-версия мультипортового сниффера готова! Пока он умеет немногое, но основное свое предназначение выполняет.
Подробней )

September 2017

S M T W T F S
     1 2
3456789
1011 12 13141516
17181920 212223
24252627282930

Syndicate

RSS Atom

Style Credit

Expand Cut Tags

No cut tags
Page generated Sep. 25th, 2017 04:16 am
Powered by Dreamwidth Studios