Star-force своими руками
Спиральная дорожка лазерных дисков очень похожа на грампластинку, только начинается не снаружи, а изнутри, наматываясь от центра к краю. Оптическая головка, удерживаемая в магнитном поле "звуковой катушки", движется на "салазках" поперек спиральной дорожки. Сама дорожка состоит из секторов с данными и каналов подкода. Номера секторов находятся как в заголовках самих секторов, так и в каналах подкода, "размазанных" вдоль спиральной дорожки. Для грубой наводки не требуемый сектор используются салазки и каналы подкода, а для точной— отклонение в магнитном поле и секторные заголовки.
Просто взять и измерять структуру спиральной дорожки нельзя, но можно сделать вот что: допустим, головка считывает сектор X, а следом за ним сектор Y. Если угол XOY, образованный центром (O) диска, секторами X и Y составляет порядка ~15 град, а сами сектора расположены на соседних витках спирали, то приводу достаточно всего лишь немного отклонить головку и через мгновение сектор Y сам падает в руки, как перезревшее яблоко — диск ведь вращается! Если же угол XOY составляет менее ~15 град, тогда за время перемещения головки, сектор Y уже "уплывет" и приводу придется ждать целый оборот лазерного диска, пока он не достигает оптической головки!
Рисунок 4 когда угол между секторами X и Y составляет ~15 град. при переходе на соседний виток, сектор Y сразу же "подлетает" к оптической головке (рисунок слева), при меньшем значении угла сектор Y успевает уплыть и головка вынуждена ждать целый сезон, тьфу, виток
Замеряя время чтения различных пар секторов, мы можем приблизительно определить их взаимное расположение на спиральной дорожке. У каждой партии диска для заданных секторов X и Y оно будет своим (ведь степень "закрутки" спирали неодинакова и варьируется от одного производителя к другому). Чтобы побороть упреждающее считывание (которым "страдают" многие приводы), защита должна читать сектора в порядке убывания их LBA-адресов.
Так же она должна измерять скорость вращения привода, чтобы во-первых, определить постоянство временных замеров (пляшут ли они как пьяные человечки или нет), а во-вторых скорректировать формулу для вычисления угла, ведь как легко показать, чем быстрее вращается диск, тем скорее "уплывает" сектор.
Исходный текст "измеряющей" программы приведен ниже:
//-[чтение сектора с диска]---------------------------------------------------
// ARG:
// CD указатель на строку с именем провода (например, "TEAC"),
// адрес на ASPI-шине (например, "1.1") или имя диска("\\.\G:");
// первые два варианта работают через ASPI, последний через SPTI;
//
// buf указатель на буфер SECROR_SIZE*2
//
// sector номер сектора в LBA-формате
//
// RETURN:
// 0 успешно
// -1 ошибка
read_from_cd(char *CD, unsigned char *buf, long sector)
{
int stat;
stat=cd_raw_sector_read(CD, buf, SECTOR_SIZE, sector, ONE_SECTOR, W_USER_DATA);
if (stat == SCSI_OK) return 0; return -1;
}
//-[чтение TSC-счетчика]------------------------------------------------------
unsigned int A()
{
__asm{
_emit 0xF ; RDTSC
_emit 0x31
}
}
#define argCD v[1]
// КОНФИГУРАЦИЯ
//----------------------------------------------------------------------------
// номер первой точки измерения (LBA-адрес)
// данная утилита измеряет топологию только по одной точке,
// что не есть хорошо, т.к. легко подобрать похожий диск
// для уверенности следует выбрать несколько точек:
// в начале, середине и конце диска
#define _CFG_BGN_SEC_ 17699
// кол-во секторов для измерения
// должно быть не меньше утроенного кол-ва секторов на виток в данной
// точке измерения (см. _CFG_BGN_SEC_ )
// число витков спирали N с поперечной плотностью D витков/мм
// от радиуса R1 до радиуса R2 определяется формулой: N = (R2- R1) * D
#define _CFG_LEN_SEC_ 0x669
// максимальный шаг приращения
// в принципе должен быть равен удвоенному кол-ву секторов
// на данном витке спирали, что увеличивает точность измерений
// но можно использовать и значение _CFG_LEN_SEC_
#define _CFG_LEN_DEL_ _CFG_LEN_SEC_
// начальный шаг приращения (должен быть по возможности мал)
#define _CFG_BGN_DEL_ 0x2
// приблизительное кол-во секторов на данном витке спирали
// (в данной версии программы это значение мало на что влияет)
#define _CFG_xWHELL_ 27
// конечный сектор для проверки
#define _END_SEC_ (_CFG_BGN_SEC_+_CFG_LEN_SEC_)
// конечный шаг
#define _END_DEL_ (_CFG_BGN_DEL_+_CFG_LEN_DEL_)
#define FB(b) (##b = (##b + 1) % _END_DEL_); // приращение шага
// шапка цикла
#define FH(a,b) for (##a=_END_SEC_,##b=_CFG_BGN_DEL_; ##a > _CFG_BGN_SEC_; ##a-=##b)
main(int c, char** v)
{
int a, b; int x=0; int i=0; int A1, A2;
unsigned char buf[SECTOR_SIZE];
// проверка аргументов командной строки
if (c < 2) {
fprintf(stderr,"USAGE:sf.exe CD\n\n");
printf( " SCSI_INQUITY via ASPI32\n"\
"-------------------------------------\n");
read_from_cd("?.?", buf,0); return 0;
}
// этап первый
//-----------------------------------------------------------------------
// читаем случайные сектора для разгона привода
fprintf(stderr,"%s\n",_TEXT_SPINEUP_);
for (a = 0; a < 0x69; a++)
{
read_from_cd(argCD, buf,rand()%_END_SEC_);
fprintf(stderr,"\r%02d%%",a*100/0x69);
}
// этап второй
//------------------------------------------------------------------------
// определяем кол-во секторов на дорожке и стабильность вращения привода
// алгоритм определения кол-ва секторов: читаем сектора задом наперед,
// с циклически увеличивающимся шагом, наименьшее значение шага
// при котором время чтения секторов будет минимальным - и будет равно
// кол-ву секторов на данном витке спирали
// (fixit: пока не реализовано, кол-во секторов взято на глазок)
//
// алгоритм определения стабильности: читаем сектора с шагом, равным
// кол-ву секторов на данном витке спирали, и оцениваем разброс;
// если разброс будет слишком большим (превышает 10%-15%), следует
// уменьшить скорость привода (как это сделать показано в CD.snail.c)
fprintf(stderr,"\r%s\n",_TEXT_TEST_);
for (a = _END_SEC_; a > _CFG_BGN_SEC_; a-=_CFG_xWHELL_)
{
A1=A(&c);read_from_cd(argCD, buf,a);A2=A(&c);
fprintf(stderr,"\r%02d%%",(_END_SEC_-a)*100/_CFG_LEN_SEC_);
}
// этап третий (важнейший!)
//------------------------------------------------------------------------
// производим, собственно, измерения
// fix1: добавить "сглаживание" полученных данных
fprintf(stderr,"\r%s\n",_TEXT_ANGLE_);
// выводим шапку таблицы
printf("delta:"); FH(a,b) { printf("\t%d",a); FB(b); } printf("\ntime:");
// измеряем и тут же выводим результаты
FH(a,b)
{
A1=A(&c); read_from_cd("TEAC", buf,a); A2=A(&c);
printf("\t%d",(A2-A1)/100);
fprintf(stderr,"\r%02d%%",(_END_SEC_-a)*100/_CFG_LEN_SEC_);
FB(b);
} printf("\n");
// всему конец
fprintf(stderr,"\r%s\n",_TEXT_END_); return 0;
}
Листинг 2 макет программы sf.c для снятия топологий
Программа использует библиотечку SCSIlib, разработанную автором для низкоуровневого управления приводами с прикладного уровня.Ее можно бесплатно скачать с ftp-сайта автора.