Июн 15

UART размер экрана

Для общения через UART с железками (avr, stm32 и прочими) в основном использую GNU screen:

$ screen /dev/tty.ubserial 9600

А вот что-то дернуло, раскрасить вывод микроконтроллера и раскрасил (не мудрено, печатаем что-то вроде \033[31m и вперед, ну только цвета меняем). А потом поехало: захотелось печатать в разных местах экрана (\033[y;xH), а вот как напечатать в центре? Надо же знать размер экрана, а он у меня (да и у всех) каждый раз разный.
Долго возился, выяснил, что screen отдавать размер окна (\033[18t) не умеет. Зато DCS передает напрямую терминалу из которого запущен: вот и нашелся грязный хак: оборачиваем запрос размера в ESC-P последовательность, и вот уже знаем размер экрана.
Печатаем хитрую строку:

\033P\033[18t033\

и получаем ответ:

\[8;31;163t

31 строка, 163 колонки, а 8 — это номер CSI-репорта. Он всегда такой.

вот тут большой список похоже что вообще всех ESC-последовательностей которые терминалы поддерживают: ttssh2.osdn.jp

P.S.
Ну а бонусом — таким же способом можно поставить заголовок окна который screen ставить умеет только через жопу.

\033P\033]0;New Window Title\a\033\\
Июл 12

Немного указательных трюков AVR

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

1
2
3
4
typedef struct {
    volatile uint8_t *port;
    uint8_t pin;
} out_t;

а дальше создаем массив этих структур:

1
2
3
4
out_t outs = {
 { &PORTA, PA1},
 { &PORTB, PB4},
};

ну и так далее. Получается удобно проходить в цикле.

1
2
3
4
uint8_t i;
for(i=0;i<sizeof(outs)/sizeof(out_t);i++){
 *outs[i].port |= _BV(outs[i].pin);
}

ну и как бонус — инициализация. в AVR регистр направления DDRx всегда на 1 байт младше, чем соответствующий PORTx, получается небольшой трюк:

1
2
3
4
uint8_t i;
for(i=0;i<sizeof(outs)/sizeof(out_t);i++){
 *(outs[i].port-1) |= _BV(outs[i].pin);
}
  • инициализация на выход всего массива. Это много медленнее, чем одной операцией проставить все нужные пины, но если время не критично — поддерживать такой код порядком проще: добавили запись в массив — и готово.
    Да, чтобы не тратить память, можно все это хранить в PROGMEM и доставать по необходимости.

ну и еще напоследок, удобный макрос от разработчиков ядра Linux для ловли багов:

1
2
3
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
// и его применение
BUILD_BUG_ON(sizeof(phs_entry_t) != sizeof(uint32_t));

если структура phs_entry_t размером не равна uint32_t (32 бита) — код не соберется

Фев 06

ARM Semihosting

В ARM-контроллерах есть полезнейшая вещица, Semihosting, позволяет переадресовывать I/O операции к хосту
Почему-то при отладке, в основном используют только printf() для вывода отладочных сообщений, хотя возможности порядком шире: можно переадресовать любую(!) I/O операцию. Например запись файла.
Для быстрого примера, создадим проект в Eclipse, конфигуратор проекта спросит про системные вызовы:
Use system calls — вот тут надо выбрать Semihosting (POSIX system calls via host) — это полное перенаправление всех POSIX вызовов к хосту.
Trace output — не важно, пусть будет Semihosting STDOUT, отладочные сообщения будут падать в STDOUT сервера
Ну и чтобы побыстрее все проверить — content — стандартный шаблон Blinky — мигалка светодиодом.

А дальше все просто — добавляем в main обычный код для вывода в файл:

 FILE* f = fopen("./test.txt", "w");
  if(f){
      fprintf(f, "Hello from ARM...\n");
      fclose(f);
  }

Думаю, и так понятно, что мы открываем файл test.txt для записи в текущем (относительно semihosting сервера) файл, и если открылся — записываем в него строку.
собираем, а вот запускать для наглядности будем из консоли:
у меня под рукой STM32VL-Discovery, поэтому конфиг запуска для неё

$ openocd -f board/stm32vldiscovery.cfg

Далее, запускаем openocd который и будет semihosting server
цепляемся к нему отладчиком

$ arm-none-eabi-gdb project.elf

и выполняем следующие команды в отладчике

target remote :3333  # подключаемся а GDB-серверу OpenOCD
monitor arm semihosting enable # включаем semihosting
monitor init # инициализируем кристал
monitor reset init # сбрасываем кристал
load  # загружаем в кристал файл указанный в параметре запука gdb
continue # запускаем запущенную программу

прошивка blinky содержит в себе примеры отладочных сообщений, так что можно вполне их посмотреть в консоли OpenOCD, а после выполнения добавленного участка кода — можно смотреть на файл test.txt:

$ cat test.txt
Hello from ARM...

Да, самое главное — прошивка с включенным Semihosting не сможет работать в standalone режиме (т.е. без подключенного отладчика), застопорится на первом же обращении к хосту. Поэтому в release версии нужно отключать. Для этого в элипс достаточно удалить define в соответствующей конфигурации

Дек 13

responseText ошибки при AJAX-запросе

За формирование страницы ошибки отвечает функция technical_500_response из django.views.debug,
программисты джанги пошли странным путем, жестко задав (без возможности настройки): если запрос AJAX — ответ будет текстом, в остальных случаях HTML.
Все бы ничего, но raise Http404(), например, плевать на этот механизм хотела, и все равно выбрасывает HTML, если выводить ошибку в консоль — сущий ад.
Изменить поведение можно например так:
Добавить Middleware которая, в случае ошибки уберет из request соответствующий заголовок,
дальше джанга отработает по своему алгоритму и вернет красивый HTML.
Криво конечно, т.к. пропадает возможность узнать был Ajax или не было, но не нужно патчить Django

1
2
3
4
class DisableAjaxException(object):
    @staticmethod
    def process_exception(req, exception):
        req.META['HTTP_X_REQUESTED_WITH'] = None

Ну и остается напомнить, порядок Middleware в settings.py важен

Июн 07

MySQL и foreign key constraint fails

Cannot add or update a child row: a foreign key constraint fails
Такое случается, если включена проверка InnoDB foreign key, но ссылается ключ на таблицу не InnoDB (например MyISAM)
лечится:

  • конвертированием всех таблиц в InnoDB
  • конвертирование всех таблиц в MyISAM
  • или отключением проверки:
DATABASES = {
'default': {
    ...         
    'OPTIONS': {
         "init_command": "SET foreign_key_checks = 0;",
    },
 }
}

Статейка про InnoDB

Июн 03

Откат iOS8 beta

После того, как все поигрались, потеряли сеть итд, хочется обратно нормальной стабильной работы.
Откатывать как обычно:

  1. Подключаем к компьютеру
  2. Вводим телефон в режим DFU: удерживаем Home+Power 10 секунд (экран отключится), отпускаем Power, и ждем еще 10 секунд, отпускаем Home
  3. iTunes найдет телефон в режиме восстановления и предложит поставить на него текущий релиз iOS (на сейчас это 7.1.1) — устанавливаем
  4. После завершения установки, будет предложено восстановить из резервной копии (вы ведь сделали её?)
  5. Ждем более стабильной беты
Апр 26

Плеер в iOS

Music player

 
 
//Тут лежит MPNowPlayingInfoCenter и прочие MP*    
#import <mediaplayer /MediaPlayer.h>
 
 
 
 NSString * path = [[NSBundle mainBundle]pathForResource:@"some_track" ofType:@"mp3"];
 NSURL *url = [NSURL fileURLWithPath:path];
//Создаем плеер
 
AVAudioPlayer * player;
player  = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
//Задаем громкость
player.volume = 1.0f;
//Загружаем файл в буффер 
[player prepareToPlay];	
//Разрешаем играть в фоне
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback  error:nil];
 
//Загружаем обложку
UIImage * artwork = [UIImage imageNamed:@"Artwork.jpg"];
//Создаем словарь с параметрами now playing
NSDictionary * info = @{MPMediaItemPropertyAlbumTitle: @"Astronimia",
                        MPMediaItemPropertyArtist: @"TONY IGY",
                        MPMediaItemPropertyArtwork: [[MPMediaItemArtwork alloc] initWithImage:artwork]
                        };
//Отправляем созданное в куда следует
[MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = info;
 
 
// Управление, со шторки, наушников, экрана блокировки
 
//Начинаем принимать события
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
//Заканчиваем принимать события
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
 
//Обработчик событий
-(void) remoteControlReceivedWithEvent:(UIEvent *)event {
    if(event.type == UIEventTypeRemoteControl){
        switch (event.subtype) {
            case UIEventSubtypeRemoteControlTogglePlayPause:
            case UIEventSubtypeRemoteControlPlay:
            case UIEventSubtypeRemoteControlPause:
                [self togglePlayPause];
                break;
            default:
                break;
        }
    }
}
</mediaplayer>