что такое расширенное логирование gps
gps.conf для всех, или как ускорить работу GPS на Android
«Фантастика!» подумал я и без промедления перешел по ссылке. По сравнению с первым постом в этот раз предлагались еще более конкретные действия, а именно заменить содержимое файла gps.conf (его можно найти по пути /etc/gps.conf, должны быть root-права) на следующие настройки:
NTP_SERVER=ua.pool.ntp.org
NTP_SERVER=0.ua.pool.ntp.org
NTP_SERVER=1.ua.pool.ntp.org
NTP_SERVER=2.ua.pool.ntp.org
NTP_SERVER=3.ua.pool.ntp.org
NTP_SERVER=europe.pool.ntp.org
NTP_SERVER=0.europe.pool.ntp.org
NTP_SERVER=1.europe.pool.ntp.org
NTP_SERVER=2.europe.pool.ntp.org
NTP_SERVER=3.europe.pool.ntp.org
XTRA_SERVER_1=/data/xtra.bin
AGPS=/data/xtra.bin
AGPS=http://xtra1.gpsonextra.net/xtra.bin
XTRA_SERVER_1=http://xtra1.gpsonextra.net/xtra.bin
XTRA_SERVER_2=http://xtra2.gpsonextra.net/xtra.bin
XTRA_SERVER_3=http://xtra3.gpsonextra.net/xtra.bin
DEFAULT_AGPS_ENABLE=TRUE
DEFAULT_USER_PLANE=TRUE
REPORT_POSITION_USE_SUPL_REFLOC=1
QOS_ACCURACY=50
QOS_TIME_OUT_STANDALONE=60
QOS_TIME_OUT_agps=89
QosHorizontalThreshold=1000
QosVerticalThreshold=500
AssistMethodType=1
AgpsUse=1
AgpsMtConf=0
AgpsMtResponseType=1
AgpsServerType=1
AgpsServerIp=3232235555
INTERMEDIATE_POS=1
C2K_HOST=c2k.pde.com
C2K_PORT=1234
SUPL_HOST=FQDN
SUPL_HOST=lbs.geo.t-mobile.com
SUPL_HOST=supl.google.com
SUPL_PORT=7276
SUPL_SECURE_PORT=7275
SUPL_NO_SECURE_PORT=3425
SUPL_TLS_HOST=FQDN
SUPL_TLS_CERT=/etc/SuplRootCert
ACCURACY_THRES=5000
CURRENT_CARRIER=common
Эти настройки рассчитаны на жителей Украины, но для жителей России их очень легко адаптировать заменив ua.pool на ru.pool.
Далее нужно перезагрузить Android, а затем запустить программу для работы с GPS и наслаждаться стабильным сигналом.
От себя могу добавить, что я пользуюсь приложением GPS Status и после перезагрузки при первом запуске приложения я сделал сброс данных кэша: в программе вызываем меню, далее выбираем Tools, там Manage A-GPS state и жмем Reset, а затем Download.
Снимаю шляпу перед автором оригинального поста, уважаемым mechanicuss. Его совет помог не только мне, и может помочь еще многим страдающим.
На этом все. Всем чистого неба и стабильного сигнала из космоса.
О системе трекинга в машине — ведение лог-файла пути поездки.
Идея записывать трек своего перемещения возникает у многих туристов, и не только автомобильных. После установки в машину стационарного Android-комбайна с функцией GPS/ГЛОНАСС мысль найти для него программу-трекер появилась сразу. Поскольку в поездках нередко бывают моменты, когда сотовой связи нет, а соответственно нет и интернета, хотелось чтобы программа-трекер умела писать трек в файл, и время от времени отправлять трек на сервер.
Хотелось также, чтобы программа стартовала в автозапуске при старте самой AndroidOS, основную свою деятельность вела в фоновом режиме, никак не занимая экран, и имела лаконичный, простой интерфейс.
После некоторых поисков я остановился на RealTime GPS Tracker который как раз и отвечал заявленным требованиям — лаконичный главный экран и основная работа в фоне.
— В разделе — все треки пользователя хранятся на сервере livegpstracks.com неограниченное время, могут быть объединены в группы, просмотрены на разных картах-подложках (доступны openstreetmap, yandexmap, googlemap, генштаб и т. п.), выгружены в разных форматах на локальный компьютер/планшет пользователя и могут быть посланы другим в виде ссылки на общедоступную web-страницу с картой и треком, или вставлены в виде ссылки в блог, вконтакт и т. п.
— в разделе есть онлайн-планировщик маршрута (я не пользовался), раздел работы с точками POI (Point-Of-Interest – точки всяческих интересных и полезных мест на местности) (я не пользовался), раздел конвертации где трек можно сконвертировать в самые различные форматы и выгрузить на свой локальный компьютер/планшет, а также пересчитать координаты.
Есть еще один раздел — который ориентирован на другую программу-трекер этого же производителя — LiveGPS Tracker. Вот здесь даны отличия этих программ-трекеров. Использование раздела полностью бесплатное. Может быть, возможности LiveGPS Tracker вам понравятся больше, мне эта программа не подошла.
При просмотре свойств обеих программ надо отметить, что некоторая информация в этой таблице про RealTimeGPS Tracker не соответствует действительности:
— хранение данных без связи с сервером — стоит НЕТ, по факту при записи данных в файл на локальном устройстве файл никуда не исчезает, данные в него исправно пишутся, в 00:00 происходит корректное закрытие этого файла и открытие нового, куда данные будут писаться следующие сутки. Наличие или отсутствие связи с сервером никак на это не влияет. Необходимо лишь в настройках программы включить запись трека в файл на локальной файловой системе, и она будет и отправлять данные на сервер и писать их в файл параллельно.
— сохранение данных после перезапуска программы — стоит НЕТ, по факту, перезапуск программы никак не влияет на накопление данных в текущем файле.
— гибкие настройки параметров записи — стоит НЕТ, по факту я не знаю, что имелось в виду в данной фразе. Настройки параметров записи в RealTimeGPS Tracker вполне гибкие, как я уже описывал выше.
Пошаговые руководства, шпаргалки, полезные ссылки.
Инструменты пользователя
Инструменты сайта
Боковая панель
Как включить расширенное логирование на стороне агента System Center DPM
Для поиска причин возникновения тех или иных проблем в работе агента DPM может помочь включение механизма расширенного логирования. Для того, чтобы включить максимальный уровень логирования работы агента System Center DPM выполните следующие настройки:
На стороне защищаемого сервера (там, где установлен агент DPM) откройте редактор системного реестра Windows с правами Администратора и найдите следующий ключ реестра:
Добавьте в этот ключ реестра новый параметр TraceLogLevel (тип REG_DWORD) со значением 0x43e
Для вступления изменений в силу остановите службу агента DPM, если она была запущена, командой:
Воспроизведите проблему, например запустите синхронизацию или создание точки восстановления в консоли сервера SCDPM (в процессе выполнения этих задач служба агента DPM будет автоматически запущена с новыми настройками логирования)
После того, как задание завершено, то есть фактически воспроизведена проблема, воспользуйтесь для анализа ситуации файлом лога:
C:\Program Files\Microsoft Data Protection Manager\DPM\Temp\DPMRACurr.errlog
После того, как анализ расширенных логов закончен, обязательно удалите созданный ранее ключ реестра, чтобы не создавать излишней нагрузки на защищаемый сервер при работе агента DPM, и перезапустите службу агента DPM.
Дополнительные источники информации
Автор первичной редакции:
Алексей Максимов
Время публикации: 21.04.2016 21:21
Как ускорить подключение GPS и увеличить точность GPS на Андроид
Как ускорить подключение GPS и увеличить точность GPS на Андроид. В данной статье вы узнаете как с помощью не сложных манипуляций в несколько десятков раз ускорить подключение GPS и увеличить и его точность на смартфонах и планшетах на ОС Android!
Теория
GPS ( Global Positioning System — система глобального позиционирования ) — система необходимая для высокоточного определения месторасположения, используется для навигации и других целях.
A-GPS — усовершенствованная система GPS, которая ускоряет холодный и горячий старт, за счет дополнительных каналов связи (WI-FI, сотовая связь), а также повышает точность позиционирования.
Холодный и горячий старт GPS — модуль GPS записывает данные о расположение спутников и другие значения (альманах), при их отсутствие или если данные устарели происходит холодный старт, который может продлиться от 5 — 15 минут, в течение этого времени модуль будет обновляться информация о GPS спутниках и в дальнейшем пытаться к ним подключиться, если модуль имеет все данные и они не устарели происходит горячий старт, время подключения к спутникам длиться 1 — 5 минут.
Абсолютно во всех новых смартфонах и планшетах Android (в которых есть GPS) используется A-GPS.
Ускорить подключение GPS и увеличить его точность
Необходимое
1. Наличие Root прав на Android смартфоне или планшете
2. Файловый менеджер с доступом в раздел /system, например Root Browser
4. Установить на ПК текстовый редактор NotePad ++ (Windows), для Linux пользователей Gedit
Извлечь файл GPS.CONF
За работу GPS модуля в Android отвечает файл GPS.CONF, который необходимо извлечь из системного раздела. Находиться он по пути /system/etc/gps.conf и переместить во внутреную память или SD карту, чтобы в дальнейшем редактировать его на ПК.
Редактирование GPS.CONF
Чтобы ускорить подключение GPS и увеличить его точность необходимо изменить настройки GPS.CONF. Откройте его с помощью Notepad++. В зависимости от производителя вы можете увидеть различные внесенные настройки.
Настройка NTP сервера
Приступим к модернизации файла GPS.CONF! Первое что необходимо выполнить — это дописать или переписать NTP_SERVER. NTP — это это высокоточный сервер синхронизации времени. В зависимости от вашего место расположения необходимо изменять главный NTP сервер. Как вы можете видеть выше на скрине указан сервер north-america.pool.ntp.org, что явно не ускорит подключение к GPS если вы к примеру находитесь в Белоруссии, Украине, России. Поэтому необходимо прописать «местный» сервер:
Также можно воспользоватся общим сервером для Европы: europe.pool.ntp.org
Пример как должно быть записано:
также можно дополнительно внести еще один сервер Европы, в случае не работы из одного из местных серверов
Пример:
Некоторые ромоделы кастомных прошивок вносят множество других NTP сервером, что не есть верно, так как, при этом подключение наоборот замедляется, из-за того что 5-6 серверов может не работать, а Android все равно будет тратить время на соединение.
Также существует альтернативные сервера XTRA их рекомендуется вписать и не выполнять никаких изменений
Задействовать или не задействовать WI-FI
Для увеличения точности навигации, а также увеличения подключения к спутинкам GPS можно задействовать беспроводной протокол передачи данных WI-FI. Для этого необходимо вписать следущий параметр:
Значение 1 разрешит использовать WI-FI, значение 0 наоборот запретит
Например:
Отчет промежуточных позиций (точность GPS или скорость подключения)
Данный параметр отвечает за скорость и точность GPS, если больше скорость (холодный и горячий старт), то меньше точность
Значение 0 — точные данные, медленней подключение.
Значение 1 — менее точные данные (чем дольше проработает, тем точней будут в течение одной сессии), но быстрей подключение.
Например:
Порог точности промежуточных позиций (точность GPS)
Данный параметр, откидывает погрешности
Значение 0 — учитывать все данные
Значение 100, 200, 300, 1000, 5000 — удаляет погрешности
Рекомендуется выставлять параметр 0, но вы можете поэкспериментировать
Например
Задействовать A-GPS (скорость, точность)
Параметр отвечает за то будет включен или отключен A-GPS (при включенном точней)
Значение TRUE — использовать A-GPS
Значение FALSE — не использовать A-GPS
Например
Подключение к точки соединения (Supplicant)
Прописать такие значения если не указаны:
Тип использования передачи данных в A-GPS
Значение TRUE — использовать User Plane
Значение FALSE — использовать Control Plane
Например:
Итоговый вариант файла GPS.CONF
Отредактированный вариант файла GPS.CONF сохранить и забросить обратно в Android и перезагрузить его! Поздравляю вы смогли ускорить подключение GPS и увеличить его точность на вашем Android!
Легкий способ для Ленивых
Для тех кто не хочет экспериментировать и хочет положиться на чужой опыт, можете воспользоваться готовым, модифицированным файлом gps.conf. По заявлению авторов BlackIce Team подключения к GPS спутникам происходит практически мгновенно.
Все что вам нужно — это скачать gps.conf для своей страны и забросить его по пути /system/etc, после чего перезагрузить Android.
Скачать коллекцию оптимизированных GPS.CONF
Многофункциональный GPSLogger своими руками. Часть 1
Я являюсь обладателем замечательного устройства — GPS логгера Holux M-241. Штука весьма удобная и полезная в путешествиях. С помощью логгера я пишу GPS трек поездки, по которому потом можно посмотреть свой путь в деталях, а также привязать снятые фотографии к GPS координатам. А еще у него есть небольшой экран который показывает дополнительную информацию — часы, текущую скорость, высоту и направление, одометр и многое другое. Вот тут я когда то написал небольшой обзор.
При всех достоинствах железки я стал из нее вырастать. Мне не хватает нескольких небольших, но полезных плюшек: несколько одометров, показ вертикальной скорости, замер параметров участка пути. Вроде мелочи, но фирма Holux посчитала это недостаточно полезным для реализации в прошивке. Так же мне не нравятся кое какие параметры железяки, а некоторые вещи за 10 лет уже морально устарели…
В какой то момент я осознал, что могу сам сделать логгер с такими фичами как мне нужно. Благо все необходимые компоненты достаточно дешевы и доступны. Свою реализацию я начал делать на основе Arduino. Под катом дневник постройки, где я постарался расписать свои технические решения.
Определяемся с фичами
Многие спросят, зачем мне строить свой логгер, если наверняка есть что нибудь готовое у именитых производителей. Возможно. Если честно, особо не искал. Но наверняка там будет чего нибудь нехватать. В любом случае этот проект — фан для меня. Почему мы и не заняться постройкой устройства своей мечты?
Итак, за что же я ценю свой Holux M-241.
Но для меня работа от батареек это сущий геморрой. Приходится носить горсть батареек и кто его знает насколько они качественные (вдруг они лежали 5 лет на полке и уже саморазрядились). С аккумами гемор еще больше. У меня зарядник умеет только парами заряжать. Приходится разряжать аккумы, чтобы они были одной степени разряжености. В итоге никогда не помнишь где уже разряженные, а где еще нет.
За 6 лет использования логгера я всего пару раз оказывался в глуши без электричества. Как правило у меня хотя бы раз в сутки появляется доступ к розетке. В таком случае встроенный литиевый аккумулятор был бы гораздо удобнее. Ну а на крайний случай у меня павербанк есть.
К тому же не каждая программа умеет слопать формат слитых треков. Родная утилита очень убога. Благо есть BT747, которая может адекватно слить трек и сконвертировать в какой нибудь удобоваримый формат.
Всякое разное. Сам не использую, но вдруг кому полезно:
Выбираем железо
С требованиями более менее определились. Пора понять на чем это все можно реализовать. Главные компоненты у меня будут такие:
Под рукой как раз валялась россыпь разнокалиберных ардуинок, а также парочка stm32f103c8t6. Решил начать с AVR, которые я хорошо знаю на уровне контроллера/регистров/периферии. Если упрусь в ограничения — будет повод пощупать STM32.
Но для начала нужно определится с очень важным вопросом — питание компонентов. Мне показалось разумным запитать все от 3.3В: GPS и экран только на нем и умеют работать. Это так же родное напряжение для USB и SD. К тому же схему можно запитать от одной литиевой банки
Выбор пал на Arduino Pro Mini, которую можно найти в версии 8МГц/3.3В. Вот только USB у нее на борту не оказалось — пришлось использовать USB-UART переходник.
Первые шаги
Вначале проект создал в Arduino IDE. Но если честно, у меня язык не поворачивается называть это IDE — так, текстовый редактор с компилятором. Во всяком случае после Visual Studio, в которой я работаю последние 13 лет делать что либо серьезное в Arduino IDE без слез и матюков не получается.
Благо есть бесплатная Atmel Studio, в которой даже Visual Assist из коробки встроен. Программа умеет все что нужно, все привычно и на своих местах. Ну почти все (не нашел только как скомпилировать только один файл, например, чтобы синтаксис проверить)
Начал с экрана — это нужно чтобы отладить скелет прошивки, а потом наполнять ее функциональностью. Остановился на первой попавшейся библиотеке для SSD1306 от Adafruit. Она умеет все что нужно и предоставляет очень простой интерфейс.
Поиграл шрифтами. Оказалось один шрифт может занимать до 8кб (размер букв 24пт) — особо не разгуляешься в 32кб контроллере. Большие шрифты нужны, например, для вывода времени.
Шрифты в комплекте с библиотекой весьма корявые. Моноширинный шрифт оказался очень широким — строка “12:34:56” не влазит, Serif — все цифры разной жирности. Разве что стандартный шрифт 5×7 в библиотеке выглядит съедобно.
Оказалось, что эти шрифты были сконверчены из каких то опенсорсных ttf шрифтов, которые просто не оптимизированы под мелкие разрешения.
Пришлось рисовать свои шрифты. Точнее сначала выколупывать из готовых отдельные символы. Символ ‘:’ в таблице ASCII очень кстати находится сразу после цифр и можно выколупать одним блоком. Так же удобно, что можно делать шрифт не на все символы, а только на диапазон, например от 0x30 (‘0’) до 0x3a (‘:’). Т.о. из FreeSans18pt7b получилось сделать весьма компактный шрифт только на нужные символы. Пришлось правда чуток подхачить ширину, чтобы текст влезал на ширину экрана.
Оказалось, что шрифт 18пт на самом деле высотой 25 пикселей. Из-за этого он слегка налазит на другую надпись
Инвертированный дисплей, кстати, помогает понять где на самом деле находятся границы области рисования и как относительно этой границы лежит строка — дисплей имеет весьма большие рамки.
Долго гуглил готовые шрифты, но они не подходили или по размеру, или по форме, или по содержанию. К примеру в интернете валом шрифтов 8х12 (дампы знакогенераторов VGA карт). Но по факту эти шрифты являются 6х8, т.е. гуляет куча места — в случае такого маленького разрешения и размера как у меня это критично.
Пришлось таки рисовать свои шрифты, благо формат шрифтов у Adafruit библиотеки очень простой. Картинку готовил в Paint.net — просто рисовал буквы нужным шрифтом, потом чуток корректировал карандашом. Картинку сохранял как png, а затем отправлял в побыстряку написанный на коленке питоновский скрипт. Этот скрипт генерировал полуфабрикат кода, который уже точечно правил в IDE прямо в хекс кодах.
Например так выглядит процесс создания моноширинного шрифта 8х12 с маленькими межбуквенными и межстрочными интервалами. Каждый символ в итоге получился примерно 7х10, и по умолчанию занимал 10 байт. Можно было бы упаковать каждый символ в 8-9 байт (библиотека это позволяет), но я не стал заморачиваться. К тому же в таком виде можно редактировать отдельные пиксели прямо в коде.
Каркас
Оригинальное устройство предоставляет весьма простой и удобный интерфейс. Информация группируется по категориям, которые показываются от отдельных страничках (экранах). С помощью кнопки можно циклически переключаться между страничками, а второй кнопкой выбрать текущий пункт или выполнить действие которое указано в подписи под кнопкой. Такой подход мне кажется весьма удобным и не нужно ничего менять.
Мне нравится красота ООП, потому я сразу слепил небольшой интерфейсик, каждая страничка реализует интерфейс как ей требуется. Страничка знает как себя нарисовать и реализует реакцию на кнопки.
В зависимости от текущего экрана кнопки могут выполнять различные действия. Поэтому верхнюю часть экрана высотой в 8 пикселей я отвел на подписи для кнопок. Текст для подписей зависит от текущего экрана и возвращается виртуальными функциями getSelButtonText() и getOkButtonText(). Также в шапке будут еще отображаться служебные штуки типа уровня сигнала GPS и заряда батареи. Оставшиеся ¾ экрана доступны для полезной информации.
Как я уже сказал экранчики могут перелистываться, а значит где то должен быть список объектов для разных страниц. При чем не один — экраны могут быть вложенными, как подменю. Я даже завел класс ScreenManager, который должен был управлять этими списками, но потом я нашел решение проще.
Так каждый экран просто имеет указатель на следующий. Если скрин позволяет войти в подменю, то у него добавляется еще один указатель на скрин этого подменю
По умолчанию обработчик кнопки просто вызывает функцию смены экрана, передавая ей нужный указатель. Функция получилась тривиальной — она просто переключала указатель на текущий экран. Чтобы обеспечить вложенность экранов я сделал небольшой стек. Так что весь менеджер экранов у меня поместился в 25 строк и 4 маленькие функции.
Правда код наполнения этих структур выглядит не очень красиво, но пока лучше не придумал.
Идем дальше. В своей реализации интерфейса мне захотелось сделать что то наподобие message box’а — короткого сообщения, которое бы показывалось на секунду-другую, а потом исчезало. Например, если на экране с текущими координатами нажать кнопку POI (Point Of Interest), то помимо записи точки в трек было бы неплохо показать пользователю сообщение “Waypoint Saved” (в оригинальном устройстве просто на секунду показывается дополнительная иконка). Или при разряде батареи “взбодрить” пользователя соответствующим сообщением.
Поскольку данные с GPS будут приходить постоянно, то ни о каких блокирующих функциях речи быть не может. Поэтому пришлось изобрести простенькую стейт машину (конечный автомат), которая в функции loop() выбирала бы что делать — показывать текущий экран или мессадж бокс.
Также с помощью машины состояний удобно обрабатывать нажатия кнопок. Возможно, через прерывания было бы правильно, но так тоже неплохо получилось. Работает это так: если в состоянии IDLE была нажата кнопка — запомним время нажатия и переходим в состояние BUTTON_PRESSED. В этом состоянии ждем пока пользователь отпустит кнопку. Тут мы можем подсчитать длительность когда кнопка была нажата. Короткие срабатывания ( 1c) для специальных функций. Например, короткое нажатие запускает/приостанавливает одометр, длинное нажатие сбрасывает значение счетчика в 0.
Возможно и другие состояния добавятся. Так, например, в оригинальном логгере после переключения на очередную страничку значения на экране меняются часто, а через пару секунд реже — раз в секунду. Это можно сделать добавлением еще одного состояния.
Когда каркас был готов, я уже, было, начал подключать GPS. Но тут возникли нюансы, которые заставили меня отложить эту задачу.
Оптимизация прошивки
Прежде чем идти дальше мне нужно отвлечься на кое какие технические детали. Дело в том, что примерно в этом месте я начал бодаться с растущим потреблением памяти. Оказалось, что строка опрометчиво объявленная без модификатора PROGMEM на старте прошивки копируется в ОЗУ и занимает там место в течении всего времени выполнения.
В двух словах. На больших компах используется Фон Неймановская архитектура где код и данные располагаются в одном адресном пространстве. Т.е. данные как из ОЗУ так и из ПЗУ будут читаться одинаковым способом.
В микроконтроллерах, как правило, используется Гарвардская архитектура, где код и данные разделены. Т.о. приходится использовать различные функции для чтения памяти и флеша. С точки зрения языка C/C++ указатели выглядят одинаково, но при написании программы мы должны точно знать куда на какую именно память указывает наш указатель и вызывать соответствующие функции.
Благо разработчики библиотек уже, отчасти, позаботились об этом. Основной класс библиотеки дисплея — Adafruit_SSD1306 наследуется от класса Print из ардуиновской стандартной библиотеки.
Это предоставляет нам целую серию разных модификаций метода print — для печати строк, отдельных символов, чисел и чего то там еще. Так вот в нем есть 2 отдельные функции для печати строк:
Первая знает, что нужно печатать строку из флешки и посимвольно ее загружает. Вторая печатает символы из ОЗУ. По факту обе эти функции принимают указатель на строку, только из разных адресных пространств.
Я долго искал в коде ардуино этот самый __FlashStringHelper чтобы научиться вызывать нужную функцию print(). Оказалось дядьки поступили хитро: они просто объявили такой тип с помощью forward declaration (без объявления самого типа) и написали макрос, который кастил указатели на строки во флеше к типу __FlashStringHelper. Просто чтобы компилятор сам выбирал нужную перегруженную функцию
Это позволяет писать так:
Но не позволяет писать так
И, судя по всему, библиотека не предоставляет ничего, что бы можно было так делать. Я знаю, что нехорошо в своем коде использовать приватные штуки библиотек, но что мне было делать? Я нарисовал свой макрос, который делал то, что мне нужно.
Так функция рисования шапки стала выглядеть так:
Ну а раз я уж влез в низкоуровневые штуки прошивки, то решил глубже изучить как же там оно все внутри устроено.
Вообще, ребятам которые придумали Ардуино нужно поставить памятник. Они сделали простую и удобную платформу для прототипирования и поделок. Огромное количество народу с минимальными знаниями электроники и программирования смогли войти в мир Ардуино. Но все это гладко и красиво пока делаешь фигню типа моргалки светодиодами или считывания показаний термометра. Как только замахиваешься на что нибудь серьезное сразу приходится разбираться глубже чем хотелось с самого начала.
Так, после каждой добавленной библиотеки или даже класса я отмечал как быстро растет потребление памяти. К этому моменту у меня было занято более 14 кб из 32 кб флеша и 1300 байт ОЗУ (из 2к). Каждое неосторожное движение добавляло еще процентов 10 к уже используемому. А ведь я еще толком не подключил GPS и SD/FAT32 библиотеки, а самого функционала пока кот наплакал. Пришлось брать в руки шашку дизассемблер и изучать что же там компилятор такого наколбасил.
Я в тайне надеялся, что линкер выкидывает неиспользуемые функции. Но оказалось, что некоторые из них линковщик вставляет практически целиком. В прошивке я обнаружил функции рисования линий и некоторые другие из библиотеки работы с экраном, хотя в коде я их явно на тот момент не вызывал. Неявно они тоже вызываться не должны — зачем нужна функция рисования линии, если я только буквы из битмапок рисую? Более 5.2кб на ровном месте (и это не считая шрифтов).
Помимо библиотеки управления дисплеем я еще обнаружил:
Так же в коде я обнаружил:
Среди этого нашелся здоровенный массив со “сплешскрином” экрана — начальные значения буфера кадра. Теоретически если сделать экрану display() сразу после старта, то можно увидеть цветок и надпись Adafruit, но в моем случае тратить на это флеш память бессмысленно.
Что с этим делать? Пока не знаю. Будет зависеть от того как будет расти потребление дальше. По хорошему найденные косяки нужно нещадно чинить. По всей видимости мне придется втянуть к себе в проект все библиотеки явно а потом почекрыжишь их хорошенько. А еще возможно придется по другому переписать некоторые куски с целью оптимизировать память. Или перейти на более мощное железо. В любом случае теперь я знаю о проблеме и есть стратегия как его чинить.
UPDATE:
Немного продвинулся в эффективности использования ресурсов. Делаю апдейт к этой части, т.к. в следующей хочу сфокусироваться на совершенно других вещах.
В коментах наблюдается некоторое недоумение по поводу использования С++. В частности что ж это он такой плохой и vtable хранит в драгоценной RAM? И вообще, виртуальные функции, конструкторы и деструкторы — это ж накладные расходы. Зачем? Давайте разбираться!
Вот статистика по памяти на некотором этапе проекта
Program size: 15 458 bytes (used 50% of a 30 720 byte maximum) (2,45 secs)
Minimum Memory Usage: 1258 bytes (61% of a 2048 byte maximum)
Эксперимент №1 — переписываем на С.
Я выкинул классы, переписал все на таблицах с указателями на функции. Поскольку экраны на самом деле имеют всегда одинаковую структуру, то все члены данных стали обычными глобальными переменными.
Статистика после рефакторинга
Program size: 14 568 bytes (used 47% of a 30 720 byte maximum) (2,35 secs)
Minimum Memory Usage: 1176 bytes (57% of a 2048 byte maximum)
Итого. Выиграл 900 байт флеша и 80 байт ОЗУ. Что именно ушло из флеша не копал. 80 байт ОЗУ это как раз размер vtable’ов. Все остальные данные (члены классов) так или иначе остались.
Должен сказать, что спортировал я не все — мне просто хотелось увидеть общую картину, не особо тратя на это время. После рефакторинга я “потерял” вложенные скрины. С ними потребление было бы чуток больше.
Но что самое главное в этом эксперименте, так это то, что качество кода значительно ушудшилось. Код одного функционала стал размазаным по нескольким файлам. Для некоторых кусков данных перестал существовать «один владелец», одни модули стали лазить в память других. Код стал размашистым и некрасивым.
Эксперимет №2 — выжимаем байты из С++
Свои сишные эксперименты я откатил, решил все оставить классами. Только на этот раз экраны делать на статически распределенных объектах. Структура страничек экранов у меня фиксирована. Можно задать ее на этапе компиляции без использования new/delete.
Program size: 15 408 bytes (used 50% of a 30 720 byte maximum) (2,60 secs)
Minimum Memory Usage: 1273 bytes (62% of a 2048 byte maximum)
Потребление ОЗУ немножко выросло. Но это, на самом деле, к лучшему. Увеличение потребление ОЗУ объясняется перемещеним объектов из кучи в статически распределенную область памяти. Т.е. по факту объекты и раньше создавались, только это не шло в статистику. А теперь эти объекты учитываются явно.
Но вот ощутимо уменьшить потребление флеша не получилось. В коде все еще остались сами конструкторы, которые по прежнему вызываются на старте. Т.е. Компилятор не смог их “выполнить” заранее и поместить все значения в заранее распределенные области. А еще в коде по прежнему были деструкторы, хотя и ежу понятно, что объекты никогда удалятся не будут.
В попытке сэкономить хотя бы чутьчуть я удалил все деструкторы в иерархии, и в частности виртуальный деструктор в базовом классе. Идея была в том, что бы освободить пару байт в каждом vtable. И тут меня ждал сюрприз:
Program size: 14 704 bytes (used 48% of a 30 720 byte maximum) (2,94 secs)
Minimum Memory Usage: 1211 bytes (59% of a 2048 byte maximum)
Оказалось из vtable’ов поуходило не по одному указателю, а аж по 2. При чем оба на деструктор. Только один деструктор пустой (видимо для объектов на стеке), а другой с вызовом free, видимо для объектов на куче (-12 байт ОЗУ). Так же ушли переменные связаные с хипом (8 байт) и втейблы объектов, которые никогда и не создаются (Screen, ParentScreen — 40 байт)
Потребление флеша уменьшилось существенно — на 700 байт. Ушли не только сами деструкторы, но и реализации malloc/free/new/delete. 700 байт за пустой виртуальный деструктор! 700 байт, Карл!
Что бы не мотать туда-сюда, вот все цифры в одном месте
Итог: Потребление на С++ получилось почти таким же как и на С. Но при этом инкапсуляция, наследование и полиморфизм это сила. Я готов за это переплачивать некоторым увеличением потребления. Возможно я просто не умею красиво писать на С, но зачем, если я могу красиво писать на С++?
Послесловие
Изначально я хотел написать одну статью в конце работы над проектом. Но поскольку заметки по ходу работы накапливаются с большой скоростью, то статья грозится быть очень большой. Так что я решил разбить ее на несколько частей. В этой части я рассказал о подготовительных этапах: понимание чего же я вообще хочу, выбор платформы, реализация каркаса приложения.
В следующей части я планирую перейти уже к реализации основной функциональности — работу с GPS. Я уже столкнулся с парочкой интересных граблей, про которые хотел бы рассказать.
Я более 10 лет серьезно не программировал под микроконтроллеры. Оказалось, что я несколько избалован обилием ресурсов больших компов и мне тесновато в реалиях ATMega32. Поэтому пришлось продумать разные бекапные варианты, как то урезание функционала библиотек или редизайн приложения во имя эффективного использования памяти. Так же я не исключаю переход на более мощные контроллеры — ATMega64 или что нибудь из линейки STM32.
По стилистике статья получается что-то вроде журнала постройки. И я буду рад конструктивным комментариям — еще не поздно что либо поменять. Желающие могут присоединиться к моему проекту на гитхабе.