И вот, опять понадобилось повозиться с объективом, т.к. ребята, пытающиеся в лабвью запустить EF200 по моей шпаргалке, долго бились, в результате сказали, что, возможно, фотоаппарат вообще генерирует каждый раз псевдослучайную последовательность и шифрует код.
В итоге морда была подключена к тушке (надо будет фотоаппарат притащить и сфотографировать все это чудо) шлейфом (Гриша снял байонет с объектива и прицепил туда кусок стеклотекстолита, сам байонет прицепил к фотоаппарату, а объектив подпаял к байонету шлейфом), к ней я подпаял 4 проводка на SPI, подключил свой китайский клон Saleae Logick и стал анализировать.
И вот с анализированием все было плохо. Для начала, я очень долго мучился, пытаясь подобрать оптимальные настройки логанализатора, чтобы можно было хитрый протокол (естественно, каноновцы выдумали свой хитрожопый SPI-протокол, чтобы другим сложней было) сдампить. Вот как выглядит передача/прием одного байта:

Вот этот маленький выброс на последнем бите и заставил меня целых полдня потратить впустую! Дело в том, что поначалу, сняв пробную порцию данных и увидев, что период синхроимпульсов составляет 12.75мкс (т.е. частота SPI около 78.431кГц), я решил сэкономить на объемах захваченной информации и снизить частоту сэмплирования до 250кГц. В итоге последний синхроимпульс был потерян и я впустую пытался придумать, какие же настройки задать логанализатору, чтобы сдампить результат. Потом поднял частоту до 8МГц и все встало на свои места.
Правда, пришлось схитрить. Вот такая вот дурацкая затея с поджатием к нулю CLK на время бездействия и поджатия его к единице перед началом "общения" заставила выбрать вот такие настройки:

Т.е. 9-битный режим с data valid на нарастающем фронте синхроимпульса.
Понятно, что в таком виде данные никак не проанализировать. Поэтому был написан парсер дампов:
#include <stdio.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char **argv){
char *inm = argv[1], *onm = argv[2];
FILE *fin = fopen(inm, "r");
char *buf = malloc(256);
printf("# time MOSI MISO\n");
double told = 0.;
do{
size_t len = 256;
if(getline(&buf, &len, fin) < 1) break;
char *brace;
if(!(brace = strchr(buf, '('))) continue;
double t; int mosi, miso;
t = atof(buf);
++brace;
mosi = strtol(brace, NULL, 16);
if(!(brace = strchr(brace, '('))) continue;
miso = strtol(brace+1, NULL, 16);
if(t - told > 0.001) printf("\n"); // next data portion
printf("%7.5f %.2x %.2x\n", t, mosi >> 1, miso >> 1);
told = t;
}while(1);
fclose(fin);
}
Он считывает дамп-файл логанализатора, где каждая строка имеет вид
0.00015375,0,'1' (0x001),'17' (0x011)
затем выдирает оттуда времéнную метку и данные SPI (в скобках), сдвигая данные на один бит вправо, и выводит на стандартный вывод, чтобы можно было сохранить их в какой-то другой файл.
Я экспортировал все в один и тот же файл (canon.txt), поэтому для упрощения преобразования дампа набросал скриптик:
#!/bin/bash
./proc_exp canon.txt > $1.dat
cp canon.txt $1.txt
Так как очень много места в каждой порции данных занимают команды опроса объектива, чтобы наглядней выявить особенности каждого файла, я строил гистограммы частот появления команд:
#!/bin/bash
cat $* | awk '{print $2 " " $3}' | sort | uniq -c | sort -n
Казалось бы, все готово и все рады, но не тут-то было! Во-первых, обнаруженные команды совершенно не соответствовали командам из моего списка (большинство из них попадались на "неизведанные"). Во-вторых, из-за очень частого опроса объектива, когда ответ один и тот же, анализировать данные довольно-таки сложно. Видимо, надо еще один парсер написать, который будет выбрасывать повторяющиеся одинаковые блоки.
Пока что результат таков:
- блоки опроса различаются для режимов "ручной фокус" и "автофокус";
- часть команд (0a, 90, a0, b0, b2, c0, e0, e4, e8, ea, f0, f8, fa, fc, fe) появляется наиболее часто и явно предназначена для опроса состояния объектива;
- еще часть команд (01, 05, 06, 07, 0c, 0f, 2d, 2e, 50, 80, 99) встречается значительно реже, т.е. явно имеет какой-то особый смысл (управление фокусировкой, опрос при инициализации, опрос значения фокуса и т.п.); интересно, что команды 0xC2, которую я использовал раньше для того, чтобы узнать значение отсчета фокуса, в данном случае нигде нет!
- команды 0a, 90, a0, b0, b2, e4 наиболее часто встречаются в процедуре опроса объектива сразу после включения, т.е. можно сказать, что они отвечают за состояние объектива;
- а вот команды 01, 07, 0c, 0e, 0f, 2f, 50, 80, 99, c0 при включении встречаются значительно реже — явно они нужны для инициализации и/или опроса редко изменяющихся данных;
- странно, что при ручной фокусировке дампы вообще ничем не отличались! По крайней мере, ответы были одними и теми же, в обоих случаях команды 01, 0a, 2f, 50, 80, 90, 99 использовались лишь единожды, а основную массу набирали команды опроса состояния;
- а вот анализ дампа автофокусировки показал забавную вещь: здесь используется уже найденная ранее
"методом тыка"(нет, физикам нужно говорить "методом Монте-Карло"!) команда 0xc0 (194), которая позволяет узнать угловую координату лимба фокуса (а не значение в метрах); - команда 0x0a почему-то имеет то 2 байта ответа (0xaa, 0x00 — наиболее часто), то всего один (в первом пакете каждого опроса подряд идут команды 0x80, 0x0a и 0x99, в ответ на которые приходит 0x81, 0x87, 0x00);
- команде 0xe4 всегда дается ответ 0x9c, 0x6a, при работе с другим объективом ответ был другим — явно сигнатура какая-то;
- в основном ответ команд — либо их эхо, либо 1-2 байта данных, но есть рекордсмены: 0x01 имеет 6 байт ответа (используется при инициализации, возможно, это запрос модели объектива); 0x90 имеет три байта ответа и данные меняются при нажатиях разных кнопок объектива; команда 0xb0 имеет то 3, то 4 байта ответа (0x16, 0x16, 0x50[, 0x00]); 0xb2 имеет 4 байта ответа, меняющихся при автофокусе и постоянных при ручном изменении фокусировки; команда опроса положения лимба (используется при автофокусировке) имеет на самом деле 3 байта в ответе, хотя последний байт всегда нулевой; у команды 0xe8 7 байт ответа (кроме первых двух байт остальные — нули), а у 0xea — 6 байт (тоже только 2 реальных данных), обе используются только при автофокусе и ответ обеим меняется "синхронно" (но по-разному);
- еще при автофокусировке встречается последовательность команд 0xf8, 0xfc, 0xfa, 0xfe, 0x00, которым приходит разный ответ (судя по тому, что в ответ на 0xfe тоже приходит 1 байт, нулевой в конце добавлен "для пущей безопасности");
- и т.д., и т.п.
Возможно, подробный анализ что-нибудь да покажет, но лучше уж сразу запрограммировать STM8 или STM32 и попытаться "пообщаться" с объективом с микроконтроллера.
Если кому-то интересно поразмыслить над логами, я запушил их в репозиторий.
Journal information