LE Blog

Инженер с поэтической душой

21.07.2010 firtree_right Управление LEGO NXT Mindstorms с помощью телефона HTC Desire на Android

summer in the city

Введение

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

Дистанционное управление

Итак, у меня уже давно есть конструктор LEGO Mindstorms, который довольно бодро взаимодействует через bluetooth с компьютером или с таким же конструктором.

А в апреле я обновил телефон на HTC Desire под управлением операционной системы Андроид, которая уже давно привлекла моё внимание, но всё руки не доходили.

В итоге появились повод, возможность и желание «пощупать» Андроид. И вот, что из этого получилось:

Секреты?

Для тех, кто соберётся заниматься чем-то подобным, могу поделиться небольшим секретом. Стандартный метод получения BluetoothSocket, рекомендованный командой Гугла, не работает, а нужен небольшой хак:

/* Не работает:
 * socket = device.createRfcommSocketToServiceRecord(MY_UUID)
 */

Method m = device.getClass().getMethod("createRfcommSocket",
            new Class[] { int.class });
socket = (BluetoothSocket)m.invoke(device, Integer.valueOf(1));

Вот и всё, что я могу рассказать :) Если я ещё буду писать про Андроид, то придётся сделать подсветку кода для него.

Материалы для самостоятельного изучения

Руководство для разработчиков под Андроид на тему bluetooth

08.07.2010 firtree_right Ассорти

В такую жару клёво делать что-нибудь новое и интересное. Пробовать что-нибудь в первый раз и проектировать с нуля. А писать документацию или дорабатывать наследие прошлого в такую жару лениво. Я нашёл программиста на си и очень им доволен. Он аккуратен, оперативен и такой же аут, как и я. Это будет уже третье поколение съёмочной программы. То есть я писал эту штуку два раза с чистого листа и мне всё мало.

Посмотрели сегодня «Девушка с татуировкой дракона». Я люблю скандинавское кино. У него всегда прекрасный, ни на что не похожий ритм. Вроде бы ничего не происходит, но невозможно глаз оторвать. Однако, я бы не смог посмотреть два скандинавских фильма с перерывом меньше чем в неделю. Вот такая любовь.

Нет более приятного собеседника за обедом, чем Маша.

А ещё я могу зайти на свой веб-сервер с телефона, отредактировать так конфиги, перезагрузить апач и обновить ПО. Не то чтобы я этим пользовался часто, но сама возможность завораживает и внушает чувство всемогущества.

А как у вас дела?

23.06.2010 firtree_right Пеар

Вот и вышел в свет ещё один портфолио-блог как у меня с Ирой. :) Сделал я его для наших с Ирой друзей, а именно Маши Красновой-Шабаевой. После того, как Маша и Тимур нарисовали дизайн, я долго тянул кота за хвост, чтобы не верстать, а потом впервые в своей практике применил метод: «Купи вёрстку у Мистера Вудмана и спи спокойно».

Заодно проверим на вшивость отечественных поставщиков хостинга, о которых недавно упоминал.

19.06.2010 firtree_right Деплой

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

В связи с чем попробовал отечественный продукт: хостинг locum.ru. Не знаю, правда, как он под нагрузкой, но первые впечатления от настройки приятные. С тех пор, как я пользуюсь capistrano, залить что-то на хостинг — легко и быстро. Самое трудное, обычно — это первый деплой. Тут как раз всё прошло быстро и не меняя привычек. Недостаток инструкций, конечно, имеется, но не страшный.

Я бы даже написал им инструкцию, как залить свой проект на Ruby on Rails на их хостинг, но я всё время стесняюсь, что не умею пользоваться ssh-agent. Может кто-то научит меня пользоваться ssh-agent, чтобы мне не добавлять дополнительный deploy-ключ в список пользователей репозитория?

18.06.2010 firtree_right Машинка!

Вот, чем я занимаюсь после работы:

17.06.2010 firtree_right Ещё два сценария работы с git: git stash и git bisect

library

Введение

Моя любимая система контроля версий имеет огромное количество инструментов. Как-то раз я участвовал в опросе, после которого выяснилось, что даже из самых популярных инструментов я использую от силы 10%.

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

Внезапные просьбы: git stash

Бывает так, что пока я работаю над нововведениями в программу, текущая стабильная её версия активно используется. При активном использовании, конечно же, могут возникнуть ошибки или пожелания что-то изменить. Бывает так, что при этом я нахожусь в середине тестирования какого-то новшества, и всё настолько сыро, что я даже не могу сделать коммит.

Итак, я нахожусь в середине правок на ветке _extremely_experimental_, а мне необходимо внести правки в ветку master. Вот, как это делается:

git stash save
git checkout master

После первой команды всё наши изменения, которые нельзя было закоммитить, сохранены и текущая ветка приведена в состояние до правок. После этого мы можем сменить ветку и внести наши правки. После того, как ошибки исправлены, нововведения сделаны и тесты проходят, мы можем вернуться обратно к нашим правкам.

Но скорее всего все или некоторые из сделанных изменений понадобятся нам в нашей экспериментальной ветке. После перехода на неё:

git checkout extremely_experimental

Если нам нужны все изменения, то:

git merge master

Если только некоторые, то:

git cherry-pick ...

После этого вернём наши правки:

git stash pop

Если возникли конфликты, то правим их и делаем:

git stash drop
git reset --mixed

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

Конечно же таких незавершённых правок может быть несколько, но это я оставлю на самостоятельное изучение пытливому читателю.

Неизвестно, когда сломалось: git bisect

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

Хорошая новость в том, что это и не обязательно. Нужно просто начать процесс:

git bisect start
git bisect bad

Так мы обозначили, что текущий коммит содержит ошибку. После этого, либо мы знаем, как называется коммит, в котором ошибки ещё не было, или находим его.

git bisect good v2.3.1

или

git checkout ...
git bisect good

После этого за нас всё будет делать git. Он будет перемещать нас по истории, а мы будем проверять, есть эта ошибка или нет, и сообщать об этом:

git bisect good

или

git bisect bad

В конце концов нам сообщат, какой именно коммит всё поломал. Название инструмента подсказывает нам, что на тестирование нам всегда предоставляется коммит, который находится посередине между плохим и хорошим. Таким образом, мы просматриваем не все _N_ коммитов в истории ошибки, а всего лишь log2N.

После того, как мы выяснили, в чём причина, убрать следы, которые оставил после себя git bisect можно так:

git bisect reset

А какими инструментами git пользуетесь вы?

Материалы для самостоятельного изучения

  1. Документация по git
  2. git stash
  3. git bisect

12.06.2010 firtree_right Оказалось, не казалось

Пока вы спали (и я тоже спал) мне явился правильный ответ: это float в формате little endian (младшим байтом вперёд). Вот код для андроида.

int tmp = Float.floatToRawIntBits(new Float(number));
byte[] msg = {(byte)tmp, (byte)(tmp >> 8), (byte)(tmp >> 16), (byte)(tmp >> 24)};

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

11.06.2010 firtree_right Профессиональное

Я тут вечерами не могу лечь спать, потому что управляю своим Lego Mindstorms роботом с телефона на Android (моего любимого ненаглядного HTC Desire то бишь) по bluetooth. Я уже написал базовое взаимодействие, и бодро передаю сообщения. Возник лишь один нюанс с передачей целых чисел. Вместо того чтобы совать их в трубу младшим байтом вперёд, как об этом говорят все интернеты, у меня они выглядят не так.

Это был целый детектив. Я слал ему little endian, но он отказывался. Сначала совсем. Потом везде видел нули Тогда я начал его пытать, и заставлял его посылать сообщения из целых чисел.

Если записать это в двоичной форме, то примерно понятно, что он имеет в виду. Но возможно есть матчасть, которую можно почитать, чтобы лучше это понять. Что это за представление, как его просто изобразить, скажем, на Java? Итак, имеем четыре байта:

... симметрично
-4 => 0x00 0x00 0x80 0xC0
-3 => 0x00 0x00 0x40 0xC0
-2 => 0x00 0x00 0x00 0xC0
-1 => 0x00 0x00 0x80 0xBF
0 => 0x00 0x00 0x00 0x00
1 => 0x00 0x00 0x80 0x3F
2 => 0x00 0x00 0x00 0x40
3 => 0x00 0x00 0x40 0x40
4 => 0x00 0x00 0x80 0x40
5 => 0x00 0x00 0xA0 0x40
6 => 0x00 0x00 0xC0 0x40
7 => 0x00 0x00 0xE0 0x40
8 => 0x00 0x00 0x00 0x41
9 => 0x00 0x00 0x10 0x41
10 => 0x00 0x00 0x20 0x41
...
15 => 0x00 0x00 0x70 0x41
16 => 0x00 0x00 0x80 0x41
17 => 0x00 0x00 0x88 0x41
...
555 => 0x00 0xC0 0x0A 0x44
...
2147483648 => 0x00 0x00 0x00 0x4F

По спецификации и из результата видно, что он старательно делает вид, что полностью использует все четыре байта, но тогда не было бы чисел, которые он бы не смог интерпретировать. В районе максимумов заметно, что очень большие числа он не различает между собой, если они отличаются на несколько единиц. Это какая-то экспоненциальная форма? Что это?

09.06.2010 firtree_right Солянка

Сегодня как раз слушал всякие подкасты, подтверждающие мою правоту. Люблю подтверждать свою правоту, что поделать :) Вкратце, чтобы никого никуда не отсылать, там говорилось про то, что ежели ты динамично растущий программист, то полезно фиксировать свои открытия об окружающих. Типа вести блог или что-то подобное. Я реально им пользуюсь столько же, сколько всякой прочей нужной документацией.

Решил со следующего раза возобновить ссылки отсюда в программерский блог по мере появления там статей. К тому же теперь там есть картинки. Для неискушенного читателя.

А ещё есть такие фишки, про которые раньше слышал, но не приходилось сталкиваться. Типа, да, прикольно придумано, но мне не надо. А потом эта фишка в режиме экстренного изучения спасает кучу рабочих часов. Выгода налицо. Про такое, кстати, обычно в блог и пишу. Во-первых, чтобы запомнить, а во вторых — вот это прекрасное состояние, когда ты что-то новое освоил и в полной мере почувствовал его продуктивность, и подмывает всем рассказать, конечно же.

Андроид, кстати, и в использовании, и в разработке оказался вполне приятным.

Такие дела.

01.06.2010 firtree_right Работа над ошибками

Mistakes

Введение

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

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

git hooks

Недостатков скрипта для удаления пробелов в концах строк нашёл два:

  1. Скрипт без нужды дёргает ни в чём не повинные файлы, потому что \s соответствует и символу конца строки, который там всегда есть.
  2. Скрипт не содержит решения для выбора всех текстовых файлов проекта.

Вот хороший скрипт:

#!/usr/bin/env ruby
`git grep -I --name-only -e ""`.split("\n").each do |p|
  lines = File.readlines(p).map(&:chomp)
  if lines.inject(false) { |memo, l| l.gsub!(/\s+$/, "") || memo }
    File.open(p, "w") do |f|
      f.puts lines.join("\n")
    end
    puts "Removed trailing spaced from '#{p}'"
    system "git add #{p}"
  end
end

Так же по совету Дмитрия в комментариях добавил скрипт для проверки счастливого коммита.

Работа с версией в (ai)rake

Совершенно очевидная ошибка в примере про работу с версиями air-приложения в rake. Когда увеличивается более старшая часть версии, то все младшие должны обнуляться:

namespace :version do

  [:major, :minor, :patch].each_with_index do |subv, index|
    desc "Bump #{subv} in version"
    task :"bump_#{subv}" do

      unless `git status` =~ /nothing to commit/
        raise "There are uncommitted changes. Failed to proceed."
      end

      appxml = YAML.load_file('airake.yml')["appxml_path"]
      str = File.read(appxml)

      msg = nil
      new_version = nil

      if str.gsub! /<version>(.*)<\/version>/ do |matched|
          old_version = $1
          major, minor, patch = old_version.split(".").map(&:to_i)
          eval("#{subv} += 1")
          new_version = [major, minor, patch].fill(0, index+1).join(".")
          msg = "Version bump #{old_version} => #{new_version}"
          puts msg
          "<version>#{new_version}</version>"
        end.nil?
        raise "Cannot detect current version.\nMake sure appxml file contains <version>X.X.X</version> tag."
      else
        File.open(appxml, "w") do |f|
          f.write str
        end

        puts `git commit -am "#{msg}"`
        puts `git tag v#{new_version}`
      end
    end
  end
end

Теперь _rake version:bump_minor_ делает из 0.1.6 не 0.2.6, а 0.2.0, как и должно быть.

Мимоходом

Тем временем я сменил тарифный план у своего провайдера на (ve). И незаметно перенёс сайт. Посмотрим, как работает на собственном опыте. Работа по ssh, как была, так и осталась основным способом администрирования, а необходимость лазить в plesk пропала, потому что его теперь нет :)