/* Includes ------------------------------------------------------------------*/ #include "stm32f4xx_hal.h" /* USER CODE BEGIN Includes */ #include "led_driver.h" #include "globals.h" #include #include #include #include "flash.h" #include "image_generator.h" /* USER CODE END Includes */ //#define NB_LEDS_PER_STRIP 60 //#define NB_LINES 20 __attribute__((section("itcmram"))) inline uint32_t getRawOffset(uint32_t column,uint32_t line) { return 3*(column+line*NB_COLUMNS); } // cf file LogoFiltered2.raw & cfromraw.cpp // from LogoElectrolab.png // 20 x 20 pixels // Exploite la symétrie gauche droite => 10x20 const uint8_t logo_electrolab[200] = { 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0D, 0x1A, 0x28, 0x30, 0x09, 0x09, 0x09, 0x09, 0x0A, 0x1F, 0x50, 0x83, 0xA7, 0xB5, 0x09, 0x09, 0x09, 0x0C, 0x3B, 0x91, 0xD6, 0xEF, 0xEB, 0xE1, 0x09, 0x09, 0x0C, 0x4A, 0xB8, 0xEE, 0xD1, 0x93, 0x62, 0x4B, 0x09, 0x0A, 0x3F, 0xBB, 0xEF, 0xA9, 0x49, 0x17, 0x0A, 0x07, 0x09, 0x25, 0x9A, 0xF0, 0xA7, 0x33, 0x01, 0x01, 0x01, 0x01, 0x0F, 0x5B, 0xDF, 0xCE, 0x45, 0x0A, 0x00, 0xA4, 0xC5, 0xC5, 0x1F, 0x91, 0xF3, 0x8B, 0x15, 0x08, 0x00, 0x96, 0xF7, 0xF7, 0x30, 0xB5, 0xE9, 0x59, 0x09, 0x08, 0x00, 0x04, 0x0D, 0x0D, 0x39, 0xC3, 0xDC, 0x42, 0x08, 0x01, 0x00, 0x86, 0xAE, 0xAE, 0x38, 0xC2, 0xDD, 0x44, 0x08, 0x00, 0x00, 0x9F, 0xE8, 0xE8, 0x2E, 0xB1, 0xEB, 0x5F, 0x0A, 0x05, 0x00, 0x04, 0x0D, 0x0D, 0x1C, 0x88, 0xF2, 0x96, 0x19, 0x08, 0x00, 0x6A, 0x99, 0x99, 0x0D, 0x51, 0xD6, 0xD8, 0x54, 0x0C, 0x01, 0xB4, 0xEE, 0xEE, 0x09, 0x1D, 0x8A, 0xEE, 0xB9, 0x44, 0x02, 0x05, 0x0E, 0x0E, 0x09, 0x09, 0x32, 0xA9, 0xF0, 0xBE, 0x60, 0x24, 0x0F, 0x08, 0x09, 0x09, 0x0A, 0x39, 0xA3, 0xE9, 0xE1, 0xAE, 0x7F, 0x66, 0x09, 0x09, 0x09, 0x0A, 0x2B, 0x79, 0xC2, 0xE9, 0xF0, 0xEC, 0x09, 0x09, 0x09, 0x09, 0x09, 0x16, 0x3D, 0x6A, 0x8D, 0x9B, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0A, 0x12, 0x1C, 0x22 }; void putSpriteEL(uint8_t *raw, uint8_t offsetx, uint8_t *color) { uint32_t raw_offset; int line, column; int j; for (line=0;line<20;line++) { j = line*10; raw_offset = getRawOffset(offsetx, line); for (column=0;column<20;column++) { // sequence j 0,1,2..9,9,8,7,...,1,0,0,1,2,... if (column>=10) j--; raw[raw_offset++] = (color[0]*logo_electrolab[j])>>8; raw[raw_offset++] = (color[1]*logo_electrolab[j])>>8; raw[raw_offset++] = (color[2]*logo_electrolab[j])>>8; if (column<10) j++; } } } // vert vert vert... uint8_t generateLogoElectrolab(uint8_t *raw, uint8_t intensity) { uint8_t offsetx; uint8_t color[3]; offsetx = 0; color[0] = 0; color[1] = intensity; color[2] = 0; putSpriteEL(raw, offsetx, color); offsetx = 20; color[0] = 0; color[1] = intensity; color[2] = 0; putSpriteEL(raw, offsetx, color); offsetx = 40; color[0] = 0; color[1] = intensity; color[2] = 0; putSpriteEL(raw, offsetx, color); return 0; } __attribute__((section("dtcmram"))) float sintable[91] = { 0.000000,0.017452,0.034899,0.052336,0.069756,0.087156,0.104528,0.121869, 0.139173,0.156434,0.173648,0.190809,0.207912,0.224951,0.241922,0.258819, 0.275637,0.292372,0.309017,0.325568,0.342020,0.358368,0.374607,0.390731, 0.406737,0.422618,0.438371,0.453990,0.469472,0.484810,0.500000,0.515038, 0.529919,0.544639,0.559193,0.573576,0.587785,0.601815,0.615662,0.629320, 0.642788,0.656059,0.669131,0.681998,0.694658,0.707107,0.719340,0.731354, 0.743145,0.754710,0.766044,0.777146,0.788011,0.798635,0.809017,0.819152, 0.829038,0.838671,0.848048,0.857167,0.866025,0.874620,0.882948,0.891007, 0.898794,0.906308,0.913545,0.920505,0.927184,0.933580,0.939693,0.945519, 0.951057,0.956305,0.961262,0.965926,0.970296,0.974370,0.978148,0.981627, 0.984808,0.987688,0.990268,0.992546,0.994522,0.996195,0.997564,0.998630, 0.999391,0.999848,1.000000 }; // si pi/2 <= x <= pi // sin(x) = sin(pi-x) // si pi <= x <= 3/4 pi // sin(x) = -sin(x-pi) // si 3/4 pi <= x <= 2pi // sin(x) = -sin(-(x-2pi)) __attribute__((section("itcmram"))) float myfsin(float x) { int i; // for plasma : that's the difference between 30hz and 70Hz...(with microlib) // not using microlib makes it go to 100Hz. i = /*fmod(x*180.0f/M_PI,360);*/ ((int) (x*180.0f/M_PI)) % 360; if (i<0) { i+=360; } if (i<=90) return sintable[i]; if (i<=180) return sintable[180-i]; if (i<=270) return -sintable[i-180]; return -sintable[-(i-360)]; } //cos(x) = sin(pi/2-x) __attribute__((section("itcmram"))) float myfcos(float x) { return myfsin(M_PI/2-x); } __attribute__((section("itcmram"))) uint8_t generatePlasma(uint8_t *raw,float u_time, uint8_t plasma_type, uint8_t intensity) { uint32_t raw_offset; uint32_t line, column; float u_k[2]; float v_coords[2]; float v; float c[2]; uint8_t x; uint8_t s1,s2,s4,c1; u_k[0] = u_k[1] = 4; for (line=0;line>2; generateUniformColor(raw,color); return 0; } // GAME OF LIFE CODE START // well, ok, ram footprint could be / 8 // but that's ok, plenty of ram uint8_t imageff[2][NB_LINES][NB_COLUMNS]; void randfill(void) { int line, column; for (line=0;line=RAND_MAX/2?1:0); } } } uint8_t get8brothers(uint8_t flip,int line,int column) { int cl,cr,lu,ld; // manage rollover on borders if (line==0) lu = NB_LINES-1; else lu = line-1; if (line == NB_LINES-1) ld = 0; else ld = line +1; if (column==0) cl = NB_COLUMNS-1; else cl = column-1; if (column==NB_COLUMNS-1) cr = 0; else cr = column+1; // addup brothers return imageff[flip][lu][cl] + imageff[flip][lu][column] + imageff[flip][lu][cr] + imageff[flip][line][cl] + imageff[flip][line][cr] + imageff[flip][ld][cl] + imageff[flip][ld][column] + imageff[flip][ld][cr]; } // goal : detect situations of cycles // not a good way to compare, best method is to compute a hash and compare the hashs on more that 2 or 3 cycles. // if match, then start a few seconds countdown before restart uint8_t compareGOLImages(void) { uint8_t *p0,*p1; uint32_t p; p0 = &imageff[0][0][0]; p1 = &imageff[1][0][0]; p = 0; while (p2))||((prepareRestart!=0)&&(time-prepareRestart>10))||(time-autoRestart>60)) { flip = 0; flop = 1; srand(time*20); randfill(); initialized = 1; prepareRestart = 0; autoRestart = time; lastTime = time; } else { if (time-lastTime<0.3f) { return 1; } flip = 1-flip; flop = 1-flop; } // calcule de flip vers flop for (line=0;line>8; while(i) { *raw_out = ((*raw_in)*(intensity+1))>>8; raw_out++; raw_in++; i--; } } // POWER LIMITER CODE START #define MAX_LEDTUBE_LINE_POWER (NB_COLUMNS*3*POWER_LIMIT) __attribute__((section("itcmram"))) int powerLimiter(uint8_t *raw_out, uint8_t *raw_in, uint8_t intensity) { int line, column, i; uint8_t *p_in; uint16_t linePower; uint16_t maxLinePower; uint16_t ipowerReduction; p_in = raw_in; maxLinePower = 0; intensity = (intensity*intensity)>>8; for (line=0;line> 8; if (linePower>maxLinePower) maxLinePower = linePower; } if (maxLinePower>MAX_LEDTUBE_LINE_POWER) // power will be limited { ipowerReduction = (uint16_t) (256.0f*MAX_LEDTUBE_LINE_POWER/maxLinePower); i=RAW_SIZE; do { *raw_out = ((*raw_in)*(ipowerReduction)) >> 8; raw_in++; raw_out++; } while(--i); return 1; } return 0; } // POWER LIMITER CODE END void ledstripXmax(uint8_t *raw); uint8_t imageGenerator(uint32_t currentMode, uint8_t *raw, float time, uint8_t intensity) { uint8_t dynamic; int raw_image_number; switch(currentMode) { case 0: dynamic = 0; break; case 1: case 2: case 3: case 4: case 5: dynamic = generatePlasma(raw,time,(uint8_t) currentMode, intensity); break; case 6: dynamic = generateLogoElectrolab(raw, intensity); break; case 7: dynamic = generateBlack(raw); break; case 8: dynamic = generateWhite(raw, intensity); break; case 9: dynamic = generateYellow(raw, intensity); break; case 10: dynamic = generateLogoElectrolab(raw, intensity); break; case 11: dynamic = generateGameOfLife(raw, time, intensity); break; case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: dynamic = generatePlasma(raw,time,(uint8_t) currentMode, intensity); break; // case 21: dynamic = generateElabLogos(raw);break; // Pas beau case 21: ledstripXmax(raw); dynamic = 1; break; default: break; } if (currentMode>=IMAGE_MODES_START) // 22..22+31=53 { raw_image_number = currentMode-IMAGE_MODES_START; readImageFromFlash(raw,raw_image_number); dynamic = 0; } return dynamic; }