12. Cvičení: Práce na projektu

Obsahem cvičení je samostatná práce na projektu a konzultace (projektu, témat z přednášek…).

Studenti z probíhajícího cvičení mají přednostní přístup k deskám.

Ukázková kód použití otočných voličů

Výhoda následujícího použití informace změně polohy otočných voličů:

  • polohu objektu si nastavíte v nezávislé proměnné např. xx, yy
  • při načtení informace si vypočtete změnu otočných voličů (absolutní hodnota změny bude menší než 127)
  • můžete udělat pohyb citlivější, než je změna hodnoty voliče (zde xx+=diff_red/2;)
  • můžete jednoduše kontrolovat správnost polohy objektu korekcí proměnných xx a yy

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <time.h>
#include <unistd.h>
#include <termios.h>            //termios, TCSANOW, ECHO, ICANON
 
#include "mzapo_parlcd.h"
#include "mzapo_phys.h"
#include "mzapo_regs.h"
#include "kote.c"
 
unsigned short *fb;
 
void draw_pixel(int x, int y, unsigned short int color) {
  if (color!=65535) {
    fb[(x%480)+480*(y%320)] = color;
  }
}
 
 
int main(int argc, char *argv[]) {
  unsigned char *parlcd_mem_base, *mem_base;
  int i,j, ptr;
  fb  = (unsigned short *)malloc(320*480*2);
 
  printf("Hello world\n");
 
  parlcd_mem_base = map_phys_address(PARLCD_REG_BASE_PHYS, PARLCD_REG_SIZE, 0);
  if (parlcd_mem_base == NULL)
    exit(1);
 
  mem_base = map_phys_address(SPILED_REG_BASE_PHYS, SPILED_REG_SIZE, 0);
  if (mem_base == NULL)
    exit(1);
 
  parlcd_hx8357_init(parlcd_mem_base);
 
  struct timespec loop_delay;
  loop_delay.tv_sec = 0;
  loop_delay.tv_nsec = 150 * 1000 * 1000;
  int xx=240, yy=160;
  uint32_t r = *(volatile uint32_t*)(mem_base + SPILED_REG_KNOBS_8BIT_o);
  int last_red = ((r>>16)&0xff);
  int last_blue = (r&0xff);
  while (1) {
 
    r = *(volatile uint32_t*)(mem_base + SPILED_REG_KNOBS_8BIT_o);
    if ((r&0x7000000)!=0) {
      break;
    }
    int red = ((r>>16)&0xff);
    int blue = (r&0xff);
    int diff_red = red - last_red;
    last_red = red;
    if (diff_red<-128) {
	diff_red+=256;
    }
    if (diff_red>128) {
	diff_red-=256;
    }
    xx+=diff_red/2;	
    if (xx<0) {
	xx=0;
    }
    if (xx>350) {
	xx=350;
    }
    int diff_blue = blue - last_blue;
    last_blue = blue;
    if (diff_blue<-128) {
	diff_blue+=256;
    }
    if (diff_blue>128) {
	diff_blue-=256;
    }
    yy+=diff_blue/2;
    if (yy<0) {
	yy=0;
    }
    if (yy>240) {
	yy=240;
    }
    printf("xx %i Diff red %i (%i)  yy %i diff blue %i (%i)\n", xx, diff_red, red, yy, diff_blue, blue);
 
    for (ptr = 0; ptr < 320*480 ; ptr++) {
        fb[ptr]=0u;
    }
    for (j=0; j<kote_png_height; j++) {
      for (i=0; i<kote_png_width; i++) {
        draw_pixel(i+xx,j+yy,kote_png[i+j*kote_png_width]);
      }
    }
 
    parlcd_write_cmd(parlcd_mem_base, 0x2c);
    for (ptr = 0; ptr < 480*320 ; ptr++) {
        parlcd_write_data(parlcd_mem_base, fb[ptr]);
    }
 
    clock_nanosleep(CLOCK_MONOTONIC, 0, &loop_delay, NULL);
  }
 
  parlcd_write_cmd(parlcd_mem_base, 0x2c);
  for (ptr = 0; ptr < 480*320 ; ptr++) {
    parlcd_write_data(parlcd_mem_base, 0);
  }
 
  printf("Goodbye world\n");
 
  return 0;
}

Ukázková kód použití vláken

  • Ukázkový kód využívající posix threads pro vícevláknovou aplikaci. Ukazuje možné rozdělení projektu do vláken
    • main - hlavní vlákno
    • input_thread - vstupní vlákno
    • output_thread - výstupní vlákno
    • V tomto případě je vykreslování na LCD realizováno kontinuelně a ne on-demand. Variant řešení je samozřejmě více. Template si klade za cíl hlavně ukázat práci s posixovými vlákny.
    • #define _POSIX_C_SOURCE 200112L
       
      #include <stdlib.h>
      #include <stdio.h>
      #include <stdint.h>
      #include <time.h>
      #include <unistd.h>
      #include <stdbool.h>
       
      #include <pthread.h>
       
      #include "mzapo_parlcd.h"
      #include "mzapo_phys.h"
      #include "mzapo_regs.h"
      #include "serialize_lock.h"
       
      #define IMG_SIZE 320*480
       
      //type definition of struct for shared data between threads
      typedef struct { 
        bool quit;
        unsigned char *parlcd_mem_base;
        uint16_t * fb_read;
        uint16_t * fb_write;
      } data_t;
       
      void * input_thread(void * data);
      void * output_thread(void * data);
       
      //mutexes for double buffering of frames
      pthread_mutex_t mtx_fb; 
       
      int main(int argc, char *argv[])
      {
       
        // Serialize execution of applications
        // Try to acquire lock the first 
        if (serialize_lock(1) <= 0) {
          printf("System is occupied\n");
       
          if (1) {
            printf("Waiting\n");
            // Wait till application holding lock releases it or exits
            serialize_lock(0);
          }
        }
       
        printf("Hello world\n");
       
        //initialize the two frame buffers
        uint16_t fb0[IMG_SIZE]; 
        uint16_t fb1[IMG_SIZE]; 
       
        //initialize the shared data
        data_t shared_data;
        shared_data.quit = false;
        shared_data.fb_read = &fb0;
        shared_data.fb_write = &fb1;
       
        //map the memory
        shared_data.parlcd_mem_base = map_phys_address(PARLCD_REG_BASE_PHYS, PARLCD_REG_SIZE, 0);
        if (shared_data.parlcd_mem_base == NULL){
          exit(1);
        }
       
        //prepare the threads
        enum {INPUT, OUTPUT, NUM_THREADS};
        const char *thread_names[] = {"input", "output"}; 
        void* (*thread_functions[])(void *) = {input_thread, output_thread};
       
        //initialize the threads and mutex
        pthread_t threads[NUM_THREADS];
        pthread_mutex_init(&mtx_fb, NULL);
       
        //spawn the threads
        for (int i = 0; i < NUM_THREADS; ++i){
          int res = pthread_create(&threads[i], NULL, thread_functions[i], &shared_data);
          fprintf(stdout, "INFO: Create thread '%s' %s\n", thread_names[i], (res == 0 ? "OK" : "FAIL") );
          //TODO:correctly exit if some thread does not initialize
        }
       
        //main loop
        uint16_t color = 0x0000;
       
        while(!shared_data.quit){
          //simulate some long calculations 
          usleep(10000);
       
          //write the frame buffer
          for (int i = 0; i < IMG_SIZE; i++) {
            //write to the write buffer     
            shared_data.fb_write[i] = color;
          }
          color+=1;
       
          //swap the buffers - first need to acquire the mutex for write read buffer
          pthread_mutex_lock(&mtx_fb);
          //..now swap them
          uint16_t * tmp = shared_data.fb_read;
          shared_data.fb_read = shared_data.fb_write;
          shared_data.fb_write = tmp;
          //..and unlock the read buffer for display
          pthread_mutex_unlock(&mtx_fb);
       
        }
        shared_data.quit = true;
       
        //joining the threads
        for (int i = 0; i < NUM_THREADS; ++i) {
            fprintf(stdout, "INFO: Call join to the thread %s\n", thread_names[i]);
            int r = pthread_join(threads[i], NULL);
            fprintf(stdout, "INFO: Joining the thread %s has been %s\n", thread_names[i], (r == 0 ? "OK" : "FAIL"));
         }
       
        printf("Goodbye world\n");
       
        // Release the lock 
        serialize_unlock();
       
        return 0;
      }
       
       
      //------------------------------------------------------------
      void * input_thread(void * data){
        data_t * shared_data = (data_t *) data;
       
        while(!shared_data->quit){
          //TODO: sample the input once in a while
          char c = getchar();
          if (c == 'q'){
            shared_data->quit = true;
          }
       
          //sleep for some time
          usleep(10000);
        }
      }
       
      //------------------------------------------------------------
      void * output_thread(void * data){
        data_t * shared_data = (data_t *) data;
       
        //initialize the display
        parlcd_hx8357_init(shared_data->parlcd_mem_base);
       
        uint16_t fb_p = NULL;
        //draw in infinite loop
        while(!shared_data->quit){
       
          //lock the output frame buffer so no one can write into it
          pthread_mutex_lock(&mtx_fb);
          //reset the cursor
          parlcd_write_cmd(shared_data->parlcd_mem_base, 0x2c);
          //write the buffer
          for (int i = 0; i < IMG_SIZE; ++i) {
              parlcd_write_data(
                shared_data->parlcd_mem_base, shared_data->fb_read[i]);
          }
          //unlock the buffer 
          pthread_mutex_unlock(&mtx_fb);
       
          //sleep for some time
          usleep(10000);
        }
      }
courses/b35apo/tutorials/12/start.txt · Last modified: 2026/04/28 16:13 by stepan