Amiga C

28. Bölüm

Cenker Özkurt

Amiga C'de örnek programlarımız devam ediyor. Bu ay iki yeni örneğimiz var. İlk örnek program, disketinizin herhangi bir track ve sector'ündeki bilgileri, bir sector uzunluğunda (512 byte) okumanızı sağlıyor. Elinizdeki birçok disket utility programlarında olduğu gibi. Tabii ki bizim örneğimiz bu olayı daha basite indirerek anlamanızı kolaylaştırıyor. İkinci örneğimiz ise, bir hafıza bölgesini görüntülememizi sağlayan kısa bir program. Bu program ile yumuşak hardware scroll'lar ile daha büyük ekranlar üzerinde gezebiliriz.

Sanıyorum, şu ana kadar vermiş olduğum kısa veya uzun örnek programları, yazarak veya üzerinde oynayarak deneyim kazanmışsınızdır. Bu ayki örneğimiz de aynı amacı taşıyor. Bundan sonra ise C'de yeni bir konu üzerinde duracağız! Konumuzu kısaca açıklayayım;

Bildiğiniz gibi Amiga'nın işletim sistemi oldukça gelişmiş (PC'lere göre!). Açılan screen'ler, window'lar ve gadget'ler bu sistemin bir parçası. Böylece bir mouse aracılığı ile bile program kullanmak oldukça kolaylaşıyor. Bu sistemin tamamı, 'intuition.library' içerisindeki program parçaları ile yönetiliyor. İşte bu sistemi tanımak ve benzeri programlan yazabilmek için, 'intuition.library' içerisine gireceğiz. Bu konuyu kısaca "intuition" olarak tanımlayabiliriz. Buradan da anlaşılıyor ki, gelecek ayki ve sonraki aylardaki konumuz, "intuition". Bu konuyu iyi kavradığınızda artık birşeyleri aşmış sayılırız!

Evet, bu ayki ilk örneğimize geçebiliriz. Önceden de belirttiğim gibi, ilk örnek ile disketteki herhangi bir track ve sector'deki bilgileri, bir sector uzunluğunca (512 byte'lık) okuyabiliyoruz. Program çalıştırıldığında bizden bir track, sector ve kafa (head) numarası istiyor. Burada track 0 ile 79 arasında, sector 0 ile 11, kafa ise 0 ya da 1 olabiliyor. Daha sonra program, disketinizin vermiş olduğunuz bölgesindeki 512 byte'lık kısmı hem ASCII hem de HEX olarak, hafızasına yükleyerek ekrana yansıtıyor. Bu sayede o bölgeyi incelememiz mümkün olabiliyor.

Şimdi aşağıdaki programımızı bir deneyin!.

/* (c) ShowDisk by Cenker Ozkurt */ 
#include "exec/types.h" 
#include "exec/devices.h" 
#include "devices/trackdisk.h"

#define TD_READ CMD_READ 
#define BLOCKSIZE TD_SECTOR 
#define NUMHEADS 2

struct MsgPort *diskport; 
struct IOExtTD *diskreq;

BYTE diskbuffer[BLOCKSIZE]; 
BYTE *diskdata; 
ULONG diskChangeCount;

main(argc,argv) 
int argc; 
char *argv[];
{
int i,j;
printf("ShowDisk by Cenker Ozkurt\n");
if(argc!=4) {
  printf("Usage : ShowDisk [Cylinder] [Sector] [Head]\n");
  return(0);
}
InitDisk();
diskdata=&diskbuffer[0];
ReadCylSec(atoi(argv[1]),atoi(argv[2]),atoi(argv[3])); 
FreeDisk(); 
for(i=0;i<512;i+=8) {
  printf("%003d : ",i);
  for(j=0;j<8;j++) {
     printf("%02x ",(UBYTE)*(diskdata+i+j));
  }
  printf(" = "); 
  for(j=0;j<8;j++) {
     if(*(diskdata+i+j)>32) {
	printf("%c",*(diskdata+i+j));
     } elseprintf(".");
  }
  printf("\N");
}
}

ReadCylSec(cyl, sec, hd) 
SHORT cyl, sec, hd;
{ 
  LONG offset;

  diskreq->iotd_Req.io_Length = BLOCKSIZE; 
  diskreq->iotd_Req.io_Data = (APTR)diskdata; 
  diskreq->iotd_Req.io_Command = TD_READ; 
  diskreq->iotd_Count = diskChangeCount; 
  offset = TD_SECTOR * (sec + NUMSECS * hd + NUMS ECS * NUMHEADS * cyl);
  diskreq->iotd_Req.io_Offset = offset; 
  return(DoIO(diskreq)); 
}

MotorOn()
{
  diskreq->iotd_Req.io_Length = 1;
  diskreq->iotd_Req.io_Command = TD_MOTOR;
  DoIO(diskreq);
  return(0); I
}

MotorOff()
{
  diskreq->iotd_Req.io_Length = 0; 
  diskreq->iotd_Req.io_Command = TD_MOTOR;
  DoIO(diskreq);
  return(0);
}

InitDisk()
{
diskport = CreatePort(0,0); 
if(diskport == 0) exit(100);
diskreq = (struct IOExtTD *)CreateExtIO(diskport,sizeof(struct IOExtTD)); 
if(diskreq == 0) { DeletePort(diskport); exit(200); }
OpenDevice(TD_NAME,0,diskreq,0);
diskreq->iotd_Req.io_Command = TD_CHANGENUM;
DoIO(diskreq);
diskChangeCount = diskreq->iotd_Req.io_Actual;
MotorOn();
}

FreeDisk()
{
MotorOff();
CIoseDevice(diskreq);
DeleteExtIO(diskreq, sizeof(struct IOExtTD));
DeletePort(diskport);
}
Program buraya kadar. Programı yazdıktan sonra CHIP memory'de çalışacak şekilde compile etmemiz gerekiyor. Aksi takdirde programımız doğru çalışmaz. Bunun sebebi, geçen aylarda anlattığım copper olayında olduğu gibi, disk işlemlerinin de kontrol register'larının DMA tarafından kontrol edilmesi. Bu da bizim yapı değişkenlerimizin CHIP hafıza bölgesinde bulunmasını gerektiriyor. Compile işlemini, CC +L Prog.c; link işlemini ise LN +C prog.o -LC32 olarak yazın.

Programı ilk olarak örnek parametrelerle bir deneyelim. Programımızın ismini ShowDisk olarak verdim. Buna göre 'ShowDisk 0 0 0' yazdığımızda, program bize sıfırıncı track ve sector olan bootblock bölgesini görüntüleyecektir. Aynı şekilde root bloğu görmek istediğimizde; 'ShowDisk 40 0 0' yazmamız yeterli olacaktır. Dikkat ettiyseniz, program parametrelerini Main içerisinden alıyor. Bu nedenle programın istediği parametreleri program isminden hemen sonra vermemiz gerekiyor. Program listesini ise rutinler haline getirerek daha anlaşılır yapmaya çalıştım. Bu nedenle şimdilik rutin seviyesinde programımızı inceleyeceğiz.

İlk olarak programımız, 'main' içerisinden parametreleri alarak, eğer bir hata yoksa InitDisk(); rutinine sıçrıyor. Bu rutinde 'df0;' device'ını bizim kullanabilmemiz için bir 'Port' yaratılıyor (CreatePort();). Daha sonra bu port'u kumanda edebilmemiz için 'diskreq' yapı değişkeni tanımlanıyor (CreateExtIO();). Artık bu işlemlerden sonra device'ımızı açıp kullanabiliriz (OpenDevice();). Tabii ki bu işi DoIO(); komutu ile gerçekleştiriyoruz. Bu komut sayesinde 'diskreq' yapı değişkeninde hazırlamış olduğumuz isteklerimiz gerçekleştiriliyor. Daha sonra program InitDisk(); rutininden çıkıp ReadCylSec(); rutinine sıçrıyor. Bu rutinde ise istenen track, sector ve head parametreleri verilerek diskten track yükleme gerçekleştiriliyor.

Bu rutin içerisinde yine 'diskreq' yapı değişkeni vasıtasıyla disket için yapmak istediğimiz işlemi belirtiyoruz. Burada bu isteğimizi 'command' struct değişkenine TD_READ olarak verdik. Bu macro değişkeni ile 'TrackDisk Read' komutunu vermiş oluyoruz. Burada TD_WRITE macro değişkenini verdiğimizde ise, bir yazma işlemim gerçekleştirmiş oluyoruz. Bu sayede disketinizin istediğiniz bir bölgesine bilgi yazabilirsiniz.

Bu arada disketten okuma işleminde, okunacak bilgilerin 'diskdata' değişkenine yüklendiğini ve BLOCKSlZE (512 byte=1 sector) uzunluğunda olduğuna dikkat edin. Rutinden geri döndüğümüzde ise, artık gerekli bilgi 'diskdata' değişkenine yüklenmiş olacaktır. Bundan sonra kendimize ayırdığımız Port'umuzu FreeDisk(); rutini ile rahat bırakabiliriz. Programın sonrası ise artık bilgilerin ekrana Text ve Hex olarak yazılmasını sağlamaktadır. Bir noktayı unutmadan belirteyim; her disketten yükleme ya da yazma işleminden önce MotorOn(); sonra MotorOff(); rutinlerine sıçramamız gerekir.

İşte, Amiga'da Track-Track yükleme ya da yazma işlemleri bunlardan ibarettir, 'diskreq' yapı değişkenine verilen diğer trackdisk macro komutlarını, include dosyaları içerisinden trackdisk.h dosyası içerisinden bulabilirsiniz.

Sıra geldi ikinci örneğimize. Programımıza bir gözatarak açıklamamıza geçelim,

#include <stdio.h> 
#include <exec/types.h> 
#inciude <graphics/gfx.h> 
#include <hardware/dmabits.h> 
#include <hardware/custom.h> 
#include <hardware/blit.h> 
#include <graphics/gfxmacros.h> 
#include <graphics/copper.h> 
#include <graphics/view.h> 
#include <graphics/rastport.h> 
#include <graphics/gels.h> 
#include <graphics/regions.h> 
#include <graphics/clip.h> 
#include <exec/exec.h> 
#include <graphics/text.h> 
#include <graphics/gfxbase.h> 
#include <functions.h>

#define DEPTH 3L 
#define WIDTH 1020L 
#define HEIGTH 1020L

#define VPWIDTH 320L 
#define VPHEIGTH 200L
#define NOT_ENOUGH_MEMORY -1000

struct View view,*oldview; 
struct ViewPort viewport; 
struct ColorMap *cm;

struct Raslnfo rasinfo; 
struct BitMap bitmap; 
struct RastPort rastport;

extern struct ColorMap *GetColorMap(); 
struct GfxBase *GfxBase;

USHORT colortable[]={
 0x000, 0xfb0, 0xccc, 0xf15, 0xa50, 0x0c5, 0x777, 0x77f, 
 0x000, 0x55f, 0x000, 0xc57, 
 0,0,0,0,
 0,0,0,0,0,0,0,0, 
 0,0,0,0,0,0,0,0
};
UWORD *colorpalette;

main(argc, argv) 
int argc; 
char *argv[];

{
  LONG i,n;
  SHORT nmax=5;
  SHORT pf1_xmove, pf1_ymove;
  UBYTE *displaymem;

  GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0L);
  if (GfxBase == NULL) exit(100); 
  oldview = GfxBase->ActiView;
 
  InitBitMap(&bitmap, DEPTH, WTDTH, HEIGHT);
  InitRastPort(&rastport); 
  rastport.BitMap = &bitmap;

  rasinfo.BitMap = &bitmap;
  rasinfo.RxOffset = 0;
  rasinfo.RyOffset = 0;
  rasinfo.Next = NULL;

  InitView(&view); 
  InitVPort(&viewport); 
  view.ViewPort = &viewport; 
  view.Modes =PFBA; 
  viewport.DWidth = VPWIDTH; 
  viewport.DHeight = VPHEIGHT; 
  viewport.RasInfo = &rasinfo;

  cm = GetColorMap(32L); 
  if (cm = NULL) {
     FreeMemory();
     exit(100);
}

  colorpalette = (UWORD *)cm->ColorTable;
  for(i=0; i<32; i++) {
     *colorpalette++ = colortable[i];
}
viewport.ColorMap = cm;

for(i=0; i=319) {
    pf1_xmove = -pf1_xmove;
	 n=n+1;
  }
  if(rasinfo.RyOffset<=0 || rasinfo.RyOffset>=199) { 
    pfl_ymove = -pfl_ymove; 
         n=n+1;
}

   MakeVPort(&view, &viewport);
   MrgCop(&view);
   LoadView(&view);

   WaitTOF();
  }
  FreeMemory();
}
FreeMemory()
{
  LONG i;

  for (i=0; i<DEPTH; i++) {
	if(bitmap.Planes[i]!=NULL) {
	FreeRaster(bitmap.Planes[i], WIDTH, HEIGHT); 
	    }
  }

  if(cm!=NULL) FreeColorMap(cm); 
  LoadView(oldview); 
  FreeVPortCopLists(&viewport); 
  FreeCprList(view.LOFCprList); 
  CloseLibrary(GfxBase);
}
İkinci örneğimiz oldukça yararlı. Bu örnekte köşeden köşeye bir çizgi çekilerek yumuşak hardware scroll gerçekleştiriliyor. Yapılan işlemi kısaca şöyle anlatalım: İlk olarak, kullanacağımız plane bilgilerini tutan 'bitmap' ve 'rastport' yapı değişkenleri yaratılıyor. Bu yapı değişkenleri bir 'rasinfo' yapı değişkenine bildiriliyor. Bu sayede scroll, rasinfo içerisinden offset değişkenlerle kontrol edilebiliyor. Rasinfo değişkeni, ViewPort yapı değişkeni için görüntü alanını saklama görevi görüyor. Bu sayede MakeVPort(); fonksiyonu ile görüntü yapısal olarak sisteme bildiriliyor. Fakat bu işlem görüntünün gelmesine yetersiz kalıyor. Bu görüntüyü copper listesine eklememiz gerekiyor. Bu işlemi de MrgCop(); fonksiyonu ile gerçekleştiriyor ve LoadView(); ile ekrana gelmesini sağlıyoruz.

Ekranda yaptığımız her işlemden sonra (mesela çizgi çekmek ya da ekran offset'i ile oynayarak kaydırma işlemini yapmak) aynı şekilde görüntüyü sisteme belirtmek ve tazelemek için MakeVPort(), MrgCop() ve LoadView() fonksiyon üçlüsünü kullanmamız gerekmektedir. Bundan sonrası ise Amiga'ya kalmış.

Programımızın yapmış olduğu iş ana hatlarıyla bu kadar. Diğer kısımları anlayabileceğinizi tahmin ederek bu ayki yazımızı burada noktalıyorum. Yazımın başında da belirttiğim gibi bundan sonraki konumuz 'intuition'lar. Gelecek ay buluşmak üzere hepinize mutlu günler dilerim!....