/* File: snake_plas.c Authors: various see other source code. Mashed together by Doug Rice, 13/9/2015 This software runs on the raspberry pi B with and Astro Pi Hat merge of snake and plasma to run on Astro Pi HAT ond Raspbery Pi B+ Install Astro Pi Hat on Raspberry Pi B+ with 40 pin GPIO connector. Resources:- Raspberry Pi https://www.raspberrypi.org/competitions/astro-pi/ http://astro-pi.org/ http://astro-pi.org/hardware/ http://astro-pi.org/resources/ https://github.com/astro-pi https://github.com/bennuttall/sense-hat-examples snake.c is installed to directory /usr/src/sense-hat/examples/snake Resources:- Arduino, Colourduino Plasma colour display which is GNU demo for Colorduino which is an 8x8 LED board with Arduino boot loader. https://github.com/lincomatic/Colorduino/blob/master/ColorduinoPlasma/ColorduinoPlasma.pde Resources:- Doug Rice http://ccgi.dougrice.plus.com/cgi-bin/wiki.pl?Arduino_Colordunio_And_SVG_Projects Build this using: gcc -lm snake_plas.c run using ./a.out Why: The Colourduinio Plasma is a good demo of the possible colours without too much effort. */ #define _GNU_SOURCE #define DEV_INPUT_EVENT "/dev/input" #define EVENT_DEV_NAME "event" #define DEV_FB "/dev" #define FB_DEV_NAME "fb" #include #include #include #include #include #include #include #include #include #include #include #include #include /* ************************ SEC 1.0 added by doug ************************ */ #include #define OFF (0x0) #define RED (0x1F<<11) #define GREEN (0x1F<<5) #define BLUE (0x1F<<0) #define AMBER RED+GREEN #define TLR fb->pixel[1][3] #define TLA fb->pixel[1][2] #define TLG fb->pixel[1][1] /***********************/ enum direction_t{ UP, RIGHT, DOWN, LEFT, NONE, }; struct segment_t { struct segment_t *next; int x; int y; }; struct snake_t { struct segment_t head; struct segment_t *tail; enum direction_t heading; }; struct apple_t { int x; int y; }; struct fb_t { uint16_t pixel[8][8]; }; int running = 1; struct snake_t snake = { {NULL, 4, 4}, NULL, NONE, }; struct apple_t apple = { 4, 4, }; struct fb_t *fb; static int is_event_device(const struct dirent *dir) { return strncmp(EVENT_DEV_NAME, dir->d_name, strlen(EVENT_DEV_NAME)-1) == 0; } static int is_framebuffer_device(const struct dirent *dir) { return strncmp(FB_DEV_NAME, dir->d_name, strlen(FB_DEV_NAME)-1) == 0; } static int open_evdev(const char *dev_name) { struct dirent **namelist; int i, ndev; int fd = -1; ndev = scandir(DEV_INPUT_EVENT, &namelist, is_event_device, versionsort); if (ndev <= 0) return ndev; for (i = 0; i < ndev; i++) { char fname[64]; char name[256]; snprintf(fname, sizeof(fname), "%s/%s", DEV_INPUT_EVENT, namelist[i]->d_name); fd = open(fname, O_RDONLY); if (fd < 0) continue; ioctl(fd, EVIOCGNAME(sizeof(name)), name); if (strcmp(dev_name, name) == 0) break; close(fd); } for (i = 0; i < ndev; i++) free(namelist[i]); return fd; } static int open_fbdev(const char *dev_name) { struct dirent **namelist; int i, ndev; int fd = -1; struct fb_fix_screeninfo fix_info; ndev = scandir(DEV_FB, &namelist, is_framebuffer_device, versionsort); if (ndev <= 0) return ndev; for (i = 0; i < ndev; i++) { char fname[64]; char name[256]; snprintf(fname, sizeof(fname), "%s/%s", DEV_FB, namelist[i]->d_name); fd = open(fname, O_RDWR); if (fd < 0) continue; ioctl(fd, FBIOGET_FSCREENINFO, &fix_info); if (strcmp(dev_name, fix_info.id) == 0) break; close(fd); fd = -1; } for (i = 0; i < ndev; i++) free(namelist[i]); return fd; } /* ************************ SEC 1.0 snake game code ************************ */ void render() { struct segment_t *seg_i; memset(fb, 0, 128); fb->pixel[apple.x][apple.y]=0xF800; for(seg_i = snake.tail; seg_i->next; seg_i=seg_i->next) { fb->pixel[seg_i->x][seg_i->y] = 0x7E0; } fb->pixel[seg_i->x][seg_i->y]=0xFFFF; } int check_collision(int appleCheck) { struct segment_t *seg_i; if (appleCheck) { for (seg_i = snake.tail; seg_i; seg_i=seg_i->next) { if (seg_i->x == apple.x && seg_i->y == apple.y) return 1; } return 0; } for(seg_i = snake.tail; seg_i->next; seg_i=seg_i->next) { if (snake.head.x == seg_i->x && snake.head.y == seg_i->y) return 1; } if (snake.head.x < 0 || snake.head.x > 7 || snake.head.y < 0 || snake.head.y > 7) { return 1; } return 0; } void game_logic(void) { struct segment_t *seg_i; struct segment_t *new_tail; for(seg_i = snake.tail; seg_i->next; seg_i=seg_i->next) { seg_i->x = seg_i->next->x; seg_i->y = seg_i->next->y; } if (check_collision(1)) { new_tail = malloc(sizeof(struct segment_t)); if (!new_tail) { printf("Ran out of memory.\n"); running = 0; return; } new_tail->x=snake.tail->x; new_tail->y=snake.tail->y; new_tail->next=snake.tail; snake.tail = new_tail; while (check_collision(1)) { apple.x = rand() % 8; apple.y = rand() % 8; } } switch (snake.heading) { case LEFT: seg_i->y--; break; case DOWN: seg_i->x++; break; case RIGHT: seg_i->y++; break; case UP: seg_i->x--; break; } } void reset(void) { struct segment_t *seg_i; struct segment_t *next_tail; seg_i=snake.tail; while (seg_i->next) { next_tail=seg_i->next; free(seg_i); seg_i=next_tail; } snake.tail=seg_i; snake.tail->next=NULL; snake.tail->x=2; snake.tail->y=3; apple.x = rand() % 8; apple.y = rand() % 8; snake.heading = NONE; } void change_dir(unsigned int code) { switch (code) { case KEY_UP: if (snake.heading != DOWN) snake.heading = UP; break; case KEY_RIGHT: if (snake.heading != LEFT) snake.heading = RIGHT; break; case KEY_DOWN: if (snake.heading != UP) snake.heading = DOWN; break; case KEY_LEFT: if (snake.heading != RIGHT) snake.heading = LEFT; break; } } /* ************************ SEC 1.0 added by doug ************************ */ void handle_events(int evfd) { struct input_event ev[64]; int i, rd; rd = read(evfd, ev, sizeof(struct input_event) * 64); if (rd < (int) sizeof(struct input_event)) { fprintf(stderr, "expected %d bytes, got %d\n", (int) sizeof(struct input_event), rd); return; } for (i = 0; i < rd / sizeof(struct input_event); i++) { if (ev->type != EV_KEY) continue; if (ev->value != 1) continue; switch (ev->code) { case KEY_ENTER: running = 0; break; default: change_dir(ev->code); } } } /* ************************ SEC 1.0 added by doug - Plasma code ************************ */ #define floor floorf /* ColorduinoPlasma - Plasma demo using Colorduino Library for Arduino Copyright (c) 2011 Sam C. Lin lincomatic@hotmail.com ALL RIGHTS RESERVED based on Color cycling plasma Version 0.1 - 8 July 2009 Copyright (c) 2009 Ben Combee. All right reserved. Copyright (c) 2009 Ken Corey. All right reserved. Copyright (c) 2008 Windell H. Oskay. All right reserved. Copyright (c) 2011 Sam C. Lin All Rights Reserved This demo is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This demo is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* #include */ #define ColorduinoScreenHeight 8 #define ColorduinoScreenWidth 8 typedef struct { unsigned char r; unsigned char g; unsigned char b; } ColorRGB; //a color with 3 components: h, s and v typedef struct { unsigned char h; unsigned char s; unsigned char v; } ColorHSV; unsigned char plasma[ColorduinoScreenWidth][ColorduinoScreenHeight]; long paletteShift; int plas_type, plas_type_subsample ; //Converts an HSV color to RGB color void HSVtoRGB(void *vRGB, void *vHSV) { float r, g, b, h, s, v; //this function works with floats between 0 and 1 float f, p, q, t; int i; ColorRGB *colorRGB=(ColorRGB *)vRGB; ColorHSV *colorHSV=(ColorHSV *)vHSV; h = (float)(colorHSV->h / 256.0); s = (float)(colorHSV->s / 256.0); v = (float)(colorHSV->v / 256.0); //if saturation is 0, the color is a shade of grey if(s == 0.0) { b = v; g = b; r = g; } //if saturation > 0, more complex calculations are needed else { h *= 6.0; //to bring hue to a number between 0 and 6, better for the calculations i = (int)(floor(h)); //e.g. 2.7 becomes 2 and 3.01 becomes 3 or 4.9999 becomes 4 f = h - i;//the fractional part of h p = (float)(v * (1.0 - s)); q = (float)(v * (1.0 - (s * f))); t = (float)(v * (1.0 - (s * (1.0 - f)))); switch(i) { case 0: r=v; g=t; b=p; break; case 1: r=q; g=v; b=p; break; case 2: r=p; g=v; b=t; break; case 3: r=p; g=q; b=v; break; case 4: r=t; g=p; b=v; break; case 5: r=v; g=p; b=q; break; default: r = g = b = 0; break; } } colorRGB->r = (int)(r * 255.0); colorRGB->g = (int)(g * 255.0); colorRGB->b = (int)(b * 255.0); } float dist(float a, float b, float c, float d) { return sqrt((c-a)*(c-a)+(d-b)*(d-b)); } void plasma_morph( struct fb_t *fb ) { unsigned char x,y; float value; ColorRGB colorRGB; ColorHSV colorHSV; if (!fb) { printf("Failed to mmap....\n"); } for(y = 0; y < ColorduinoScreenHeight; y++) { for(x = 0; x < ColorduinoScreenWidth; x++) { switch( plas_type % 2) { case 0: { /* original */ value = sin(dist(x + paletteShift, y, 128.0, 128.0) / 8.0) + sin(dist(x, y, 64.0, 64.0) / 8.0) + sin(dist(x, y + paletteShift / 7, 192.0, 64) / 7.0) + sin(dist(x, y, 192.0, 100.0) / 8.0); }; break; case 1: { /* more rapid changing values */ value = sin(dist(x + paletteShift, y, 128.0, 128.0) / 3.0) + sin(dist(x, y, 32.0, 32.0) / 5.0) + sin(dist(x, y + paletteShift / 7, 192.0, 64) / 7.0) + sin(dist(x, y, 192.0, 100.0) / 4.0); }; }; switch( plas_type >> 1) { case 0: { /* original */ colorHSV.h=(unsigned char)((value) * 128)&0xff; colorHSV.s=255; colorHSV.v=255; }; break; case 1: { /* colour on dark */ colorHSV.v=(unsigned char)((value) * 128)&0xff; colorHSV.h=255; colorHSV.s=255; }; break; case 2: { /* White and red */ colorHSV.s=(unsigned char)((value) * 128)&0xff; colorHSV.v=255; colorHSV.h=255; }; break; case 3: { /* blodge of colour */ colorHSV.v=(unsigned char)((value) * 128)&0xff; colorHSV.h=paletteShift % 255; colorHSV.s=255; }; break; case 4: { /* White and changing colour */ colorHSV.s=(unsigned char)((value) * 128)&0xff; colorHSV.v=128; colorHSV.h=paletteShift % 255; }; break; case 5: { /* colour on dark */ colorHSV.v=(unsigned char)((value) * 128)&0xff; colorHSV.h=paletteShift % 255; colorHSV.s=255; }; break; case 6: { /* original - 64*/ colorHSV.h=(unsigned char)((value) * 64)&0xff; colorHSV.s=255; colorHSV.v=255; }; break; case 7: { /* original */ colorHSV.h=(unsigned char)((value) * 32)&0xff; colorHSV.s=255; colorHSV.v=(unsigned char)((value) * 128)&0xff; }; break; }; /* end switch */ HSVtoRGB(&colorRGB, &colorHSV); //printf("%d %d %d \n", colorRGB.b, colorRGB.g, colorRGB.r ); // Colorduino.SetPixel(x, y, colorRGB.r, colorRGB.g, colorRGB.b); fb->pixel[x][y]=( (colorRGB.b>>3) <<0 ) /*blue*/ + ( (colorRGB.g>>3) <<5 ) /*green*/ + ( (colorRGB.r>>3) <<11); /*red*/ }; }; paletteShift++; plas_type_subsample--; printf( ":=: %d %d %d %d \n",x,y,plas_type,plas_type_subsample ); if ( plas_type_subsample < 0 ){ plas_type_subsample = 256; plas_type++; if ( plas_type > 7 ){ plas_type = 0 ; }; } // Colorduino.FlipPage(); // swap screen buffers to show it } /******************************************************** Name: ColorFill Function: Fill the frame with a color Parameter:R: the value of RED. Range:RED 0~255 G: the value of GREEN. Range:RED 0~255 B: the value of BLUE. Range:RED 0~255 ********************************************************/ void ColorFill(unsigned char R,unsigned char G,unsigned char B) { unsigned char y,x; ColorRGB *p; //PixelRGB *p ; = Colorduino.GetPixel(0,0); /* need a pointer to p */ for ( y=0;yr = R; p->g = G; p->b = B; p++; */ } } //Colorduino.FlipPage(); } #define ColorduinoScreenHeight 8 #define ColorduinoScreenWidth 8 void setup() { unsigned char y,x; //Colorduino.Init(); // initialize the board // compensate for relative intensity differences in R/G/B brightness // array of 6-bit base values for RGB (0~63) // whiteBalVal[0]=red // whiteBalVal[1]=green // whiteBalVal[2]=blue unsigned char whiteBalVal[3] = {36,63,63}; // for LEDSEE 6x6cm round matrix //Colorduino.SetWhiteBal(whiteBalVal); // start with morphing plasma, but allow going to color cycling if desired. paletteShift=128000; unsigned char bcolor; //generate the plasma once for( y = 0; y < ColorduinoScreenHeight; y++) for( x = 0; x < ColorduinoScreenWidth; x++) { //the plasma buffer is a sum of sines bcolor = (unsigned char) ( 128.0 + (128.0 * sin(x*8.0 / 16.0)) + 128.0 + (128.0 * sin(y*8.0 / 16.0)) ) / 2; plasma[x][y] = bcolor; } // to adjust white balance you can uncomment this line // and comment out the plasma_morph() in loop() // and then experiment with whiteBalVal above // ColorFill(255,255,255); } /* void loop() { plasma_morph(); } */ /* ========================================================================================== */ /* ************************ SEC 1.0 main from snake moved to bottom as prototypes have not been added for Plasma code. ************************ */ int main(int argc, char* args[]) { int ret = 0; int fbfd = 0; int cnt; int bit; struct pollfd evpoll = { .events = POLLIN, }; srand (time(NULL)); evpoll.fd = open_evdev("Raspberry Pi Sense HAT Joystick"); if (evpoll.fd < 0) { fprintf(stderr, "Event device not found.\n"); return evpoll.fd; } fbfd = open_fbdev("RPi-Sense FB"); if (fbfd <= 0) { ret = fbfd; printf("Error: cannot open framebuffer device.\n"); goto err_ev; } fb = mmap(0, 128, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0); if (!fb) { ret = EXIT_FAILURE; printf("Failed to mmap.\n"); goto err_fb; } memset(fb, 0, 128); snake.tail = &snake.head; reset(); /* while (running) { while (poll(&evpoll, 1, 0) > 0) handle_events(evpoll.fd); game_logic(); if (check_collision(0)) { reset(); } render(); usleep (300000); } */ bit = 1; fb->pixel[0][0]=1<<1; /* settting Pixel on astro pi sense hat */ // fb->pixel[2][0]=0x1F<<0; /*blue*/ // fb->pixel[3][0]=0x1F<<5; /*green*/ // fb->pixel[4][0]=0x1F<<11; /*red*/ usleep (30000); memset(fb, 0, 128); for ( cnt = 0 ; cnt < 2 ; cnt++){ usleep (30000); // fb->pixel[1][7]=BLUE; /*green*/ usleep (30000); TLR = RED; /*blue*/ TLA = OFF; /*green*/ TLG = OFF; /*green*/ usleep (30000); TLR = RED; /*blue*/ TLA = OFF; /*green*/ TLG = OFF; /*green*/ fb->pixel[1][7]=OFF; /*green*/ usleep (30000); TLR = RED; /*blue*/ TLA = AMBER; /*green*/ TLG = OFF; /*green*/ usleep (30000); TLR = OFF; /*blue*/ TLA = OFF; /*green*/ TLG = GREEN; /*green*/ usleep (30000); TLR = OFF; /*blue*/ TLA = OFF; /*green*/ TLG = GREEN; /*green*/ usleep (30000); TLR = OFF; /*blue*/ TLA = AMBER; /*green*/ TLG = OFF; /*green*/ usleep (30000); TLR = RED; /*blue*/ TLA = OFF; /*green*/ TLG = OFF; /*green*/ } printf("setup()....\n"); setup(); plas_type_subsample = 4; plas_type = 0; // for ( cnt = 0 ; cnt < 20000 ; cnt++){ while( 1==1 ){ // printf("plasma_morph()....\n"); plasma_morph( fb ); usleep (50000); } memset(fb, 0, 128); reset(); munmap(fb, 128); /* gotos to escape when file */ err_fb: close(fbfd); err_ev: close(evpoll.fd); return ret; }