Maskinorienterad Programmering / Programmering av Inbyggda System

Hemuppgifter C-programmering

C - Föreläsning 5.

Här skall vi kika på hur man skulle kunna konvertera vårt projekt mot labbdatorn MD407.

Att konvertera projektet mot labbdatorn MD407

Ni utför ju både hemuppgifter (på den här hemsidan) samt laborationsuppgifter i labbsalarna. I den sista laborationsuppgiften kommer ni att implementera ett spel (eller liknande projekt). I princip skulle ni kunna konvertera ert projekt i hemuppgifterna till labbdatorn MD407. Det som behövs är följande:
  • SDL finns såklart inte för MD407. Alltså behöver vi implementera motsvarigheterna till keyboard input, grafisk output och ascii-output själva:
    • Grafisk output: Med hjälp av avsnittet "Grafisk Display" i Arbetsboken behövs egna motsvarigheter istället för dessa SDL- eller SDL-baserade funktioner implementeras:
      • SDL_GetWindowSize(...). Grafiska displayens upplösning är 128*64.
      • bool initRenderer(int windowWidth, int windowHeight). Ska initiera den grafiska displayen. Ni kan helt enkelt anropa er graphics_initialize() från avsnitt 5 Arbetsboken.
      • void closeRenderer(). Behövs ej.
      • GfxObject createGfxObject( const char* imagefilename ). Skapa istället ett lämpligt och initierat objekt av typen GEOMETRY från Arbetsboken avsnitt 5.
      • void renderGfxObject(GfxObject* gfx, int x, int y, double angle, float scale ); Förslagsvis skippar man för enkelhets skull möjligheten att rotera och skala. Använd istället er draw_object()-funktion från Arbetsboken, avsnitt 5.
      • void renderGfxSubFrame(GfxObject* gfx, int x, int y, double angle, float scale, SDL_Rect srcRect ). Skippa animeringar eller utöka structen GEOMETRY för sådant stöd.
      • void freeGfxObject(GfxObject* gfx); Behövs ej.
    • ASCII output: I renderer.c för funktionerna renderText(...) samt renderTextWithColor(...) kan ni förslagsvis istället skriva ut till ASCII-displayen med t ex:
      void ascii_print(char* s, int line) { ascii_gotoxy(1, line); while(*s) ascii_write_char( *(s++) ); }
      där ascii_gotoxy() och ascii_write_char() finns i avsnitt 5, Arbetsboken.
    • Keyboard input: I Arbetsboken avsnitt 4 - General Purpose IO implementerade ni stöd för ett 16-knappars tangentbord. I spel vill man typiskt läsa av alla knappar som är nedtryckta - inte bara en. Detta kräver endast en mycket liten modifiering av er funktion keyb(). T ex:
      • Skapa en global variabel keyStatus som innehåller en statusbit per knapp (0=up, 1=down).
      • I realtidsloopen i main(), istället för att använda SDL_PollEvent, anropa er tangentbordsfunktion som uppdaterar statusbitarna.
      • I player.c, istället för state[SDL_SCANCODE_ ...]) läser ni av lämplig bit i keyStatus.
      • Vill ni läsa av seriella tangentbordsnedtryckningar från ert vanliga datortangentbord gör ni detta lätt med er char _tstchar(void)-funktion från Arbetsboken avsnitt 7 Seriekommunikation.
  • Flyttal: Om ni använder flyttal, checka att det är aktiverat i CrossGCC (arm)-kompilatorn under "Project Settings"->Compiler->"C Compiler Options".
    • Följande flaggor simulerar flyttal och funkar bra både i hårdvara och simulator: -mthumb;-msoft-float;-march=armv6-m;
    • Följande flaggor funkar bara för hårdvaran men ger bättre prestanda:
    -mthumb;-mfloat-abi=hard;-mfpu=fpv4-sp-d16;-march=armv7-m;
  • Flyttalsfunktioner från math.h: Vi använder fmod(), fabs, sqrt(). Dessutom använder vi rand() från stdlib.h samt strlen() från string.h. Enklast är att implementera dessa själv, t ex såhär:
    MyMath.h #ifndef MYMATH_H #define MYMATH_H #define RAND_MAX 32767 static unsigned int next = 1; static inline unsigned int rand(void) { next = next * 1103515245 + 12345; return (unsigned int)(next/65536) % 32768; } static inline void srand(unsigned int seed) { next = seed; } static inline int strlen(const char* str) { const char *s; for (s = str; *s; s++) ; return (s - str); } static inline float fabs(float v) { return (v >= 0) ? v : -v; } static inline float floor(float v) { return (int)v; } static inline float fmod(float x, float y) { float i, f; if (y == 0.0) return 0.0; i = floor(x/y); f = x - i*y; if ((x < 0.0) != (y < 0.0)) f = f-y; return f; } static inline float sqrt(float x){ float xhalf = 0.5f * x; int i = *(int*)&x; // store floating-point bits in integer i = 0x5f3759df - (i >> 1); // initial guess for Newton's method x = *(float*)&i; // convert new bits into float x = x*(1.5f - xhalf*x*x); // One round of Newton's method return 1.0f/x; } #endif // MYMATH_H