середу, 25 листопада 2009 р.

Макет з клавіатурою

Хоч я й зайнятий останнім часом “по саме нікуди”, проект потрохи розвивається. Тепер макет постійно живиться від акумулятора через лінійний перетворювач напруги. До слова, як спробував побудувати імпульсний (по-ідеї, більш економний), то холостий хід у нього виходив на відмінно, але при навантаженні задихався. (Так хотілося це побачити на власні очі, що притарабанив з роботи осцилоскоп)

По-друге, додав до макету дві кнопки керування. Одна дозволяє перемикати режими, інша підналаштовувати покази годинника чи навіть його запускати/зупиняти. Варто зізнатися, що з спершу нічого не вийшло. Перебудувавши код, щоб на дисплеї друкувалися події, зіткнувся із тим, що час від часу малюється якесь сміття (Welcome to the real concurrent world!). Виявилося, що sdcc генерував non-reentrant код деяких функцій. Отже, довелося його наставити на шлях істинний з --stack-auto, та відмовившись від деяких благ цивілізації. Як би там не було, тепер усе працює, як … годинник ;-)

Чим більше працюю з sdcc, тим більшає спокуса погратися із AVR. Є ж для них нормальний компілятор GCC. Знайду дармовий внутрішньо-схемний програматор — так відразу ж спробую.

Нарешті, про наболіле. Ми знову шукаємо розробника на С++ для Linux. І знову я спантеличений. Надсилають вражаючі резюме, хоч відразу бери й наймай. А як приходять на співбесіду, то з’ясовується, що біти в числі рахувати не вміють; номінальні “знавці STL” не знають, що робить функція remove_if. Куди котиться світ?

неділю, 15 листопада 2009 р.

Майже готовий годинник

Причепив брехунця:

суботу, 14 листопада 2009 р.

Канал через UDP

Півтора року тому для підтримки GPRS знадобилося мені реалізувати специфічний протокол SIA-over-IP. Це до возу приліпили крила й реактивний двигун, так що він тепер літає поруч із лайнерами. Тобто, сто років вже працюють у текстовому форматі SIA різні прилади, так ці самі повідомлення вже можна пропихати й через інтернет.

В документі було написано, що протокол орієнтований на з’єднання TCP, але при необхідності можна ті самі пакети слати у датаграмах UDP. Сказано — зроблено, просто для полегшення власної сверблячки зробив я обидва варіанти, хоч і ніхто не просив.

І от тижнів зо два тому телефонує інженер, який робив цей протокол для приладів, і питає, мовляв, як там у нас на сервері із UDP? Кажу, що все на місці, бери й спробуй… Працювало все нормально, але тільки до тих пір, як спробували під’єднатися до віртуального інтерфейсу. Виявилося, що пакети на сервер таки приходять, той відповідає, але вже через справжній інтерфейс. Тобто, прилад присилає на віртуальну адресу 192.168.38.14, а сервер відповідає із 192.168.38.13. Тому їх не хоче випускати у світ файрвол. Та й сам прилад, мабуть, проігнорував би.

Порившись півдня у інтернетрях, кажу архітекторові, що вся біда у прив’язці приймаючого сокета до IPADDR_ANY, давайте, мовляв, я їх заведу на кожен інтерфейс по одному, буде швидко й найдійно. — Та де там, шукай далі, як правильно обдурювати адресата, переписуючи на конверт зворотню адресу з оригіналу…

Таки надибав! Всі про це знають, але ніхто не каже вголос. Підглянув (thanks OSS!), і за день зробив. Довелося, правда, замінити recvfrom/sendto на recvmsg/sendmsg, у самому повідомленні порпатися у допоміжній інформації (struct in_pktinfo), та ще й самому її підкидати. Але так до кінця й не впевнений, що воно того було варте.

середу, 11 листопада 2009 р.

Перший працюючий годинник

Прислужилося ще одне кругле число. 4 194 304 — це теж степінь двійки, і його можна представити як добуток 4×16×256×256. А на практиці це означає, що взявши кварцовий резонатор з такою власною частотою, мікроконтролер PIC буде виконувати 16×256×256 інструкцій за одну секунду. Налаштовуємо прескалер таймера на поділ частоти на 16, матимемо переповнення восьмирозрядного TMR0 256 разів за секунду. А добитися щосекундного переповнення ще якогось байта — це задача для першокурсника.

Словом, дуже вдалий набір фактів для побудови точного годинника: маємо генератор 1 Гц для відліку секунд, інший з частотою 256 Гц для динамічної індикації на дисплеї. Щось підказує, що це ще далеко не всі можливості…

Отже, вже є перша працююча реалізація годинника. Асемблер я не знаю і вчити не хочу, тому програма написана на C. І то треба було півдесятка років відпрацювати з C++, щоб нарешті оцінити міць і красу С--! Словом, за звичкою прогама виходить модульною з простими інтерфейсами, з прихованою від недружнього світу реалізацією тощо. Але про це вже іншим разом.

Раз візуальний ефект є, беремо далі курс на звуковий супровід. Треба буде десь придбати п’єзо-сирену, і причепити її до схеми.

суботу, 7 листопада 2009 р.

Друкована плата для дисплею

Щоб не паяти павутину із проводів, вирішив для дисплею виготовити друковану плату. Крім того дуже хотілося розібратися, як вони проектуються. Та й паяю я препаршиво.

Отже, накидав я схему майбутнього стартового годинника у gschem. Оскільки у стандартній бібліотеці моїх “вісімок” не було, довелося їх намалювати самостійно. Десь у тенетах наткнувся на підказку, що можна деякі цифри поперевертати, щоб отримати двокрапковий роздільник годин, хвилин та секунд.

Потім перегнав схему у програму pcb, заздалегідь по опису деталі (datasheet) описавши слід індикатора. Дисплей — це хороший початок, бо зовсім не треба думати над розміщенням деталей, отже, на одну проблему менше. А от із мережею доріжок довелося покоптитися. Можливо, й можна було б провести всі з’єднання на одній стороні, впаявши кілька додаткових перемичок самостійно, але для мене це не очевидно.

А далі був експорт схеми плати у файли Ґербера, замовлення у Херсоні і два тижні очікування. До слова, виробник мав упоратися за тиждень, тому я незадоволений результатом. Крім того, місцями на платі наскрізні отвори зміщені десь майже на чверть-доріжки (0,25 мм). Прототип все-таки.

Несподівано для себе відкрив, що впаювати в таку плату деталі дуже легко. Звісно, довелося помучитися із першим десятком голок, а на решту пішло хвилин зо десять.

Тепер можна неквапно на макетній платі готувати мікроконтролер.

середу, 4 листопада 2009 р.

Автоматичне тестування у bash

Рік тому з’явилася була ідея створювати для автоматичної перевірки всієї системи невеликі скрипти оболонки Unix. Відверто, з нашим лідером QA ми навіть спромоглися втілити її. Після нескладної підготовки середовища, запускався написаний на bash скрипт, який по SSH керував приладом, заставляючи його відіслати якісь повідомлення. Разом із тим виконував якісь перевірки на сервері. Така нехитра схема нам дозволила автоматизувати рутинні перевірки, і зрештою довести до систему до пуття.

Тепер знову постала необхідність розкопувати старі кулемети. Розробляючи нову версію сервера з нуля, ми зіткнулися із дикою бідою. Дуже важко відслідкувати всі внесені до схеми бази даних зміни і вчасно поновлювати код демонів (хто робив, той зрозуміє). Тому тепер я намагаюся пліч-о-пліч із ручними перевірками “занотовувати” свої дії у скрипти bash. Таким чином легко потім повторювати перевірки щодня. Можливо, в майбутньому автоматизуємо нічні збірки із прогонкою всіх тестів.

Такі тести мали б називатися регресійними модульними, але вони не те саме, що модульні тести вихідного коду. Бінарний модуль — це чорна скринька, але перевіряються внутрішності системи (записи в базі даних, зміни у файловій системі тощо).

Запускаються ці диво-скрипти на перевірюваному розгорнутому сервері, але покладаючись на структуру вихідного коду. Типові приклади дій у скриптах такі:

  • Визначаються якісь вихідні значення, параметри:

    
    serial=1234567890
    msg_idx=1234
    cam_cnt=4
    

  • Готується оточення, заводяться значення в базу даних, перезапускаються потрібні демони тощо:

    
    echo "Creating database ipmp"
    mysql << END || die "Failed to recreate the database ipmp"
      DROP DATABASE IF EXISTS ipmp;
      `cat $vdns_root/documents/web/ipmp/Ipmp2.sql`
    END
    
    echo "Preparing environment"
    rm -rf /ha_shared/vdns/eventsPictures
    mysql ipmp << END || die "Failed to prepare environment"
      INSERT INTO unit
      SET utc_id = 1,
          unt_serial = '$serial',
          unt_remote_access = 'allow';
    END
    
    echo "Restarting pnet_server"
    killall -KILL pnet_server
    ($vdns_root/src/apps/pnet_server/pnet_server &)|| \
        die "Couldn't launch pnet_server"
    
    echo "Restarting pnet_notify"
    killall -KILL pnet_notify
    ($vdns_root/src/apps/pnet_notify/pnet_notify &) || \
        die "Couldn't launch pnet_notify"
    sleep 2
    

  • Від імені приладу відсилається запит:

    
    # Sending error request
    resp=`curl -s -d asdf "http://localhost:8080/scripts/notify.php"`
    [[ $? -eq 0 ]] || die "Failed to get error response"
    [[ "$resp" =~ "<index>-1</index>" ]] || die "Incorrect error response"
    
    # Sending request
    ./send1.sh -a localhost -s $serial -i $msg_idx -c $cam_cnt
    [[ $? -eq 0 ]] || die "Failed to send the event"
    

  • Нарешті, виконуються перевірки ефекту запиту:

    
    echo "Checking events"
    res=`mysql -s ipmp <<END
      SELECT etv_id,
             evt_description,
             evt_message_index,
             evt_original_device_name
      FROM event;
    END` || die "Failed to check events"
    
    diff -uw <(echo "$res") <(cat <<END
    31      Fire    $msg_idx        Control Panel
    END)
    
    [[ $? -eq 0 ]] || die "Event don't match"
    

Для порівняння табличних даних в нагоді дуже стає команда diff: виходить компактно, інформативно. Краса!