├── LICENSE ├── Makefile ├── README.md ├── cnrfb.c ├── cnrfb.h ├── elf_x86_64_mod.x ├── esp ├── 0x00000.bin ├── 0x40000.bin ├── Makefile ├── driver │ ├── uart.c │ └── uart.h └── user │ ├── mystuff.c │ ├── mystuff.h │ ├── stdint.h │ ├── stdio.h │ ├── string.h │ ├── user_config.h │ ├── user_main.c │ ├── ws2812.c │ └── ws2812.h ├── font.h ├── fonter.c ├── fps.c ├── fps.h ├── heap.c ├── heap.h ├── linux_interface.c ├── mathfuncts.c ├── mathfuncts.h ├── mathtables.h ├── tabler.c └── vga8x12.pbm /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Charles 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all : fonter fps 2 | 3 | OBJS:=cnrfb.c linux_interface.c heap.c 4 | 5 | MAKE_TINY_x86_64:=-Os -s -flto -Wl,--relax -Wl,-Map=test.map -Wl,--gc-sections -ffunction-sections -fdata-sections -T./elf_x86_64_mod.x 6 | 7 | fps : fps.c $(OBJS) font.h mathtables.h 8 | gcc $(OBJS) $< mathfuncts.c -o $@ $(MAKE_TINY_x86_64) 9 | 10 | fonter : fonter.o 11 | gcc $(MAKE_TINY_x86_64) -o $@ $^ 12 | 13 | mathtables.h : tabler.c 14 | gcc $(MAKE_TINY_x86_64) -o tabler tabler.c -lm 15 | ./tabler > mathtables.h 16 | 17 | font.h : fonter vga8x12.pbm 18 | ./fonter vga8x12.pbm 8 16 > font.h 19 | 20 | clean : 21 | rm -rf fonter cnrfb *.o *~ fps tabler 22 | 23 | wipe : clean 24 | rm -rf mathtables.h font.h 25 | 26 | 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pylotron 2 | Embedded VNC-based FPS. 3 | manual: 4 | 1.Look in the "esp" folder, then use the 0x00000.bin and 0x40000.bin firmwares. You can flash these to an esp8266 using firmware flashing tools. 5 | 2. Download vnc viewer for your OS. (RealVNC and ultravnc Viewers is working, tight vnc viewer doesn't working) 6 | 3. Connect your PC to esp8266's AP. 7 | 4. Connect your vnc viewer to 192.168.4.1 8 | 5. Enjoy! You can run using "w, s, d, a"; look around using "←, →"; shoot using "space" and jump using "alt". 9 | 10 | -------------------------------------------------------------------------------- /cnrfb.c: -------------------------------------------------------------------------------- 1 | //https://www.realvnc.com/docs/rfbproto.pdf 2 | //http://vncdotool.readthedocs.org/en/latest/rfbproto.html 3 | 4 | #include 5 | #include 6 | #include "cnrfb.h" 7 | #include "font.h" 8 | 9 | struct CNRFBSt CNRFBs[MAX_RFB_CONNS]; 10 | 11 | uint8_t ServerInit[] = { 12 | RFB_WIDTH>>8, RFB_WIDTH&0xff, 13 | RFB_HEIGHT>>8, RFB_HEIGHT&0xff, 14 | 15 | 8, //Bits per pixel. 16 | 8, //Depth 17 | 0, //Big endian (meaningless) 18 | 1, //True color? 19 | //Color is RRRGGGBB 20 | 0, 7, 0, 7, 0, 3, 21 | 0, 3, 6, 0, 0, 0, 22 | }; 23 | 24 | int CNRFBNewConnection( ) 25 | { 26 | int i; 27 | for( i = 0; i < MAX_RFB_CONNS; i++ ) 28 | { 29 | if( CNRFBs[i].in_use == 0 ) 30 | { 31 | printf( "Connecting at: %d\n", i ); 32 | memset( &CNRFBs[i], 0, sizeof(struct CNRFBSt) ); 33 | CNRFBs[i].in_use = 1; 34 | CNRFBs[i].state = 0; 35 | CNRFBs[i].timeout = 0; 36 | CNRFBs[i].use_zrle = 1; 37 | return i; 38 | } 39 | } 40 | } 41 | 42 | void CNRFBGotData( int conn, int recvqty ) 43 | { 44 | struct CNRFBSt * c = &CNRFBs[conn]; 45 | c->timeout = 0; 46 | 47 | switch( c->state ) 48 | { 49 | case 0: 50 | case 2: //Server just connected, or server already sent handshake. 51 | if( recvqty != 12 ) 52 | { 53 | CNRFBNote( "Error: wrong number of bytes for handshake (%d).\n", recvqty ); 54 | break; 55 | } 56 | else 57 | { 58 | CNRFBRead4(); 59 | CNRFBRead4(); 60 | CNRFBRead4(); 61 | } 62 | //Todo: Check to make sure versions are compatible. 63 | c->state++; 64 | break; 65 | case 4: 66 | { 67 | uint8_t canshare = CNRFBRead1(); 68 | c->state = 5; 69 | break; 70 | } 71 | case 6: 72 | case 7: 73 | case 8: 74 | { 75 | while( CNRFBReadRemain() ) 76 | { 77 | //Normal operations mode. 78 | uint8_t cmd = CNRFBRead1(); 79 | switch( cmd ) 80 | { 81 | case 0: //Client requests a different pixel type. 82 | { 83 | CNRFBRead2(); CNRFBRead1(); 84 | int bpp = CNRFBRead1(); 85 | int dep = CNRFBRead1(); 86 | int endian = CNRFBRead1(); 87 | int tcolor = CNRFBRead1(); 88 | CNRFBDump(12); 89 | 90 | if( !tcolor ) 91 | c->need_to_send_colormap |= 1; 92 | break; 93 | } 94 | case 2: //Got encodings 95 | { 96 | CNRFBRead2(); 97 | uint16_t codes = CNRFBRead2(); 98 | uint16_t i; 99 | for( i = 0; i != codes; i++ ) 100 | { 101 | CNRFBRead4(); 102 | } 103 | c->got_encodings = 1; 104 | break; 105 | } 106 | case 3: //Wants update! 107 | { 108 | int incremental = CNRFBRead1(); 109 | c->update_requested = 1; 110 | CNRFBDump(8); //x,y,w,h 111 | c->state = 7; 112 | break; 113 | } 114 | case 4: 115 | { 116 | uint8_t down = CNRFBRead1(); 117 | uint8_t key; 118 | CNRFBRead2(); 119 | key = CNRFBRead4(); 120 | GotKeyPress( conn, key, down ); 121 | } 122 | break; 123 | case 5: 124 | { //Pointer event 125 | int bm = CNRFBRead1(); 126 | int x = CNRFBRead2(); 127 | int y = CNRFBRead2(); 128 | GotMouseEvent( conn, bm, x, y ); 129 | break; 130 | } 131 | case 6: 132 | { //Client Cut Text 133 | CNRFBDump(3); 134 | uint32_t len = CNRFBRead4(); 135 | uint8_t buff[len]; 136 | int i; 137 | for( i = 0; i < len; i++ ) 138 | buff[i] = CNRFBRead1(); 139 | GotClipboard( conn, len, buff ); 140 | break; 141 | } 142 | default: 143 | printf( "Unknown code: %d\n", cmd ); 144 | }; 145 | } 146 | 147 | break; 148 | } 149 | default: 150 | break; 151 | } 152 | } 153 | 154 | void CNRFBConnectionWasClosed( int conn ) 155 | { 156 | CNRFBs[conn].in_use = 0; 157 | 158 | CNRFBCloseConnection( conn ); 159 | } 160 | 161 | void CNRFBInit() 162 | { 163 | memset( CNRFBs, 0, sizeof( CNRFBs ) ); 164 | } 165 | 166 | void CNRFBTick( int slow_tick ) 167 | { 168 | static uint8_t cl; 169 | 170 | cl++; 171 | if( cl >= MAX_RFB_CONNS ) cl = 0; 172 | 173 | int i, j; 174 | 175 | //Do for all clients. 176 | for( i = 0; i < MAX_RFB_CONNS; i++ ) 177 | { 178 | struct CNRFBSt * c = &CNRFBs[i]; 179 | if( c->in_use == 0 ) continue; 180 | 181 | if( slow_tick ) 182 | { 183 | if( c->timeout++ > MAX_RFB_TIMEOUT ) 184 | { 185 | CNRFBNote( "Connection %d timed out.\n", i ); 186 | c->in_use = 0; 187 | CNRFBCloseConnection( i ); 188 | continue; 189 | } 190 | } 191 | 192 | if( CNRFBCanSendData( i ) ) 193 | { 194 | switch( c->state ) 195 | { 196 | case 1: //cases 012 are for handshaking 197 | case 0: 198 | CNRFBStartSend( i ); 199 | CNRFBSendData( "RFB 003.003\n", 12 ); 200 | CNRFBEndSend( i ); 201 | c->state += 2; 202 | break; 203 | case 2: break; 204 | case 3: //Security handshake 205 | CNRFBStartSend( i ); 206 | CNRFBSend4( 1 ); //No security. 207 | CNRFBEndSend(); 208 | c->state = 4; 209 | break; 210 | case 4: break; 211 | case 5: //Got desktop share flag 212 | { 213 | CNRFBStartSend( i ); 214 | CNRFBSendData( ServerInit, 20 ); 215 | int nl = strlen( RFB_SERVER_NAME ); 216 | CNRFBSend4( nl ); 217 | CNRFBSendData( RFB_SERVER_NAME, nl ); 218 | CNRFBEndSend(); 219 | 220 | c->state = 6; //Move to and expect a clientinit message. 221 | break; 222 | } 223 | case 6: 224 | if( c->got_encodings ) 225 | c->state = 7; 226 | break; 227 | case 7: 228 | { 229 | c->update_requested = 1; 230 | c->state = 8; 231 | break; 232 | } 233 | default: //8 = normal state 234 | if( c->need_to_send_colormap == 1 ) //Split color map up into two packets so it's not enormous. 235 | { 236 | int whichset = c->need_to_send_colormap-1; 237 | 238 | CNRFBStartSend( i ); 239 | CNRFBSend1( 1 ); //Palette 240 | CNRFBSend1( 0 ); //Padding 241 | CNRFBSend2( 0 ); 242 | CNRFBSend2( 256 ); 243 | 244 | for( j = 0; j < 128; j++ ) 245 | { 246 | uint8_t color = j; 247 | CNRFBSend2( (color & 0x07)<<(5+8) ); 248 | CNRFBSend2( ((color>>3) & 0x07)<<(5+8) ); 249 | CNRFBSend2( ((color>>6) & 0x03)<<(6+8) ); 250 | } 251 | CNRFBEndSend(); 252 | c->need_to_send_colormap |= 2; ///Really weird logic to make it possible to re-send the color map mid-way through the colormap. 253 | c->need_to_send_colormap &= 2; 254 | } 255 | else if( (c->need_to_send_colormap & 2) == 2 ) 256 | { 257 | CNRFBStartSend( i ); 258 | for( j = 0; j < 128; j++ ) 259 | { 260 | uint8_t color = j+128; 261 | CNRFBSend2( (color & 0x07)<<(5+8) ); 262 | CNRFBSend2( ((color>>3) & 0x07)<<(5+8) ); 263 | CNRFBSend2( ((color>>6) & 0x03)<<(6+8) ); 264 | } 265 | CNRFBEndSend(); 266 | c->need_to_send_colormap &= 1; 267 | } 268 | else if( c->update_requested ) 269 | { 270 | FreeFrameForClient( i ); 271 | } 272 | break; 273 | 274 | } 275 | } 276 | 277 | } 278 | 279 | } 280 | 281 | 282 | //17 bytes each. 283 | void DrawRect( uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t color ) 284 | { 285 | CNRFBSend2( x ); 286 | CNRFBSend2( y ); 287 | CNRFBSend2( w ); 288 | CNRFBSend2( h ); 289 | CNRFBSend4( 2 ); //RRE 290 | CNRFBSend4( 0 ); 291 | CNRFBSend1( color ); 292 | } 293 | 294 | void DrawRectAtAsPartOfRRE( uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t color ) 295 | { 296 | CNRFBSend1( color ); 297 | CNRFBSend2( x ); 298 | CNRFBSend2( y ); 299 | CNRFBSend2( w ); 300 | CNRFBSend2( h ); 301 | } 302 | 303 | 304 | int StartFrameDraw( int conn, int nrdr ) 305 | { 306 | if( !CNRFBCanSendData( conn ) ) return -1; 307 | CNRFBStartSend( conn ); 308 | 309 | CNRFBSend1( 0 ); //FramebufferUpdate 310 | CNRFBSend1( 0 ); //Padding 311 | CNRFBSend2( nrdr ); 312 | return 0; 313 | } 314 | 315 | 316 | void StartRRE( int qty, uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t bg ) 317 | { 318 | CNRFBSend2( x ); 319 | CNRFBSend2( y ); 320 | CNRFBSend2( w ); 321 | CNRFBSend2( h ); 322 | CNRFBSend4( 2 ); //RRE 323 | CNRFBSend4( qty ); 324 | CNRFBSend1( bg ); 325 | } 326 | 327 | int CountCharForRRE( uint8_t ch ) 328 | { 329 | return font_places[ch+1] - font_places[ch]; 330 | } 331 | 332 | void DrawCharAtAsPartOfRRE( uint8_t ch, uint8_t fg, uint16_t offsetx, uint16_t offsety ) 333 | { 334 | uint16_t pla = font_places[ch]; 335 | uint16_t end = font_places[ch+1]; 336 | for( ; pla != end; pla++ ) 337 | { 338 | uint16_t col = font_pieces[pla]; 339 | CNRFBSend1( fg ); 340 | CNRFBSend2( ((col>>0)&0xf) + offsetx ); 341 | CNRFBSend2( ((col>>4)&0xf) + offsety ); 342 | CNRFBSend2( ((col>>8)&0xf) + 1 ); 343 | CNRFBSend2( ((col>>12)&0xf) + 1 ); 344 | } 345 | } 346 | 347 | void PrintText( const char * text, uint8_t fg, uint8_t bg, uint16_t border, uint16_t x, uint16_t y ) 348 | { 349 | int qty = 0; 350 | const char * c = text; 351 | uint16_t maxw = 0, maxh = FONT_CHAR_H; 352 | uint16_t xp = 0, yp = 0; 353 | 354 | for( ; *c; c++ ) 355 | { 356 | switch( *c ) 357 | { 358 | case '\n': xp = 0; maxh+= FONT_CHAR_H; break; 359 | case '\t': xp += FONT_CHAR_W * 4; break; 360 | default: qty += CountCharForRRE( *c ); xp += FONT_CHAR_W; break; 361 | } 362 | if( xp > maxw ) maxw = xp; 363 | } 364 | 365 | xp = border; 366 | yp = border; 367 | StartRRE( qty, x, y, maxw + border*2, maxh + border*2, bg ); 368 | 369 | for( c = text; *c; c++ ) 370 | { 371 | switch( *c ) 372 | { 373 | case '\n': xp = border; yp+= FONT_CHAR_H; break; 374 | case '\t': xp += FONT_CHAR_W * 4; break; 375 | default: DrawCharAtAsPartOfRRE(*c, fg, xp, yp); xp += FONT_CHAR_W; break; 376 | } 377 | } 378 | } 379 | 380 | 381 | void EndFrameDraw(int conn) 382 | { 383 | CNRFBs[conn].update_requested = 0; 384 | CNRFBEndSend(); 385 | } 386 | 387 | -------------------------------------------------------------------------------- /cnrfb.h: -------------------------------------------------------------------------------- 1 | #ifndef _CNRFB_H 2 | #define _CNRFB_H 3 | 4 | 5 | 6 | #include 7 | 8 | #define MAX_RFB_CONNS 8 9 | #define MAX_RFB_TIMEOUT 10000 10 | 11 | #define MAX_SEND_BUFFER 512 12 | 13 | #define RFB_WIDTH 640 14 | #define RFB_HEIGHT 480 15 | #define RFB_SERVER_NAME "Test" 16 | 17 | #define CHARBANKX 0 18 | #define CHARBANKY (RFB_HEIGHT-32) 19 | 20 | #define RFB_COLS 80 21 | #define RFB_ROWS 60 22 | 23 | #define CNRFBNote( x... ) printf( x ); 24 | 25 | // TCP/IP Interface (You must provide this) 26 | 27 | int CNRFBNewConnection( ); //If returns negative, indicates failure. 28 | void CNRFBGotData( int conn, int recvqty ); 29 | void CNRFBConnectionWasClosed( int conn ); 30 | void CNRFBTick( int slow_tick ); //Slow ticks happen at 100 Hz? 31 | 32 | 33 | int CNRFBCanSendData( int conn ); //If returns nonzero, can send. 34 | int CNRFBStartSend( int conn ); //Returns nonzero if can't send. 35 | void CNRFBSendData( const uint8_t * data, int len ); 36 | void CNRFBSend1( uint8_t data ); 37 | void CNRFBSend2( uint16_t data ); 38 | void CNRFBSend4( uint32_t data ); 39 | void CNRFBEndSend( ); 40 | void CNRFBCloseConnection( int conn ); 41 | 42 | int CNRFBReadRemain(); //value of 0 indicates no more can read. 43 | uint8_t CNRFBRead1(); 44 | uint16_t CNRFBRead2(); 45 | uint32_t CNRFBRead4(); 46 | void CNRFBDump( int i ); 47 | void CNRFBFinishCB(); //Call if you want to stop receiving and start sending. 48 | 49 | //Callback 50 | 51 | void FreeFrameForClient( int i ); 52 | void GotKeyPress( int client, int key, int down ); 53 | void GotMouseEvent( int client, int mask, int x, int y ); 54 | void GotClipboard( int client, int length, unsigned char * st ); 55 | // CNRFB Code 56 | 57 | struct CNRFBSt 58 | { 59 | int in_use:1; 60 | int use_zrle:1; 61 | int got_encodings:1; 62 | int update_requested:1; 63 | int need_to_send_colormap:2; 64 | uint8_t state:4; 65 | uint16_t timeout; 66 | uint8_t refresh_state:2; //0 = no refresh, 1,2,3 need to send respective. 67 | uint16_t refresh; 68 | }; 69 | 70 | extern struct CNRFBSt CNRFBs[MAX_RFB_CONNS]; 71 | 72 | // Calls to the actual RFB system. 73 | 74 | // Draw calls (can only be performed from within a screen update. 75 | 76 | //Return value is 0 if ok, otherwise, can't start frame draw. 77 | int StartFrameDraw( int conn, int qty ); 78 | 79 | //Its own thing. 80 | void DrawRect( uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t color ); 81 | 82 | //Treated as 1 rect, 17 bytes. 83 | void StartRRE( int qty, uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t bg ); //Treated as 1 rect. (4+sizeof(px)+(8+sizeof(px))*subrects) NOTE: qty can be 0! 84 | 85 | int CountCharForRRE( uint8_t ch ); //returns count of subrects. 86 | void DrawCharAtAsPartOfRRE( uint8_t ch, uint8_t fg, uint16_t offsetx, uint16_t offsety ); 87 | void DrawRectAtAsPartOfRRE( uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t fg ); //9 bytes. 88 | void PrintText( const char * text, uint8_t fg, uint8_t bg, uint16_t border, uint16_t x, uint16_t y ); //Treated as a rect. 89 | void EndFrameDraw(int conn); 90 | 91 | #endif 92 | 93 | 94 | -------------------------------------------------------------------------------- /elf_x86_64_mod.x: -------------------------------------------------------------------------------- 1 | /* Default linker script, for normal executables ... Tweaked by C. Lohr to make them smaller. */ 2 | OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", 3 | "elf64-x86-64") 4 | OUTPUT_ARCH(i386:x86-64) 5 | ENTRY(_start) 6 | SEARCH_DIR("/usr/x86_64-linux-gnu/lib64"); SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib/x86_64-linux-gnu"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib"); 7 | SECTIONS 8 | { 9 | /* Read-only sections, merged into text segment: */ 10 | PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS; 11 | .interp : { *(.interp) } 12 | .note.gnu.build-id : { *(.note.gnu.build-id) } 13 | .hash : { *(.hash) } 14 | .gnu.hash : { *(.gnu.hash) } 15 | .dynsym : { *(.dynsym) } 16 | .dynstr : { *(.dynstr) } 17 | .gnu.version : { *(.gnu.version) } 18 | .gnu.version_d : { *(.gnu.version_d) } 19 | .gnu.version_r : { *(.gnu.version_r) } 20 | .rela.init : { *(.rela.init) } 21 | .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } 22 | .rela.fini : { *(.rela.fini) } 23 | .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } 24 | .rela.data.rel.ro : { *(.rela.data.rel.ro .rela.data.rel.ro.* .rela.gnu.linkonce.d.rel.ro.*) } 25 | .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } 26 | .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } 27 | .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } 28 | .rela.ctors : { *(.rela.ctors) } 29 | .rela.dtors : { *(.rela.dtors) } 30 | .rela.got : { *(.rela.got) } 31 | .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } 32 | .rela.ldata : { *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*) } 33 | .rela.lbss : { *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*) } 34 | .rela.lrodata : { *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*) } 35 | .rela.ifunc : { *(.rela.ifunc) } 36 | .rela.plt : 37 | { 38 | *(.rela.plt) 39 | PROVIDE_HIDDEN (__rela_iplt_start = .); 40 | *(.rela.iplt) 41 | PROVIDE_HIDDEN (__rela_iplt_end = .); 42 | } 43 | .init : 44 | { 45 | KEEP (*(SORT_NONE(.init))) 46 | } 47 | .plt : { *(.plt) *(.iplt) } 48 | .text : 49 | { 50 | *(.text.unlikely .text.*_unlikely) 51 | *(.text.exit .text.exit.*) 52 | *(.text.startup .text.startup.*) 53 | *(.text.hot .text.hot.*) 54 | *(.text .stub .text.* .gnu.linkonce.t.*) 55 | /* .gnu.warning sections are handled specially by elf32.em. */ 56 | /* *(.gnu.warning) */ 57 | } 58 | .fini : 59 | { 60 | KEEP (*(SORT_NONE(.fini))) 61 | } 62 | PROVIDE (__etext = .); 63 | PROVIDE (_etext = .); 64 | PROVIDE (etext = .); 65 | .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } 66 | .rodata1 : { *(.rodata1) } 67 | /* .eh_frame_hdr : { *(.eh_frame_hdr) } 68 | .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } 69 | .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table 70 | .gcc_except_table.*) } 71 | */ 72 | /* These sections are generated by the Sun/Oracle C++ compiler. */ 73 | /* .exception_ranges : ONLY_IF_RO { *(.exception_ranges 74 | .exception_ranges*) } 75 | */ 76 | /* Adjust the address for the data segment. We want to adjust up to 77 | the same address within the page on the next page up. */ 78 | 79 | . = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1)); 80 | . = DATA_SEGMENT_ALIGN (16, 8); /*(CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));*/ 81 | 82 | /* Exception handling */ 83 | /* .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } */ 84 | .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } 85 | .exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } 86 | /* Thread Local Storage sections */ 87 | .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } 88 | .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } 89 | .preinit_array : 90 | { 91 | PROVIDE_HIDDEN (__preinit_array_start = .); 92 | KEEP (*(.preinit_array)) 93 | PROVIDE_HIDDEN (__preinit_array_end = .); 94 | } 95 | .init_array : 96 | { 97 | PROVIDE_HIDDEN (__init_array_start = .); 98 | KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) 99 | KEEP (*(.init_array)) 100 | KEEP (*(EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) 101 | PROVIDE_HIDDEN (__init_array_end = .); 102 | } 103 | .fini_array : 104 | { 105 | PROVIDE_HIDDEN (__fini_array_start = .); 106 | KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) 107 | KEEP (*(.fini_array)) 108 | KEEP (*(EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) 109 | PROVIDE_HIDDEN (__fini_array_end = .); 110 | } 111 | .ctors : 112 | { 113 | /* gcc uses crtbegin.o to find the start of 114 | the constructors, so we make sure it is 115 | first. Because this is a wildcard, it 116 | doesn't matter if the user does not 117 | actually link against crtbegin.o; the 118 | linker won't look for a file to match a 119 | wildcard. The wildcard also means that it 120 | doesn't matter which directory crtbegin.o 121 | is in. */ 122 | KEEP (*crtbegin.o(.ctors)) 123 | KEEP (*crtbegin?.o(.ctors)) 124 | /* We don't want to include the .ctor section from 125 | the crtend.o file until after the sorted ctors. 126 | The .ctor section from the crtend file contains the 127 | end of ctors marker and it must be last */ 128 | KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) 129 | KEEP (*(SORT(.ctors.*))) 130 | KEEP (*(.ctors)) 131 | } 132 | .dtors : 133 | { 134 | KEEP (*crtbegin.o(.dtors)) 135 | KEEP (*crtbegin?.o(.dtors)) 136 | KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) 137 | KEEP (*(SORT(.dtors.*))) 138 | KEEP (*(.dtors)) 139 | } 140 | .jcr : { KEEP (*(.jcr)) } 141 | .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } 142 | .dynamic : { *(.dynamic) } 143 | .got : { *(.got) *(.igot) } 144 | . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .); 145 | .got.plt : { *(.got.plt) *(.igot.plt) } 146 | .data : 147 | { 148 | *(.data .data.* .gnu.linkonce.d.*) 149 | SORT(CONSTRUCTORS) 150 | } 151 | .data1 : { *(.data1) } 152 | _edata = .; PROVIDE (edata = .); 153 | . = .; 154 | __bss_start = .; 155 | .bss : 156 | { 157 | *(.dynbss) 158 | *(.bss .bss.* .gnu.linkonce.b.*) 159 | *(COMMON) 160 | /* Align here to ensure that the .bss section occupies space up to 161 | _end. Align after .bss to ensure correct alignment even if the 162 | .bss section disappears because there are no input sections. 163 | FIXME: Why do we need it? When there is no .bss section, we don't 164 | pad the .data section. */ 165 | . = ALIGN(. != 0 ? 64 / 8 : 1); 166 | } 167 | .lbss : 168 | { 169 | *(.dynlbss) 170 | *(.lbss .lbss.* .gnu.linkonce.lb.*) 171 | *(LARGE_COMMON) 172 | } 173 | . = ALIGN(64 / 8); 174 | .lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : 175 | { 176 | *(.lrodata .lrodata.* .gnu.linkonce.lr.*) 177 | } 178 | .ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : 179 | { 180 | *(.ldata .ldata.* .gnu.linkonce.l.*) 181 | . = ALIGN(. != 0 ? 64 / 8 : 1); 182 | } 183 | . = ALIGN(64 / 8); 184 | _end = .; PROVIDE (end = .); 185 | . = DATA_SEGMENT_END (.); 186 | /* Stabs debugging sections. */ 187 | .stab 0 : { *(.stab) } 188 | .stabstr 0 : { *(.stabstr) } 189 | .stab.excl 0 : { *(.stab.excl) } 190 | .stab.exclstr 0 : { *(.stab.exclstr) } 191 | .stab.index 0 : { *(.stab.index) } 192 | .stab.indexstr 0 : { *(.stab.indexstr) } 193 | .comment 0 : { *(.comment) } 194 | /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } 195 | /DISCARD/ : { *(.eh_frame_hdr) } 196 | /DISCARD/ : { *(.eh_frame) } 197 | } 198 | -------------------------------------------------------------------------------- /esp/0x00000.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cnlohr/pylotron/3147cc0a17870d26192613cc93133b9081a9bcaf/esp/0x00000.bin -------------------------------------------------------------------------------- /esp/0x40000.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cnlohr/pylotron/3147cc0a17870d26192613cc93133b9081a9bcaf/esp/0x40000.bin -------------------------------------------------------------------------------- /esp/Makefile: -------------------------------------------------------------------------------- 1 | all : image.elf 2 | FW_FILE_1:=0x00000.bin 3 | FW_FILE_2:=0x40000.bin 4 | 5 | TARGET_OUT:=image.elf 6 | SRCS:=driver/uart.c \ 7 | user/ws2812.c \ 8 | ../cnrfb.c \ 9 | ../fps.c \ 10 | ../mathfuncts.c \ 11 | ../heap.c \ 12 | user/mystuff.c \ 13 | user/user_main.c 14 | 15 | GCC_FOLDER:=~/esp8266/xtensa-toolchain-build/build-lx106 16 | ESPTOOL_PY:=~/esp8266/esptool/esptool.py 17 | FW_TOOL:=~/esp8266/other/esptool/esptool 18 | SDK:=/home/cnlohr/esp8266/esp_iot_sdk_v1.2.0 19 | PORT:=/dev/ttyUSB0 20 | #PORT:=/dev/ttyACM0 21 | 22 | XTLIB:=$(SDK)/lib 23 | XTGCCLIB:=$(GCC_FOLDER)/gcc-4.9.1-elf/xtensa-lx106-elf/libgcc/libgcc.a 24 | FOLDERPREFIX:=$(GCC_FOLDER)/root/bin 25 | PREFIX:=$(FOLDERPREFIX)/xtensa-lx106-elf- 26 | CC:=$(PREFIX)gcc 27 | 28 | CFLAGS:=-DICACHE_FLASH -mlongcalls -I$(SDK)/include -Idriver -Iuser -Os -I$(SDK)/include/ -g -I.. -Wl,--relax -Wl,--gc-sections # -flto 29 | # -flto 30 | 31 | LDFLAGS_CORE:=\ 32 | -nostdlib \ 33 | -L$(XTLIB) \ 34 | -L$(XTGCCLIB) \ 35 | $(SDK)/lib/libmain.a \ 36 | $(SDK)/lib/libnet80211.a \ 37 | $(SDK)/lib/libwpa.a \ 38 | $(SDK)/lib/libupgrade.a \ 39 | $(SDK)/lib/liblwip.a \ 40 | $(SDK)/lib/libpp.a \ 41 | $(SDK)/lib/libssl.a \ 42 | $(SDK)/lib/libphy.a \ 43 | $(SDK)/lib/libnet80211.a \ 44 | $(SDK)/lib/libwpa.a \ 45 | $(XTGCCLIB) \ 46 | -T $(SDK)/ld/eagle.app.v6.ld 47 | 48 | LINKFLAGS:= \ 49 | $(LDFLAGS_CORE) \ 50 | -B$(XTLIB) 51 | 52 | #image.elf : $(OBJS) 53 | # $(PREFIX)ld $^ $(LDFLAGS) -o $@ 54 | 55 | $(TARGET_OUT) : $(SRCS) 56 | $(PREFIX)gcc $(CFLAGS) -o $@ $^ $(LINKFLAGS) 57 | 58 | 59 | 60 | $(FW_FILE_1): $(TARGET_OUT) 61 | @echo "FW $@" 62 | $(FW_TOOL) -eo $(TARGET_OUT) -bo $@ -bs .text -bs .data -bs .rodata -bc -ec 63 | 64 | $(FW_FILE_2): $(TARGET_OUT) 65 | @echo "FW $@" 66 | $(FW_TOOL) -eo $(TARGET_OUT) -es .irom0.text $@ -ec 67 | 68 | burn : $(FW_FILE_1) $(FW_FILE_2) 69 | ($(ESPTOOL_PY) --port $(PORT) write_flash 0x00000 0x00000.bin 0x40000 0x40000.bin)||(true) 70 | 71 | 72 | clean : 73 | rm -rf user/*.o driver/*.o $(TARGET_OUT) $(FW_FILE_1) $(FW_FILE_2) program.map program.lst image.map 74 | 75 | 76 | -------------------------------------------------------------------------------- /esp/driver/uart.c: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright 2013-2014 Espressif Systems (Wuxi) 3 | * 4 | * FileName: uart.c 5 | * 6 | * Description: Two UART mode configration and interrupt handler. 7 | * Check your hardware connection while use this mode. 8 | * 9 | * Modification history: 10 | * 2014/3/12, v1.0 create this file. 11 | *******************************************************************************/ 12 | #include 13 | #include 14 | #include "uart.h" 15 | 16 | // UartDev is defined and initialized in rom code. 17 | extern UartDevice UartDev; 18 | //extern os_event_t at_recvTaskQueue[at_recvTaskQueueLen]; 19 | 20 | void GotSerialByte( char c ); 21 | LOCAL void uart0_rx_intr_handler(void *para); 22 | 23 | /****************************************************************************** 24 | * FunctionName : uart_config 25 | * Description : Internal used function 26 | * UART0 used for data TX/RX, RX buffer size is 0x100, interrupt enabled 27 | * UART1 just used for debug output 28 | * Parameters : uart_no, use UART0 or UART1 defined ahead 29 | * Returns : NONE 30 | *******************************************************************************/ 31 | LOCAL void ICACHE_FLASH_ATTR 32 | uart_config(uint8 uart_no) 33 | { 34 | if (uart_no == UART1) 35 | { 36 | PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK); 37 | } 38 | else 39 | { 40 | /* rcv_buff size if 0x100 */ 41 | ETS_UART_INTR_ATTACH(uart0_rx_intr_handler, &(UartDev.rcv_buff)); 42 | PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U); 43 | PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD); 44 | // PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_U0RTS); 45 | } 46 | 47 | uart_div_modify(uart_no, UART_CLK_FREQ / (UartDev.baut_rate)); 48 | 49 | WRITE_PERI_REG(UART_CONF0(uart_no), UartDev.exist_parity 50 | | UartDev.parity 51 | | (UartDev.stop_bits << UART_STOP_BIT_NUM_S) 52 | | (UartDev.data_bits << UART_BIT_NUM_S)); 53 | 54 | //clear rx and tx fifo,not ready 55 | SET_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST); 56 | CLEAR_PERI_REG_MASK(UART_CONF0(uart_no), UART_RXFIFO_RST | UART_TXFIFO_RST); 57 | 58 | //set rx fifo trigger 59 | // WRITE_PERI_REG(UART_CONF1(uart_no), 60 | // ((UartDev.rcv_buff.TrigLvl & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) | 61 | // ((96 & UART_TXFIFO_EMPTY_THRHD) << UART_TXFIFO_EMPTY_THRHD_S) | 62 | // UART_RX_FLOW_EN); 63 | if (uart_no == UART0) 64 | { 65 | //set rx fifo trigger 66 | WRITE_PERI_REG(UART_CONF1(uart_no), 67 | ((0x01 & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S) | 68 | ((0x01 & UART_RX_FLOW_THRHD) << UART_RX_FLOW_THRHD_S) | 69 | UART_RX_FLOW_EN); 70 | } 71 | else 72 | { 73 | WRITE_PERI_REG(UART_CONF1(uart_no), 74 | ((UartDev.rcv_buff.TrigLvl & UART_RXFIFO_FULL_THRHD) << UART_RXFIFO_FULL_THRHD_S)); 75 | } 76 | 77 | //clear all interrupt 78 | WRITE_PERI_REG(UART_INT_CLR(uart_no), 0xffff); 79 | //enable rx_interrupt 80 | SET_PERI_REG_MASK(UART_INT_ENA(uart_no), UART_RXFIFO_FULL_INT_ENA); 81 | } 82 | 83 | /****************************************************************************** 84 | * FunctionName : uart1_tx_one_char 85 | * Description : Internal used function 86 | * Use uart1 interface to transfer one char 87 | * Parameters : uint8 TxChar - character to tx 88 | * Returns : OK 89 | *******************************************************************************/ 90 | LOCAL STATUS 91 | uart_tx_one_char(uint8 uart, uint8 TxChar) 92 | { 93 | while (true) 94 | { 95 | uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(uart)) & (UART_TXFIFO_CNT<> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) < 126) { 97 | break; 98 | } 99 | } 100 | 101 | WRITE_PERI_REG(UART_FIFO(uart) , TxChar); 102 | return OK; 103 | } 104 | 105 | /****************************************************************************** 106 | * FunctionName : uart1_write_char 107 | * Description : Internal used function 108 | * Do some special deal while tx char is '\r' or '\n' 109 | * Parameters : char c - character to tx 110 | * Returns : NONE 111 | *******************************************************************************/ 112 | LOCAL void ICACHE_FLASH_ATTR 113 | uart1_write_char(char c) 114 | { 115 | if (c == '\n') 116 | { 117 | uart_tx_one_char(UART1, '\r'); 118 | uart_tx_one_char(UART1, '\n'); 119 | } 120 | else if (c == '\r') 121 | { 122 | } 123 | else 124 | { 125 | uart_tx_one_char(UART1, c); 126 | } 127 | } 128 | /****************************************************************************** 129 | * FunctionName : uart0_tx_buffer 130 | * Description : use uart0 to transfer buffer 131 | * Parameters : uint8 *buf - point to send buffer 132 | * uint16 len - buffer len 133 | * Returns : 134 | *******************************************************************************/ 135 | void ICACHE_FLASH_ATTR 136 | uart0_tx_buffer(uint8 *buf, uint16 len) 137 | { 138 | uint16 i; 139 | 140 | for (i = 0; i < len; i++) 141 | { 142 | uart_tx_one_char(UART0, buf[i]); 143 | } 144 | } 145 | 146 | /****************************************************************************** 147 | * FunctionName : uart0_sendStr 148 | * Description : use uart0 to transfer buffer 149 | * Parameters : uint8 *buf - point to send buffer 150 | * uint16 len - buffer len 151 | * Returns : 152 | *******************************************************************************/ 153 | void ICACHE_FLASH_ATTR 154 | uart0_sendStr(const char *str) 155 | { 156 | while(*str) 157 | { 158 | uart_tx_one_char(UART0, *str++); 159 | } 160 | } 161 | 162 | /****************************************************************************** 163 | * FunctionName : uart0_rx_intr_handler 164 | * Description : Internal used function 165 | * UART0 interrupt handler, add self handle code inside 166 | * Parameters : void *para - point to ETS_UART_INTR_ATTACH's arg 167 | * Returns : NONE 168 | *******************************************************************************/ 169 | //extern void at_recvTask(void); 170 | 171 | LOCAL void 172 | uart0_rx_intr_handler(void *para) 173 | { 174 | static uint8_t history[4]; 175 | static uint8_t hhead; 176 | uint8 uart_no = UART0;//UartDev.buff_uart_no; 177 | 178 | if (UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST)) 179 | { 180 | WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_RXFIFO_FULL_INT_CLR); 181 | } 182 | 183 | // WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_RXFIFO_FULL_INT_CLR); 184 | 185 | if (READ_PERI_REG(UART_STATUS(uart_no)) & (UART_RXFIFO_CNT << UART_RXFIFO_CNT_S)) 186 | { 187 | volatile uint8_t v = READ_PERI_REG(UART_FIFO(uart_no)) & 0xFF; 188 | WRITE_PERI_REG(UART_INT_CLR(uart_no), UART_RXFIFO_FULL_INT_CLR); 189 | 190 | history[hhead++] = v; 191 | if( hhead > 3 ) hhead = 0; 192 | 193 | //Detect a request to reboot into bootloader. 194 | if( history[hhead&3] == 0xc2 && history[(hhead+1)&3] == 0x42 && history[(hhead+2)&3] == 0x56 && history[(hhead+3)&3] == 0xff ) 195 | { 196 | system_restart(); 197 | } 198 | 199 | 200 | GotSerialByte( v ); 201 | } 202 | } 203 | 204 | /****************************************************************************** 205 | * FunctionName : uart_init 206 | * Description : user interface for init uart 207 | * Parameters : UartBautRate uart0_br - uart0 bautrate 208 | * UartBautRate uart1_br - uart1 bautrate 209 | * Returns : NONE 210 | *******************************************************************************/ 211 | void ICACHE_FLASH_ATTR 212 | uart_init(UartBautRate uart0_br, UartBautRate uart1_br) 213 | { 214 | // rom use 74880 baut_rate, here reinitialize 215 | UartDev.baut_rate = uart0_br; 216 | uart_config(UART0); 217 | UartDev.baut_rate = uart1_br; 218 | uart_config(UART1); 219 | ETS_UART_INTR_ENABLE(); 220 | 221 | // install uart1 putc callback 222 | os_install_putc1((void *)uart1_write_char); 223 | } 224 | 225 | void ICACHE_FLASH_ATTR 226 | uart_reattach() 227 | { 228 | uart_init(BIT_RATE_74880, BIT_RATE_74880); 229 | // ETS_UART_INTR_ATTACH(uart_rx_intr_handler_ssc, &(UartDev.rcv_buff)); 230 | // ETS_UART_INTR_ENABLE(); 231 | } 232 | -------------------------------------------------------------------------------- /esp/driver/uart.h: -------------------------------------------------------------------------------- 1 | #ifndef UART_APP_H 2 | #define UART_APP_H 3 | 4 | #include "eagle_soc.h" 5 | #include "c_types.h" 6 | 7 | //Generated at 2012-07-03 18:44:06 8 | /* 9 | * Copyright (c) 2010 - 2011 Espressif System 10 | * 11 | */ 12 | 13 | #ifndef UART_REGISTER_H_INCLUDED 14 | #define UART_REGISTER_H_INCLUDED 15 | #define REG_UART_BASE( i ) (0x60000000+(i)*0xf00) 16 | //version value:32'h062000 17 | 18 | #define UART_FIFO( i ) (REG_UART_BASE( i ) + 0x0) 19 | #define UART_RXFIFO_RD_BYTE 0x000000FF 20 | #define UART_RXFIFO_RD_BYTE_S 0 21 | 22 | #define UART_INT_RAW( i ) (REG_UART_BASE( i ) + 0x4) 23 | #define UART_RXFIFO_TOUT_INT_RAW (BIT(8)) 24 | #define UART_BRK_DET_INT_RAW (BIT(7)) 25 | #define UART_CTS_CHG_INT_RAW (BIT(6)) 26 | #define UART_DSR_CHG_INT_RAW (BIT(5)) 27 | #define UART_RXFIFO_OVF_INT_RAW (BIT(4)) 28 | #define UART_FRM_ERR_INT_RAW (BIT(3)) 29 | #define UART_PARITY_ERR_INT_RAW (BIT(2)) 30 | #define UART_TXFIFO_EMPTY_INT_RAW (BIT(1)) 31 | #define UART_RXFIFO_FULL_INT_RAW (BIT(0)) 32 | 33 | #define UART_INT_ST( i ) (REG_UART_BASE( i ) + 0x8) 34 | #define UART_RXFIFO_TOUT_INT_ST (BIT(8)) 35 | #define UART_BRK_DET_INT_ST (BIT(7)) 36 | #define UART_CTS_CHG_INT_ST (BIT(6)) 37 | #define UART_DSR_CHG_INT_ST (BIT(5)) 38 | #define UART_RXFIFO_OVF_INT_ST (BIT(4)) 39 | #define UART_FRM_ERR_INT_ST (BIT(3)) 40 | #define UART_PARITY_ERR_INT_ST (BIT(2)) 41 | #define UART_TXFIFO_EMPTY_INT_ST (BIT(1)) 42 | #define UART_RXFIFO_FULL_INT_ST (BIT(0)) 43 | 44 | #define UART_INT_ENA( i ) (REG_UART_BASE( i ) + 0xC) 45 | #define UART_RXFIFO_TOUT_INT_ENA (BIT(8)) 46 | #define UART_BRK_DET_INT_ENA (BIT(7)) 47 | #define UART_CTS_CHG_INT_ENA (BIT(6)) 48 | #define UART_DSR_CHG_INT_ENA (BIT(5)) 49 | #define UART_RXFIFO_OVF_INT_ENA (BIT(4)) 50 | #define UART_FRM_ERR_INT_ENA (BIT(3)) 51 | #define UART_PARITY_ERR_INT_ENA (BIT(2)) 52 | #define UART_TXFIFO_EMPTY_INT_ENA (BIT(1)) 53 | #define UART_RXFIFO_FULL_INT_ENA (BIT(0)) 54 | 55 | #define UART_INT_CLR( i ) (REG_UART_BASE( i ) + 0x10) 56 | #define UART_RXFIFO_TOUT_INT_CLR (BIT(8)) 57 | #define UART_BRK_DET_INT_CLR (BIT(7)) 58 | #define UART_CTS_CHG_INT_CLR (BIT(6)) 59 | #define UART_DSR_CHG_INT_CLR (BIT(5)) 60 | #define UART_RXFIFO_OVF_INT_CLR (BIT(4)) 61 | #define UART_FRM_ERR_INT_CLR (BIT(3)) 62 | #define UART_PARITY_ERR_INT_CLR (BIT(2)) 63 | #define UART_TXFIFO_EMPTY_INT_CLR (BIT(1)) 64 | #define UART_RXFIFO_FULL_INT_CLR (BIT(0)) 65 | 66 | #define UART_CLKDIV( i ) (REG_UART_BASE( i ) + 0x14) 67 | #define UART_CLKDIV_CNT 0x000FFFFF 68 | #define UART_CLKDIV_S 0 69 | 70 | #define UART_AUTOBAUD( i ) (REG_UART_BASE( i ) + 0x18) 71 | #define UART_GLITCH_FILT 0x000000FF 72 | #define UART_GLITCH_FILT_S 8 73 | #define UART_AUTOBAUD_EN (BIT(0)) 74 | 75 | #define UART_STATUS( i ) (REG_UART_BASE( i ) + 0x1C) 76 | #define UART_TXD (BIT(31)) 77 | #define UART_RTSN (BIT(30)) 78 | #define UART_DTRN (BIT(29)) 79 | #define UART_TXFIFO_CNT 0x000000FF 80 | #define UART_TXFIFO_CNT_S 16 81 | #define UART_RXD (BIT(15)) 82 | #define UART_CTSN (BIT(14)) 83 | #define UART_DSRN (BIT(13)) 84 | #define UART_RXFIFO_CNT 0x000000FF 85 | #define UART_RXFIFO_CNT_S 0 86 | 87 | #define UART_CONF0( i ) (REG_UART_BASE( i ) + 0x20) 88 | #define UART_TXFIFO_RST (BIT(18)) 89 | #define UART_RXFIFO_RST (BIT(17)) 90 | #define UART_IRDA_EN (BIT(16)) 91 | #define UART_TX_FLOW_EN (BIT(15)) 92 | #define UART_LOOPBACK (BIT(14)) 93 | #define UART_IRDA_RX_INV (BIT(13)) 94 | #define UART_IRDA_TX_INV (BIT(12)) 95 | #define UART_IRDA_WCTL (BIT(11)) 96 | #define UART_IRDA_TX_EN (BIT(10)) 97 | #define UART_IRDA_DPLX (BIT(9)) 98 | #define UART_TXD_BRK (BIT(8)) 99 | #define UART_SW_DTR (BIT(7)) 100 | #define UART_SW_RTS (BIT(6)) 101 | #define UART_STOP_BIT_NUM 0x00000003 102 | #define UART_STOP_BIT_NUM_S 4 103 | #define UART_BIT_NUM 0x00000003 104 | #define UART_BIT_NUM_S 2 105 | #define UART_PARITY_EN (BIT(1)) 106 | #define UART_PARITY (BIT(0)) 107 | 108 | #define UART_CONF1( i ) (REG_UART_BASE( i ) + 0x24) 109 | #define UART_RX_TOUT_EN (BIT(31)) 110 | #define UART_RX_TOUT_THRHD 0x0000007F 111 | #define UART_RX_TOUT_THRHD_S 24 112 | #define UART_RX_FLOW_EN (BIT(23)) 113 | #define UART_RX_FLOW_THRHD 0x0000007F 114 | #define UART_RX_FLOW_THRHD_S 16 115 | #define UART_TXFIFO_EMPTY_THRHD 0x0000007F 116 | #define UART_TXFIFO_EMPTY_THRHD_S 8 117 | #define UART_RXFIFO_FULL_THRHD 0x0000007F 118 | #define UART_RXFIFO_FULL_THRHD_S 0 119 | 120 | #define UART_LOWPULSE( i ) (REG_UART_BASE( i ) + 0x28) 121 | #define UART_LOWPULSE_MIN_CNT 0x000FFFFF 122 | #define UART_LOWPULSE_MIN_CNT_S 0 123 | 124 | #define UART_HIGHPULSE( i ) (REG_UART_BASE( i ) + 0x2C) 125 | #define UART_HIGHPULSE_MIN_CNT 0x000FFFFF 126 | #define UART_HIGHPULSE_MIN_CNT_S 0 127 | 128 | #define UART_PULSE_NUM( i ) (REG_UART_BASE( i ) + 0x30) 129 | #define UART_PULSE_NUM_CNT 0x0003FF 130 | #define UART_PULSE_NUM_CNT_S 0 131 | 132 | #define UART_DATE( i ) (REG_UART_BASE( i ) + 0x78) 133 | #define UART_ID( i ) (REG_UART_BASE( i ) + 0x7C) 134 | #endif // UART_REGISTER_H_INCLUDED 135 | 136 | 137 | 138 | #define RX_BUFF_SIZE 256 139 | #define TX_BUFF_SIZE 100 140 | #define UART0 0 141 | #define UART1 1 142 | 143 | typedef enum { 144 | FIVE_BITS = 0x0, 145 | SIX_BITS = 0x1, 146 | SEVEN_BITS = 0x2, 147 | EIGHT_BITS = 0x3 148 | } UartBitsNum4Char; 149 | 150 | typedef enum { 151 | ONE_STOP_BIT = 0, 152 | ONE_HALF_STOP_BIT = BIT2, 153 | TWO_STOP_BIT = BIT2 154 | } UartStopBitsNum; 155 | 156 | typedef enum { 157 | NONE_BITS = 0, 158 | ODD_BITS = 0, 159 | EVEN_BITS = BIT4 160 | } UartParityMode; 161 | 162 | typedef enum { 163 | STICK_PARITY_DIS = 0, 164 | STICK_PARITY_EN = BIT3 | BIT5 165 | } UartExistParity; 166 | 167 | typedef enum { 168 | BIT_RATE_9600 = 9600, 169 | BIT_RATE_19200 = 19200, 170 | BIT_RATE_38400 = 38400, 171 | BIT_RATE_57600 = 57600, 172 | BIT_RATE_74880 = 74880, 173 | BIT_RATE_115200 = 115200, 174 | BIT_RATE_230400 = 230400, 175 | BIT_RATE_460800 = 460800, 176 | BIT_RATE_921600 = 921600 177 | } UartBautRate; 178 | 179 | typedef enum { 180 | NONE_CTRL, 181 | HARDWARE_CTRL, 182 | XON_XOFF_CTRL 183 | } UartFlowCtrl; 184 | 185 | typedef enum { 186 | EMPTY, 187 | UNDER_WRITE, 188 | WRITE_OVER 189 | } RcvMsgBuffState; 190 | 191 | typedef struct { 192 | uint32 RcvBuffSize; 193 | uint8 *pRcvMsgBuff; 194 | uint8 *pWritePos; 195 | uint8 *pReadPos; 196 | uint8 TrigLvl; //JLU: may need to pad 197 | RcvMsgBuffState BuffState; 198 | } RcvMsgBuff; 199 | 200 | typedef struct { 201 | uint32 TrxBuffSize; 202 | uint8 *pTrxBuff; 203 | } TrxMsgBuff; 204 | 205 | typedef enum { 206 | BAUD_RATE_DET, 207 | WAIT_SYNC_FRM, 208 | SRCH_MSG_HEAD, 209 | RCV_MSG_BODY, 210 | RCV_ESC_CHAR, 211 | } RcvMsgState; 212 | 213 | typedef struct { 214 | UartBautRate baut_rate; 215 | UartBitsNum4Char data_bits; 216 | UartExistParity exist_parity; 217 | UartParityMode parity; // chip size in byte 218 | UartStopBitsNum stop_bits; 219 | UartFlowCtrl flow_ctrl; 220 | RcvMsgBuff rcv_buff; 221 | TrxMsgBuff trx_buff; 222 | RcvMsgState rcv_state; 223 | int received; 224 | int buff_uart_no; //indicate which uart use tx/rx buffer 225 | } UartDevice; 226 | 227 | void uart_init(UartBautRate uart0_br, UartBautRate uart1_br); 228 | void uart0_sendStr(const char *str); 229 | 230 | #endif 231 | 232 | -------------------------------------------------------------------------------- /esp/user/mystuff.c: -------------------------------------------------------------------------------- 1 | #include "mystuff.h" 2 | 3 | char generic_print_buffer[384]; 4 | 5 | 6 | void user_rf_pre_init(void) 7 | { 8 | //nothing. 9 | } 10 | 11 | 12 | char * strcat( char * dest, char * src ) 13 | { 14 | return strcat(dest, src ); 15 | } 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /esp/user/mystuff.h: -------------------------------------------------------------------------------- 1 | #ifndef _MYSTUFF_H 2 | #define _MYSTUFF_H 3 | 4 | extern char generic_print_buffer[384]; 5 | 6 | #define printf( ... ) ets_sprintf( generic_print_buffer, __VA_ARGS__ ); uart0_sendStr( generic_print_buffer ); 7 | #define sprintf ets_sprintf 8 | #define memset ets_memset 9 | #define memcpy ets_memcpy 10 | #define strlen ets_strlen 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /esp/user/stdint.h: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /esp/user/stdio.h: -------------------------------------------------------------------------------- 1 | #include "mystuff.h" 2 | 3 | -------------------------------------------------------------------------------- /esp/user/string.h: -------------------------------------------------------------------------------- 1 | //Nothing here. 2 | -------------------------------------------------------------------------------- /esp/user/user_config.h: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /esp/user/user_main.c: -------------------------------------------------------------------------------- 1 | #include "mem.h" 2 | #include "fps.h" 3 | #include "c_types.h" 4 | #include "user_interface.h" 5 | #include "ets_sys.h" 6 | #include 7 | #include "osapi.h" 8 | #include "espconn.h" 9 | #include "mystuff.h" 10 | #include 11 | 12 | void ICACHE_FLASH_ATTR SocketInit(); 13 | 14 | #define procTaskPrio 0 15 | #define procTaskQueueLen 1 16 | 17 | static struct espconn *prfbServer; 18 | 19 | static volatile os_timer_t interval_timer; 20 | 21 | //Tasks that happen all the time. 22 | os_event_t procTaskQueue[procTaskQueueLen]; 23 | 24 | static void ICACHE_FLASH_ATTR 25 | procTask(os_event_t *events) 26 | { 27 | system_os_post(procTaskPrio, 0, 0 ); 28 | if( events->sig == 0 && events->par == 0 ) 29 | { 30 | CNRFBTick( 0 ); 31 | UpdateEvent( 0 ); 32 | } 33 | } 34 | 35 | uint8_t outbuffer[32*3]; 36 | 37 | //Timer event. 38 | static void //ICACHE_FLASH_ATTR 39 | myTimer(void *arg) 40 | { 41 | int i, j; 42 | static int update; 43 | uart0_sendStr("."); 44 | update++; 45 | 46 | 47 | #define LEDSPERSEG 1 48 | 49 | //Do this since we don't want to update it every single time. 50 | switch( update & 0x0f ) 51 | { 52 | case 0: 53 | for( i = 0; i < 8; i++ ) 54 | { 55 | uint8_t pc = PlayerColors[i]; 56 | struct FPS * f = &FPSs[i]; 57 | 58 | uint8_t red = (pc & 0x07)<<5; 59 | uint8_t green = (pc & 0x38)<<2; 60 | uint8_t blue = (pc & 0xc0); 61 | if( !f->in_use ) 62 | { 63 | red>>=3; 64 | green>>=3; 65 | blue>>=3; 66 | } 67 | 68 | 69 | int rank = (LEDSPERSEG*7)-f->rank*LEDSPERSEG; 70 | if( rank < 0 ) rank = 0; 71 | if( rank >= 31 ) rank = 31; 72 | for( j = 0; j < LEDSPERSEG; j++ ) 73 | { 74 | outbuffer[rank*3+1] = red; 75 | outbuffer[rank*3+0] = green; 76 | outbuffer[rank*3+2] = blue; 77 | rank++; 78 | } 79 | } 80 | break; 81 | case 3: 82 | WS2812OutBuffer( outbuffer, 8*3*LEDSPERSEG ); 83 | } 84 | 85 | CNRFBTick( 1 ); 86 | UpdateEvent( 1 ); 87 | 88 | } 89 | 90 | void ICACHE_FLASH_ATTR 91 | GotSerialByte( char c ) 92 | { 93 | } 94 | 95 | void ICACHE_FLASH_ATTR 96 | user_init(void) 97 | { 98 | WS2812OutBuffer( "\x1f\x1f\x1f", 3 ); 99 | 100 | uart_init(BIT_RATE_115200, BIT_RATE_115200); 101 | uart0_sendStr("\r\nCustom Server\r\n"); 102 | wifi_station_dhcpc_start(); 103 | 104 | //Add a process 105 | system_os_task(procTask, procTaskPrio, procTaskQueue, procTaskQueueLen); 106 | 107 | uart0_sendStr("\r\nCustom Server\r\n"); 108 | 109 | //Timer example 110 | os_timer_disarm(&interval_timer); 111 | os_timer_setfn(&interval_timer, (os_timer_func_t *)myTimer, NULL); 112 | os_timer_arm(&interval_timer, 20, 1); //50 Hz. 113 | 114 | WS2812OutBuffer( "\x1f\x1f\x00", 3 ); 115 | 116 | //Hook for initialization 117 | SocketInit(); 118 | CNRFBInit(); 119 | ToolStart(); 120 | 121 | 122 | system_os_post(procTaskPrio, 0, 0 ); 123 | } 124 | 125 | 126 | 127 | 128 | 129 | ///After here is the TCP/IP Interface 130 | 131 | static struct espconn * ESPSockets[MAX_RFB_CONNS]; 132 | 133 | LOCAL uint8_t * readbuffer; 134 | LOCAL uint16_t readbufferpos; 135 | LOCAL uint16_t readbuffersize; 136 | 137 | LOCAL uint8_t sendbuffer[1536]; 138 | LOCAL uint16_t sendptr; 139 | LOCAL int sendconn; 140 | 141 | void CNRFBDump( int i ) 142 | { 143 | readbufferpos += i; 144 | } 145 | 146 | 147 | int ICACHE_FLASH_ATTR CNRFBCanSendData( int sock ) 148 | { 149 | 150 | struct espconn * conn = ESPSockets[sock]; 151 | struct espconn_packet infoarg; 152 | sint8 r = espconn_get_packet_info(conn, &infoarg); 153 | if( infoarg.snd_queuelen < 2 ) 154 | { 155 | //This actually doesn't happen unless there's a fault. 156 | CNRFBConnectionWasClosed( sock ); 157 | return 0; 158 | } 159 | if( infoarg.snd_buf_size < 1536 ) 160 | { 161 | printf( "BU\n" ); 162 | return 0; 163 | } 164 | 165 | return 1; 166 | } 167 | 168 | int ICACHE_FLASH_ATTR CNRFBStartSend( int conn ) 169 | { 170 | if( !CNRFBCanSendData( conn ) ) 171 | { 172 | return -1; 173 | } 174 | 175 | sendconn = conn; 176 | 177 | sendptr = 0; 178 | } 179 | 180 | void ICACHE_FLASH_ATTR CNRFBSendData( const uint8_t * data, int len ) 181 | { 182 | memcpy( sendbuffer + sendptr, data, len ); 183 | sendptr += len; 184 | } 185 | 186 | void CNRFBSend1( uint8_t data ) 187 | { 188 | sendbuffer[sendptr++] = data; 189 | } 190 | 191 | void CNRFBSend2( uint16_t data ) 192 | { 193 | sendbuffer[sendptr++] = data>>8; 194 | sendbuffer[sendptr++] = data; 195 | } 196 | 197 | void CNRFBSend4( uint32_t data ) 198 | { 199 | sendbuffer[sendptr++] = data>>24; 200 | sendbuffer[sendptr++] = data>>16; 201 | sendbuffer[sendptr++] = data>>8; 202 | sendbuffer[sendptr++] = data; 203 | } 204 | 205 | void ICACHE_FLASH_ATTR CNRFBEndSend( ) 206 | { 207 | if( sendconn >= 0 && sendptr ) 208 | { 209 | espconn_sent(ESPSockets[sendconn],sendbuffer,sendptr); 210 | } 211 | } 212 | 213 | 214 | void ICACHE_FLASH_ATTR CNRFBCloseConnection( int conn ) 215 | { 216 | int i; 217 | DisconnectEvent( conn ); 218 | espconn_disconnect( ESPSockets[conn] ); 219 | ESPSockets[conn] = 0; 220 | } 221 | 222 | 223 | int CNRFBReadRemain() 224 | { 225 | return readbuffersize - readbufferpos; 226 | } 227 | 228 | uint8_t CNRFBRead1() 229 | { 230 | if( readbufferpos + 1 > readbuffersize ) return 0; 231 | return readbuffer[readbufferpos++]; 232 | } 233 | 234 | uint16_t CNRFBRead2() 235 | { 236 | uint16_t r; 237 | if( readbufferpos + 2 > readbuffersize ) return 0; 238 | r = readbuffer[readbufferpos++]; 239 | r = (r<<8) | readbuffer[readbufferpos++]; 240 | return r; 241 | } 242 | 243 | uint32_t CNRFBRead4() 244 | { 245 | uint32_t r; 246 | if( readbufferpos + 4 > readbuffersize ) return 0; 247 | r = readbuffer[readbufferpos++]; 248 | r = (r<<8) | readbuffer[readbufferpos++]; 249 | r = (r<<8) | readbuffer[readbufferpos++]; 250 | r = (r<<8) | readbuffer[readbufferpos++]; 251 | return r; 252 | } 253 | 254 | 255 | 256 | 257 | LOCAL void ICACHE_FLASH_ATTR rfb_disconnetcb(void *arg) 258 | { 259 | struct espconn *pespconn = (struct espconn *) arg; 260 | 261 | int st = (int)pespconn->reverse; 262 | 263 | CNRFBConnectionWasClosed( st ); 264 | } 265 | 266 | LOCAL void ICACHE_FLASH_ATTR rfb_recvcb(void *arg, char *pusrdata, unsigned short length) 267 | { 268 | struct espconn *pespconn = (struct espconn *) arg; 269 | int st = (int)pespconn->reverse; 270 | 271 | readbuffer = (uint8_t*)pusrdata; 272 | readbufferpos = 0; 273 | readbuffersize = length; 274 | 275 | CNRFBGotData( st, length ); 276 | } 277 | 278 | void ICACHE_FLASH_ATTR rfbserver_connectcb(void *arg) 279 | { 280 | int i; 281 | struct espconn *pespconn = (struct espconn *)arg; 282 | 283 | int r = CNRFBNewConnection(); 284 | if( r >= MAX_RFB_CONNS || r < 0 ) 285 | { 286 | espconn_disconnect( pespconn ); 287 | return; 288 | } 289 | 290 | pespconn->reverse = (void*)r; 291 | ESPSockets[r] = pespconn; 292 | ConnectEvent( r ); 293 | 294 | espconn_regist_recvcb( pespconn, rfb_recvcb ); 295 | espconn_regist_disconcb( pespconn, rfb_disconnetcb ); 296 | } 297 | 298 | void ICACHE_FLASH_ATTR SocketInit() 299 | { 300 | espconn_tcp_set_max_con( 9 ); 301 | prfbServer = (struct espconn *)os_zalloc(sizeof(struct espconn)); 302 | ets_memset( prfbServer, 0, sizeof( struct espconn ) ); 303 | espconn_create( prfbServer ); 304 | prfbServer->type = ESPCONN_TCP; 305 | prfbServer->state = ESPCONN_NONE; 306 | prfbServer->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp)); 307 | prfbServer->proto.tcp->local_port = 5900; 308 | espconn_regist_connectcb(prfbServer, rfbserver_connectcb); 309 | espconn_accept(prfbServer); 310 | espconn_regist_time(prfbServer, 15, 0); //timeout 311 | // espconn_tcp_set_max_con_allow(prfbServer,8); //??? 312 | } 313 | 314 | 315 | -------------------------------------------------------------------------------- /esp/user/ws2812.c: -------------------------------------------------------------------------------- 1 | #include "ws2812.h" 2 | #include "ets_sys.h" 3 | #include "mystuff.h" 4 | #include "osapi.h" 5 | 6 | #define GPIO_OUTPUT_SET(gpio_no, bit_value) \ 7 | gpio_output_set(bit_value<>= 1; 41 | } 42 | } 43 | 44 | ets_intr_unlock(); 45 | } 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /esp/user/ws2812.h: -------------------------------------------------------------------------------- 1 | #ifndef _WS2812_H 2 | #define _WS2812_H 3 | 4 | #define WSGPIO 0 5 | 6 | #include "c_types.h" 7 | #include "user_interface.h" 8 | #include "ets_sys.h" 9 | #include "gpio.h" 10 | 11 | //You will have to os_intr_lock(); os_intr_unlock(); 12 | 13 | void WS2812OutBuffer( uint8_t * buffer, uint16_t length ); 14 | 15 | #endif 16 | 17 | -------------------------------------------------------------------------------- /font.h: -------------------------------------------------------------------------------- 1 | #define FONT_CHAR_W 8 2 | #define FONT_CHAR_H 16 3 | 4 | const unsigned short font_pieces[1564] = { 5 | 0x17d0, 0x7030, 0x7037, 0x0521, 0x05b1, 0x0372, 0x1173, 0x0042, 0x0045, 0x2591, 0x1750, 0x1521, 0x7130, 0x7136, 0x2123, 0x0280, 6 | 0x0085, 0x3650, 0x5252, 0x5141, 0x5144, 0x6053, 0x4252, 0x2461, 0x6043, 0x0670, 0x2260, 0x2265, 0x1342, 0x2193, 0x0133, 0x03b2, 7 | 0x3551, 0x8133, 0x1760, 0x0342, 0x03b2, 0x3163, 0x1372, 0x5700, 0x57a0, 0x9100, 0x9106, 0x6200, 0x6005, 0x0290, 0x0095, 0x0352, 8 | 0x3061, 0x3066, 0x03a2, 0x1052, 0x1055, 0x0191, 0x0095, 0x4700, 0x47b0, 0x3163, 0xa000, 0xa007, 0x1372, 0x5100, 0x5006, 0x01a0, 9 | 0x00a6, 0x3170, 0x3174, 0x1224, 0x1152, 0x03b1, 0x3026, 0x0143, 0x0361, 0x0023, 0x4173, 0x3131, 0x3135, 0x0322, 0x0591, 0x0372, 10 | 0x8122, 0x2126, 0x12a0, 0x0322, 0x0342, 0x0091, 0x9121, 0x8126, 0x2195, 0x21a0, 0x0421, 0x0441, 0x3133, 0x3183, 0x2062, 0x2065, 11 | 0x0150, 0x0156, 0x0170, 0x0275, 0x0190, 0x0196, 0x6230, 0x2450, 0xa010, 0x8120, 0x4340, 0x0660, 0x6234, 0x2152, 0xa016, 0x8025, 12 | 0x4043, 0x0160, 0x8123, 0x1332, 0x0581, 0x0541, 0x1382, 0x6121, 0x6125, 0x11a1, 0x11a5, 0x9123, 0x9126, 0x2130, 0x0421, 0x0161, 13 | 0x0411, 0x04c1, 0x3051, 0x3055, 0x2032, 0x2084, 0x2011, 0x0125, 0x0242, 0x1060, 0x1165, 0x1082, 0x10a5, 0x01b0, 0x0020, 0x1044, 14 | 0x0192, 0x01b5, 0x3680, 0x9123, 0x1332, 0x0581, 0x05b1, 0x0541, 0x1382, 0x9123, 0x1332, 0x0541, 0x9123, 0x0591, 0x1392, 0x0670, 15 | 0x4054, 0x2164, 0x0053, 0x0093, 0x0670, 0x4052, 0x2061, 0x0152, 0x0192, 0x3160, 0x0690, 0x0770, 0x4052, 0x4055, 0x2061, 0x2165, 16 | 0x3471, 0x1252, 0x1690, 0x0043, 0x3441, 0x5242, 0x1640, 0x6043, 0x6123, 0x2332, 0x11a3, 0x2111, 0x2115, 0x3012, 0x3015, 0x8131, 17 | 0x8134, 0x0650, 0x0690, 0x3175, 0x2103, 0x2130, 0x21b3, 0x0461, 0x0421, 0x04b1, 0x0135, 0x1090, 0x1036, 0x01a0, 0x1140, 0x11a5, 18 | 0x1046, 0x1055, 0x1064, 0x1073, 0x1082, 0x1091, 0x10a0, 0x3170, 0x3174, 0x4022, 0x3024, 0x2053, 0x02b1, 0x1031, 0x1134, 0x0165, 19 | 0x01b5, 0x0122, 0x0061, 0x2112, 0x0141, 0x5142, 0x0124, 0x0133, 0x01a3, 0x01b4, 0x5144, 0x0122, 0x0133, 0x01a3, 0x01b2, 0x2362, 20 | 0x0770, 0x0151, 0x0155, 0x0191, 0x0195, 0x4153, 0x0571, 0x2193, 0x01c2, 0x0670, 0x11a3, 0x1046, 0x1055, 0x1064, 0x1073, 0x1082, 21 | 0x1091, 0x10a0, 0x5140, 0x5146, 0x0322, 0x1163, 0x03b2, 0x0131, 0x0135, 0x01a1, 0x01a5, 0x9123, 0x05b1, 0x1032, 0x0041, 0x06b0, 22 | 0x0421, 0x1135, 0x1190, 0x0130, 0x0154, 0x0163, 0x0172, 0x0181, 0x01a5, 0x9025, 0x0321, 0x3175, 0x03b1, 0x2135, 0x0262, 0x0130, 23 | 0x01a0, 0x9124, 0x0670, 0x1033, 0x1042, 0x1051, 0x03b3, 0x0060, 0x4120, 0x3175, 0x0620, 0x04b1, 0x0560, 0x01a0, 0x6140, 0x3175, 24 | 0x04b1, 0x0560, 0x0222, 0x0131, 0x3125, 0x3182, 0x0420, 0x1120, 0x0164, 0x0173, 0x9021, 0x9025, 0x3070, 0x3175, 0x0321, 0x2030, 25 | 0x2135, 0x0361, 0x03b1, 0x6135, 0x2130, 0x0421, 0x0361, 0x03b1, 0x01a4, 0x1143, 0x1193, 0x1143, 0x1193, 0x01b2, 0x2062, 0x0135, 26 | 0x0144, 0x0153, 0x1083, 0x1094, 0x10a5, 0x1053, 0x0071, 0x01b5, 0x0551, 0x0581, 0x2065, 0x0131, 0x0142, 0x0153, 0x1084, 0x1093, 27 | 0x10a2, 0x1054, 0x0175, 0x00b1, 0x2163, 0x0421, 0x1130, 0x1135, 0x11a3, 0x0154, 0x6140, 0x2363, 0x0431, 0x04b1, 0x1145, 0x3263, 28 | 0x6150, 0x6155, 0x0232, 0x0470, 0x0141, 0x0144, 0x0023, 0x9121, 0x9025, 0x3175, 0x0420, 0x2135, 0x04b0, 0x0361, 0x5140, 0x0322, 29 | 0x03b2, 0x0131, 0x0135, 0x1096, 0x01a1, 0x1036, 0x00a5, 0x9121, 0x5145, 0x0420, 0x04b0, 0x0134, 0x01a4, 0x9121, 0x0620, 0x06b0, 30 | 0x2054, 0x1125, 0x1096, 0x2026, 0x0261, 0x00a5, 0x9121, 0x0620, 0x2054, 0x1125, 0x03b0, 0x2026, 0x0261, 0x5140, 0x3175, 0x0322, 31 | 0x02b2, 0x0131, 0x0135, 0x0173, 0x01a1, 0x1036, 0x4076, 0x9120, 0x9125, 0x0460, 0x9123, 0x0322, 0x03b2, 0x8124, 0x2180, 0x03b1, 32 | 0x0323, 0x9121, 0x2125, 0x2195, 0x3054, 0x1261, 0x0020, 0x3025, 0x0184, 0x00b0, 0x9121, 0x06b0, 0x0320, 0x1096, 0x00a5, 0x9120, 33 | 0x9126, 0x1540, 0x2143, 0x0230, 0x0035, 0x9120, 0x9125, 0x1340, 0x1153, 0x0230, 0x2054, 0x7130, 0x7135, 0x0421, 0x04b1, 0x9121, 34 | 0x2135, 0x0520, 0x0461, 0x03b0, 0x7130, 0x7135, 0x31a4, 0x0421, 0x2093, 0x01b1, 0x02d4, 0x9121, 0x9025, 0x3185, 0x0420, 0x2135, 35 | 0x0361, 0x1064, 0x00b0, 0x2185, 0x0421, 0x04b1, 0x1130, 0x1135, 0x1190, 0x0262, 0x0151, 0x0174, 0x9123, 0x0720, 0x1120, 0x1126, 36 | 0x03b2, 0x2020, 0x2027, 0x8120, 0x8125, 0x04b1, 0x6120, 0x6126, 0x03a2, 0x0191, 0x0195, 0x11a3, 0x7120, 0x7126, 0x2173, 0x2191, 37 | 0x2195, 0x3153, 0x1120, 0x1126, 0x11a0, 0x11a6, 0x0141, 0x0145, 0x0352, 0x0382, 0x0191, 0x0195, 0x5163, 0x2120, 0x2126, 0x0151, 38 | 0x0155, 0x0362, 0x03b2, 0x0720, 0x07b0, 0x1190, 0x1120, 0x1126, 0x0145, 0x0154, 0x0163, 0x0172, 0x0181, 0x1097, 0x2020, 0x00a6, 39 | 0x9122, 0x0322, 0x03b2, 0x1140, 0x1162, 0x1184, 0x1195, 0x1151, 0x1173, 0x0030, 0x2096, 0x9124, 0x0122, 0x01b2, 0x0212, 0x0121, 40 | 0x0124, 0x0130, 0x0135, 0x0003, 0x07d0, 0x1102, 0x0123, 0x4164, 0x2180, 0x0351, 0x0271, 0x02b1, 0x01b5, 0x9121, 0x3175, 0x04b1, 41 | 0x0351, 0x0164, 0x0020, 0x4160, 0x0451, 0x04b1, 0x0165, 0x01a5, 0x8124, 0x3170, 0x02b1, 0x0152, 0x0161, 0x01b5, 0x0023, 0x4160, 42 | 0x0451, 0x0670, 0x04b1, 0x0165, 0x01a5, 0x8131, 0x0222, 0x0134, 0x0360, 0x03b0, 0x1035, 0x7164, 0x4160, 0x03e1, 0x0251, 0x02b1, 43 | 0x0155, 0x01d0, 0x9121, 0x5165, 0x0154, 0x0020, 0x0261, 0x00b0, 0x6153, 0x1123, 0x03b2, 0x0052, 0x8155, 0x1125, 0x11c1, 0x03e2, 44 | 0x0054, 0x9121, 0x3064, 0x11a5, 0x0155, 0x1271, 0x0020, 0x1055, 0x0194, 0x00b0, 0x9123, 0x03b2, 0x0022, 0x6150, 0x5163, 0x5166, 45 | 0x1155, 0x1250, 0x5161, 0x5165, 0x0253, 0x0150, 0x4160, 0x4165, 0x0451, 0x04b1, 0x8161, 0x4165, 0x0253, 0x04b1, 0x0150, 0x03e0, 46 | 0x8164, 0x4160, 0x0251, 0x02b1, 0x0155, 0x03e3, 0x5161, 0x1165, 0x0253, 0x0150, 0x03b0, 0x1053, 0x0451, 0x04b1, 0x0282, 0x2051, 47 | 0x0165, 0x0194, 0x01a0, 0x01a5, 0x0060, 0x0171, 0x7132, 0x0550, 0x02b3, 0x01a5, 0x0023, 0x5150, 0x5154, 0x02b1, 0x01b5, 0x3150, 48 | 0x3156, 0x03a2, 0x0191, 0x0195, 0x11a3, 0x5150, 0x5156, 0x2183, 0x11a1, 0x11a5, 0x2173, 0x0150, 0x0156, 0x0161, 0x0165, 0x0372, 49 | 0x0392, 0x01a1, 0x01a5, 0x01b0, 0x01b6, 0x7155, 0x5150, 0x04e0, 0x03b1, 0x01d4, 0x0650, 0x06b0, 0x1150, 0x1154, 0x0173, 0x0182, 50 | 0x0191, 0x01a0, 0x01a5, 0x7033, 0x4074, 0x3024, 0x0224, 0x0161, 0x02b4, 0x4173, 0x3123, 0x7034, 0x4073, 0x3023, 0x0121, 0x0264, 51 | 0x01b1, 0x0221, 0x0233, 0x0125, 0x0130, 0x3170, 0x3175, 0x0252, 0x04a0, 0x0161, 0x0164, 0x0043, 0x4140, 0x4095, 0x0322, 0x03d1, 52 | 0x02a2, 0x0131, 0x0135, 0x1086, 0x0191, 0x1036, 0x10a4, 0x01c5, 0x5150, 0x5154, 0x02b1, 0x0120, 0x0124, 0x01b5, 0x4160, 0x0451, 53 | 0x0670, 0x04b1, 0x0114, 0x0123, 0x0132, 0x0165, 0x01a5, 0x4164, 0x2180, 0x0351, 0x0222, 0x0271, 0x02b1, 0x0131, 0x0134, 0x01b5, 54 | 0x0013, 0x4164, 0x2180, 0x0351, 0x0271, 0x02b1, 0x0120, 0x0124, 0x01b5, 0x4164, 0x2180, 0x0351, 0x0271, 0x02b1, 0x0111, 0x0122, 55 | 0x0133, 0x01b5, 0x4164, 0x2180, 0x0351, 0x0212, 0x0232, 0x0271, 0x02b1, 0x0121, 0x0124, 0x01b5, 0x3151, 0x4085, 0x0342, 0x0292, 56 | 0x02c2, 0x0155, 0x0185, 0x1094, 0x01b5, 0x4160, 0x0451, 0x0670, 0x04b1, 0x0222, 0x0131, 0x0134, 0x0165, 0x01a5, 0x0013, 0x4160, 57 | 0x0451, 0x0670, 0x04b1, 0x0120, 0x0125, 0x0165, 0x01a5, 0x4160, 0x0451, 0x0670, 0x04b1, 0x0111, 0x0122, 0x0133, 0x0165, 0x01a5, 58 | 0x6153, 0x0121, 0x0125, 0x03b2, 0x0052, 0x6153, 0x1113, 0x0322, 0x0131, 0x0135, 0x03b2, 0x0052, 0x6153, 0x0111, 0x0122, 0x0133, 59 | 0x03b2, 0x0052, 0x5160, 0x5165, 0x0242, 0x0480, 0x0110, 0x0115, 0x0151, 0x0154, 0x0033, 0x5160, 0x5165, 0x0202, 0x0222, 0x0242, 60 | 0x0480, 0x0111, 0x0114, 0x0151, 0x0154, 0x7141, 0x0640, 0x06b0, 0x0471, 0x0103, 0x0112, 0x0121, 0x1145, 0x01a5, 0x4163, 0x3056, 61 | 0x3081, 0x02b5, 0x0151, 0x0154, 0x1166, 0x0481, 0x1090, 0x02b1, 0x1052, 0x02a3, 0x9124, 0x7140, 0x0422, 0x0660, 0x0131, 0x02b4, 62 | 0x4160, 0x4165, 0x0451, 0x04b1, 0x0222, 0x0131, 0x0134, 0x0013, 0x4160, 0x4165, 0x0451, 0x04b1, 0x0120, 0x0125, 0x4160, 0x4165, 63 | 0x0451, 0x04b1, 0x0111, 0x0122, 0x0133, 0x5150, 0x5154, 0x1112, 0x02b1, 0x0321, 0x0130, 0x0134, 0x01b5, 0x5150, 0x5154, 0x02b1, 64 | 0x0111, 0x0122, 0x0133, 0x01b5, 0x7155, 0x5150, 0x03b1, 0x03e1, 0x0120, 0x0125, 0x01d4, 0x6140, 0x6145, 0x0431, 0x04b1, 0x0110, 65 | 0x0115, 0x7130, 0x7135, 0x04b1, 0x0110, 0x0115, 0x4140, 0x2113, 0x0591, 0x0531, 0x2193, 0x0146, 0x0186, 0x9121, 0x05b0, 0x0212, 66 | 0x0124, 0x0350, 0x01a5, 0x1025, 0x00a0, 0x7143, 0x0760, 0x0780, 0x0120, 0x0126, 0x0131, 0x0135, 0x0342, 0xa111, 0x4165, 0x0510, 67 | 0x1125, 0x0441, 0x6056, 0x0374, 0x03b0, 0x01b6, 0xa123, 0x0561, 0x0214, 0x02d1, 0x0126, 0x01c0, 0x4164, 0x2180, 0x0351, 0x0271, 68 | 0x02b1, 0x0113, 0x0122, 0x0131, 0x01b5, 0x6153, 0x0114, 0x0123, 0x0132, 0x03b2, 0x0052, 0x4160, 0x4165, 0x0451, 0x04b1, 0x0113, 69 | 0x0122, 0x0131, 0x5150, 0x5154, 0x02b1, 0x0113, 0x0122, 0x0131, 0x01b5, 0x5161, 0x5165, 0x0221, 0x0233, 0x0253, 0x0125, 0x0130, 70 | 0x0150, 0x8130, 0x8135, 0x1350, 0x0201, 0x0213, 0x1163, 0x0105, 0x0110, 0x0240, 0x2064, 0x3114, 0x0561, 0x3012, 0x1021, 0x0442, 71 | 0x0112, 0x0461, 0x3012, 0x3014, 0x1021, 0x1124, 0x0112, 0x0142, 0x2180, 0x04b1, 0x1122, 0x1152, 0x1195, 0x0171, 0x4160, 0x0660, 72 | 0x4165, 0x0460, 0x4110, 0x04d3, 0x0294, 0x1036, 0x1045, 0x1054, 0x1063, 0x1072, 0x1081, 0x1090, 0x2096, 0x01a3, 0x10b5, 0x01a6, 73 | 0x00c4, 0x5185, 0x4110, 0x02b2, 0x1036, 0x1045, 0x1054, 0x1063, 0x1072, 0x1081, 0x1090, 0x0094, 0x00a3, 0x6153, 0x2382, 0x1123, 74 | 0x2061, 0x2064, 0x0152, 0x0155, 0x1082, 0x1085, 0x1052, 0x1055, 0x0070, 0x0073, 0x0192, 0x0195, 0x2062, 0x2065, 0x0150, 0x0153, 75 | 0x1081, 0x1084, 0x1051, 0x1054, 0x0172, 0x0175, 0x0090, 0x0093, 0x0003, 0x0007, 0x0011, 0x0015, 0x0023, 0x0027, 0x0031, 0x0035, 76 | 0x0043, 0x0047, 0x0051, 0x0055, 0x0063, 0x0067, 0x0071, 0x0075, 0x0083, 0x0087, 0x0091, 0x0095, 0x00a3, 0x00a7, 0x00b1, 0x00b5, 77 | 0x00c3, 0x00c7, 0x00d1, 0x00d5, 0x00e3, 0x00e7, 0x00f1, 0x00f5, 0x0001, 0x0003, 0x0005, 0x0007, 0x0010, 0x0012, 0x0014, 0x0016, 78 | 0x0021, 0x0023, 0x0025, 0x0027, 0x0030, 0x0032, 0x0034, 0x0036, 0x0041, 0x0043, 0x0045, 0x0047, 0x0050, 0x0052, 0x0054, 0x0056, 79 | 0x0061, 0x0063, 0x0065, 0x0067, 0x0070, 0x0072, 0x0074, 0x0076, 0x0081, 0x0083, 0x0085, 0x0087, 0x0090, 0x0092, 0x0094, 0x0096, 80 | 0x00a1, 0x00a3, 0x00a5, 0x00a7, 0x00b0, 0x00b2, 0x00b4, 0x00b6, 0x00c1, 0x00c3, 0x00c5, 0x00c7, 0x00d0, 0x00d2, 0x00d4, 0x00d6, 81 | 0x00e1, 0x00e3, 0x00e5, 0x00e7, 0x00f0, 0x00f2, 0x00f4, 0x00f6, 0xf001, 0xf003, 0xf005, 0xf007, 0x0000, 0x0103, 0x0111, 0x0115, 82 | 0x0020, 0x0123, 0x0131, 0x0135, 0x0040, 0x0143, 0x0151, 0x0155, 0x0060, 0x0163, 0x0171, 0x0175, 0x0080, 0x0183, 0x0191, 0x0195, 83 | 0x00a0, 0x01a3, 0x01b1, 0x01b5, 0x00c0, 0x01c3, 0x01d1, 0x01d5, 0x00e0, 0x01e3, 0x01f1, 0x01f5, 0xf103, 0xf103, 0x0270, 0xf103, 84 | 0x0250, 0x0270, 0xf102, 0xf105, 0x0170, 0x8172, 0x8175, 0x0470, 0xa153, 0x0250, 0x0270, 0xf105, 0x8172, 0x5102, 0x0150, 0x0170, 85 | 0xf102, 0xf105, 0xa155, 0x8172, 0x0450, 0x0170, 0x7105, 0x5102, 0x0470, 0x0150, 0x7102, 0x7105, 0x0470, 0x7103, 0x0250, 0x0270, 86 | 0x8173, 0x0270, 0x7103, 0x0473, 0x7103, 0x0770, 0x8173, 0x0770, 0xf103, 0x0473, 0x0770, 0xf103, 0x0770, 0xf103, 0x0453, 0x0473, 87 | 0xf102, 0xf105, 0x0275, 0x7102, 0x5105, 0x0572, 0x0255, 0xa152, 0x8175, 0x0552, 0x0275, 0x5102, 0x5105, 0x0770, 0x0150, 0x0255, 88 | 0x8172, 0x8175, 0x0750, 0x0170, 0x0275, 0xf102, 0x8175, 0x5105, 0x0255, 0x0275, 0x0750, 0x0770, 0x8172, 0x8175, 0x5102, 0x5105, 89 | 0x0150, 0x0170, 0x0255, 0x0275, 0x5103, 0x0770, 0x0750, 0x7102, 0x7105, 0x0770, 0x8173, 0x0750, 0x0770, 0x8172, 0x8175, 0x0770, 90 | 0x7102, 0x7105, 0x0572, 0x7103, 0x0453, 0x0473, 0xa153, 0x0453, 0x0473, 0x8172, 0x8175, 0x0572, 0xf102, 0xf105, 0x0770, 0xf103, 91 | 0x0750, 0x0770, 0x7103, 0x0270, 0x8173, 0x0473, 0xf700, 0x8770, 0xf300, 0xf304, 0x6700, 0x4160, 0x4163, 0x0251, 0x02b1, 0x0155, 92 | 0x10a5, 0x1055, 0x01b5, 0x8130, 0x5024, 0x2185, 0x0221, 0x2134, 0x4075, 0x0063, 0x00b4, 0x9120, 0x2125, 0x0420, 0x7141, 0x7144, 93 | 0x0640, 0x0630, 0x06b0, 0x2063, 0x1130, 0x1135, 0x0151, 0x1082, 0x1091, 0x01a5, 0x1052, 0x0173, 0x00a0, 0x5153, 0x4160, 0x0551, 94 | 0x02b1, 0x7141, 0x4145, 0x0491, 0x01c0, 0x6153, 0x0241, 0x0145, 0x0150, 0x1045, 0x0531, 0x2161, 0x2165, 0x2193, 0x2133, 0x05b1, 95 | 0x0352, 0x0392, 0x4150, 0x4155, 0x0232, 0x0470, 0x02b2, 0x0141, 0x0144, 0x01a1, 0x01a4, 0x4171, 0x4174, 0x2140, 0x2145, 0x0222, 96 | 0x0131, 0x0134, 0x00b0, 0x02b4, 0x4165, 0x3171, 0x0323, 0x03b2, 0x2044, 0x2023, 0x0162, 0x0032, 0x0154, 0x4153, 0x2160, 0x2166, 97 | 0x0551, 0x0591, 0x6036, 0x6051, 0x2153, 0x1281, 0x2060, 0x2166, 0x1045, 0x0491, 0x0136, 0x0151, 0x2181, 0x00b0, 0x5141, 0x0223, 98 | 0x0461, 0x02b3, 0x0132, 0x01a2, 0x7140, 0x7145, 0x0431, 0x0640, 0x0670, 0x06a0, 0x4143, 0x07b0, 0x0561, 0x05b1, 0x2055, 0x0132, 99 | 0x0143, 0x1074, 0x1083, 0x1044, 0x0165, 0x0092, 0x05b1, 0x2052, 0x0134, 0x0143, 0x1073, 0x1084, 0x1043, 0x0061, 0x0194, 0xc133, 100 | 0x1136, 0x0224, 0xa103, 0x2180, 0x02b1, 0x0571, 0x1143, 0x1193, 0x0251, 0x0263, 0x0281, 0x0293, 0x0155, 0x0160, 0x0185, 0x0190, 101 | 0x3012, 0x3014, 0x1021, 0x1124, 0x0112, 0x0142, 0x1173, 0x0183, 0xa114, 0x2171, 0x0314, 0x01a2, 0x0070, 0x10a3, 0x4121, 0x4124, 102 | 0x0110, 0x0113, 0x0460, 0x0211, 0x2013, 0x0120, 0x1032, 0x1041, 0x0123, 0x0050, 0x0054, 0x6441, 103 | }; 104 | 105 | const unsigned short font_places[257] = { 106 | 0x0000, 0x0001, 0x0009, 0x0011, 0x0016, 0x001a, 0x0020, 0x0025, 0x0027, 0x002f, 0x0037, 0x0041, 0x004a, 0x0050, 0x0056, 0x005c, 107 | 0x0066, 0x006c, 0x0072, 0x0077, 0x007b, 0x0080, 0x0092, 0x0093, 0x0099, 0x009c, 0x009f, 0x00a4, 0x00a9, 0x00ab, 0x00b0, 0x00b4, 108 | 0x00b8, 0x00b8, 0x00bb, 0x00bf, 0x00c3, 0x00ce, 0x00d7, 0x00e3, 0x00e5, 0x00ea, 0x00ef, 0x00f5, 0x00f7, 0x00f9, 0x00fa, 0x00fb, 109 | 0x0102, 0x010b, 0x010f, 0x0119, 0x0121, 0x0128, 0x012e, 0x0134, 0x013a, 0x0143, 0x0149, 0x014b, 0x014e, 0x0158, 0x015a, 0x0164, 110 | 0x016a, 0x0170, 0x0177, 0x017e, 0x0187, 0x018d, 0x0196, 0x019d, 0x01a7, 0x01aa, 0x01ad, 0x01b1, 0x01ba, 0x01bf, 0x01c5, 0x01cb, 111 | 0x01cf, 0x01d4, 0x01db, 0x01e3, 0x01ec, 0x01f3, 0x01f6, 0x01fc, 0x0201, 0x020c, 0x0213, 0x0220, 0x0223, 0x022b, 0x022e, 0x0234, 112 | 0x0235, 0x0237, 0x023d, 0x0243, 0x0248, 0x024f, 0x0255, 0x025b, 0x0262, 0x0268, 0x026c, 0x0271, 0x027a, 0x027d, 0x0282, 0x0286, 113 | 0x028a, 0x0290, 0x0296, 0x029c, 0x02a6, 0x02ab, 0x02af, 0x02b5, 0x02ba, 0x02c5, 0x02ca, 0x02d3, 0x02d9, 0x02db, 0x02e1, 0x02e5, 114 | 0x02ec, 0x02f8, 0x02fe, 0x0307, 0x0311, 0x0319, 0x0322, 0x032c, 0x0335, 0x033f, 0x0347, 0x0350, 0x0355, 0x035c, 0x0362, 0x036b, 115 | 0x0375, 0x037e, 0x038a, 0x0390, 0x0398, 0x039e, 0x03a5, 0x03ad, 0x03b4, 0x03bb, 0x03c1, 0x03c6, 0x03cd, 0x03d5, 0x03dd, 0x03e6, 116 | 0x03ec, 0x03f5, 0x03fb, 0x0402, 0x0409, 0x0411, 0x041b, 0x0421, 0x0428, 0x042e, 0x0430, 0x0432, 0x0441, 0x044d, 0x0450, 0x045c, 117 | 0x0468, 0x0488, 0x04c8, 0x04ec, 0x04ed, 0x04ef, 0x04f2, 0x04f5, 0x04f8, 0x04fb, 0x0500, 0x0502, 0x0506, 0x050a, 0x050d, 0x0510, 118 | 0x0512, 0x0514, 0x0516, 0x0518, 0x051a, 0x051b, 0x051d, 0x0520, 0x0523, 0x0527, 0x052b, 0x0530, 0x0535, 0x053a, 0x053c, 0x0544, 119 | 0x0547, 0x054a, 0x054d, 0x0550, 0x0553, 0x0556, 0x0559, 0x055c, 0x055f, 0x0562, 0x0564, 0x0566, 0x0567, 0x0568, 0x0569, 0x056a, 120 | 0x056b, 0x0573, 0x057b, 0x057e, 0x0581, 0x058d, 0x0591, 0x0595, 0x059a, 0x05a2, 0x05ab, 0x05b4, 0x05bd, 0x05c2, 0x05ce, 0x05d4, 121 | 0x05d7, 0x05da, 0x05dd, 0x05e6, 0x05ef, 0x05f2, 0x05f5, 0x05f8, 0x0600, 0x0606, 0x0607, 0x0608, 0x060e, 0x0612, 0x061b, 0x061c, 122 | 0x061c, 123 | }; 124 | 125 | -------------------------------------------------------------------------------- /fonter.c: -------------------------------------------------------------------------------- 1 | //Confusing tool to turn .pbm fonts into compressed RREs for RFB 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define ECHARS 256 10 | #define MAX_RECTS_PER_CHAR 100 11 | 12 | #define DOUBLEPACK 13 | 14 | int cw, ch; 15 | int w, h; 16 | int bytes; 17 | uint8_t * buff; 18 | 19 | struct MRect 20 | { 21 | uint8_t x, y, w, h; 22 | }; 23 | 24 | int ReadFile( const char * rn ); 25 | void DumpBuffer( uint8_t * dat, int len, char * name ) 26 | { 27 | 28 | printf( "const unsigned char %s[%d] = {", name, len ); 29 | int i; 30 | for( i = 0; i < len; i++ ) 31 | { 32 | if( (i%16) == 0 ) 33 | { 34 | printf( "\n\t" ); 35 | } 36 | printf( "0x%02x, ", dat[i] ); 37 | } 38 | printf( "\n};\n\n" ); 39 | } 40 | void DumpBuffer16( uint16_t * dat, int len, char * name ) 41 | { 42 | 43 | printf( "const unsigned short %s[%d] = {", name, len ); 44 | int i; 45 | for( i = 0; i < len; i++ ) 46 | { 47 | if( (i%16) == 0 ) 48 | { 49 | printf( "\n\t" ); 50 | } 51 | printf( "0x%04x, ", dat[i] ); 52 | } 53 | printf( "\n};\n\n" ); 54 | } 55 | 56 | int TryCover( uint8_t * ibuff, struct MRect * r ) 57 | { 58 | int x, y; 59 | int count = 0; 60 | for( y = r->y; y < r->y+r->h; y++ ) 61 | { 62 | for( x = r->x; x < r->x+r->w; x++ ) 63 | { 64 | if( ibuff[x+y*cw] == 1 ) count++; 65 | else if( ibuff[x+y*cw] == 0 ) return -1; 66 | } 67 | } 68 | return count; 69 | } 70 | 71 | void DoCover( uint8_t * ibuff, struct MRect * r ) 72 | { 73 | int x, y; 74 | int count = 0; 75 | for( y = r->y; y < r->y+r->h; y++ ) 76 | { 77 | for( x = r->x; x < r->x+r->w; x++ ) 78 | { 79 | if( ibuff[x+y*cw] > 0 ) ibuff[x+y*cw]++; 80 | } 81 | } 82 | } 83 | 84 | 85 | int Covers( uint8_t * ibuff, struct MRect * rs ) 86 | { 87 | int i; 88 | int x, y, w, h; 89 | 90 | for( i = 0; i < MAX_RECTS_PER_CHAR; i++ ) 91 | { 92 | struct MRect most_efficient, tmp; 93 | int most_efficient_count = 0; 94 | for( y = 0; y < ch; y++ ) 95 | for( x = 0; x < cw; x++ ) 96 | for( h = 1; h <= ch-y; h++ ) 97 | for( w = 1; w <= cw-x; w++ ) 98 | { 99 | #ifdef DOUBLEPACK 100 | if( w > 16 || h > 16 || x > 16 || y > 16 ) continue; 101 | #endif 102 | tmp.x = x; tmp.y = y; tmp.w = w; tmp.h = h; 103 | int ct = TryCover( ibuff, &tmp ); 104 | if( ct > most_efficient_count ) 105 | { 106 | memcpy( &most_efficient, &tmp, sizeof( tmp ) ); 107 | most_efficient_count = ct; 108 | } 109 | } 110 | 111 | if( most_efficient_count == 0 ) 112 | { 113 | return i; 114 | } 115 | 116 | DoCover( ibuff, &most_efficient ); 117 | memcpy( &rs[i], &most_efficient, sizeof( struct MRect ) ); 118 | } 119 | fprintf( stderr, "Error: too many rects per char.\n "); 120 | exit( -22 ); 121 | } 122 | 123 | int GreedyChar( int chr, int debug, struct MRect * RectSet ) 124 | { 125 | int x, y, i; 126 | uint8_t cbuff[ch*cw]; 127 | int rectcount; 128 | 129 | for( y = 0; y < ch; y++ ) 130 | for( x = 0; x < cw/8; x++ ) 131 | { 132 | int ppcx = w/cw; 133 | int xpos = (chr % ppcx)*cw; 134 | int ypos = (chr / ppcx)*ch; 135 | int idx = xpos/8+(ypos+y)*w/8+x; 136 | int inpos = buff[idx]; 137 | 138 | for( i = 0; i < 8; i++ ) 139 | { 140 | cbuff[x*8+y*cw+i] = (inpos&(1<<(7-i)))?0:1; 141 | } 142 | } 143 | 144 | 145 | //Greedily find the minimum # of rectangles that can cover this. 146 | rectcount = Covers( cbuff, RectSet ); 147 | 148 | if( debug ) 149 | { 150 | printf( "Char %d:\n", chr ); 151 | for( i = 0; i < rectcount; i++ ) 152 | { 153 | printf( " %d %d %d %d\n", RectSet[i].x, RectSet[i].y, RectSet[i].w, RectSet[i].h ); 154 | } 155 | printf( "\n" ); 156 | 157 | //Print a char for test. 158 | printf( "%d\n", ch ); 159 | for( y = 0; y < ch; y++ ) 160 | { 161 | for( x = 0; x < cw; x++ ) 162 | { 163 | printf( "%d", cbuff[x+y*cw] ); 164 | } 165 | printf( "\n" ); 166 | } 167 | } 168 | 169 | return rectcount; 170 | } 171 | 172 | 173 | int main( int argc, char ** argv ) 174 | { 175 | int r, i, x, y, j; 176 | 177 | if( argc != 4 ) 178 | { 179 | fprintf( stderr, "Got %d args.\nUsage: [tool] [input_pbm] [char w] [char h]\n", argc ); 180 | return -1; 181 | } 182 | 183 | if( (r = ReadFile( argv[1] )) ) 184 | { 185 | return r; 186 | } 187 | 188 | cw = atoi( argv[2] ); 189 | ch = atoi( argv[3] ); 190 | 191 | printf( "#define FONT_CHAR_W %d\n", cw ); 192 | printf( "#define FONT_CHAR_H %d\n\n", ch ); 193 | 194 | if( ( cw % 8 ) != 0 ) 195 | { 196 | fprintf( stderr, "Error: CW MUST be divisible by 8.\n" ); 197 | } 198 | 199 | // struct MRect MRect rs; 200 | // GreedyChar( 0xdc, 1, &rs ); 201 | 202 | struct MRect MRects[ECHARS*MAX_RECTS_PER_CHAR]; 203 | uint16_t places[ECHARS+1]; 204 | int place = 0; 205 | for( i = 0; i < ECHARS; i++ ) 206 | { 207 | places[i] = place; 208 | place += GreedyChar( i, 0, &MRects[place] ); 209 | } 210 | places[i] = place; 211 | 212 | uint16_t outbuffer[ECHARS*MAX_RECTS_PER_CHAR*2]; 213 | for( i = 0; i < place; i++ ) 214 | { 215 | int x = MRects[i].x; 216 | int y = MRects[i].y; 217 | int w = MRects[i].w; 218 | int h = MRects[i].h; 219 | if( w == 0 || w > 16 ) { fprintf( stderr, "Error: invalid W value\n" ); return -5; } 220 | if( h == 0 || h > 16 ) { fprintf( stderr, "Error: invalid H value\n" ); return -5; } 221 | if( x > 15 ) { fprintf( stderr, "Error: invalid X value\n" ); return -5; } 222 | if( y > 15 ) { fprintf( stderr, "Error: invalid Y value\n" ); return -5; } 223 | w--; 224 | h--; 225 | outbuffer[i] = x | (y<<4) | (w<<8) | (h<<12); 226 | } 227 | 228 | fprintf( stderr, "Total places: %d\n", place ); 229 | DumpBuffer16( outbuffer, place, "font_pieces" ); 230 | DumpBuffer16( places, ECHARS+1, "font_places" ); 231 | 232 | return 0; 233 | } 234 | 235 | 236 | 237 | 238 | 239 | int ReadFile( const char * rn ) 240 | { 241 | int r; 242 | char ct[1024]; 243 | char * cct; 244 | FILE * f = fopen( rn, "r" ); 245 | 246 | if( !f ) 247 | { 248 | fprintf( stderr, "Error: Cannot open file.\n" ); 249 | return -11; 250 | } 251 | 252 | if( fscanf( f, "%1023s\n", ct ) != 1 || strcmp( ct, "P4" ) != 0 ) 253 | { 254 | fprintf( stderr, "Error: Expected P4 header.\n" ); 255 | return -2; 256 | } 257 | 258 | size_t sizin = 0; 259 | cct = 0; 260 | ssize_t s = getline( &cct, &sizin, f ); 261 | 262 | if( !cct || cct[0] != '#' ) 263 | { 264 | fprintf( stderr, "Error: Need a comment line.\n" ); 265 | return -3; 266 | } 267 | free( cct ); 268 | 269 | if( (r = fscanf( f, "%d %d\n", &w, &h )) != 2 || w <= 0 || h <= 0 ) 270 | { 271 | fprintf( stderr, "Error: Need w and h in pbm file. Got %d params. (%d %d)\n", r, w, h ); 272 | return -4; 273 | } 274 | 275 | bytes = (w*h)>>3; 276 | buff = malloc( bytes ); 277 | r = fread( buff, 1, bytes, f ); 278 | if( r != bytes ) 279 | { 280 | fprintf( stderr, "Error: Ran into EOF when reading file. (%d)\n",r ); 281 | return -5; 282 | } 283 | 284 | fclose( f ); 285 | return 0; 286 | } 287 | -------------------------------------------------------------------------------- /fps.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "heap.h" 6 | #include "cnrfb.h" 7 | #include "mathfuncts.h" 8 | #include "fps.h" 9 | 10 | struct FPS FPSs[MAX_RFB_CONNS]; 11 | uint8_t RankingHeap[MAX_RFB_CONNS]; 12 | uint8_t RankingHeapPlace; 13 | uint16_t PlayerPoints[MAX_RFB_CONNS]; //Separate so it can be used with the heap for the leaderboard. 14 | const uint8_t PlayerColors[] = { 0x06, 0x24, 0x20, 0xF0, 0xC0, 0xC6, 0x5b, 0x01 }; 15 | const uint8_t keymap[] = { 81, 83, 82, 84, 'a', 'd', 'w', 's', 227, ' ' }; //227 = left control 16 | 17 | struct Thing Things[MAX_THINGS]; 18 | uint8_t PylonHealths[MAX_PYLONS]; // <128 = dead, animating out to 0. >= 128 = alive, with health 19 | 20 | int last_boolet = MAX_THINGS; 21 | uint8_t gtickcount = 0; 22 | uint16_t gameover = 0; 23 | uint8_t pylons_remaining = 0; 24 | 25 | 26 | static uint32_t GetRandomPos( uint8_t i ) 27 | { 28 | return ((i*1000004249)^0xA48C4B19)&0x1fff1fff; 29 | } 30 | 31 | void FreeFrameForClient( int conn ) 32 | { 33 | struct CNRFBSt * c = &CNRFBs[conn]; 34 | struct FPS * f = &FPSs[conn]; 35 | int i; 36 | 37 | if( !gameover ) 38 | { 39 | //Actually only needs to be MAX_VISBLE_THINGS 40 | int16_t Thetas[MAX_VISIBLE_THINGS]; 41 | uint16_t Distances[MAX_VISIBLE_THINGS]; 42 | uint8_t Heap[MAX_VISIBLE_THINGS]; 43 | uint8_t ThingMapping[MAX_VISIBLE_THINGS]; 44 | uint8_t heaplen = 0; 45 | 46 | int qty = 0; 47 | 48 | for( i = 0; i < MAX_THINGS + MAX_PYLONS; i++ ) 49 | { 50 | int16_t x, y; 51 | 52 | if( qty >= MAX_VISIBLE_THINGS ) break; 53 | 54 | if( i >= MAX_THINGS ) 55 | { 56 | int pylon = i-MAX_THINGS; 57 | 58 | if( PylonHealths[pylon]<=0 ) continue; 59 | 60 | uint32_t p = GetRandomPos(i-MAX_THINGS); 61 | 62 | x = p>>16; 63 | y = p&0xffff; 64 | } 65 | else 66 | { 67 | if( Things[i].size <= 0 ) continue; 68 | x = Things[i].x; 69 | y = Things[i].y; 70 | } 71 | 72 | int16_t dtx = x - f->x; 73 | int16_t dty = y - f->y; 74 | 75 | uint32_t sq = (dtx * dtx) + (dty * dty); 76 | uint16_t dist = tasqrt( sq ); 77 | 78 | int16_t theta = tatan2( dtx, dty ); 79 | 80 | theta -= f->pointangle; 81 | 82 | if( theta < FOV+1 && theta > -FOV-1 && dist > 6 ) 83 | { 84 | Thetas[qty] = (int16_t)theta; 85 | Distances[qty] = dist; 86 | ThingMapping[qty] = i; 87 | HeapAdd( Heap, &heaplen, qty, Distances ); 88 | qty++; 89 | } 90 | } 91 | 92 | StartFrameDraw( conn, 2 ); 93 | 94 | //If was just hit, turn sky red. 95 | StartRRE( qty+2, 0, 0, RFB_WIDTH, RFB_HEIGHT-16, (f->wasjusthit)?0x07:0x80 ); 96 | f->wasjusthit = 0; 97 | DrawRectAtAsPartOfRRE( 0, RFB_HEIGHT/2 + (f->z>>3), RFB_WIDTH, RFB_HEIGHT/2-16-(f->z>>3), 0x20 ); 98 | 99 | int oheap = heaplen; 100 | for( i = 0; i < oheap; i++ ) 101 | { 102 | int j = HeapRemove( Heap, &heaplen, Distances ); 103 | int t = ThingMapping[j]; 104 | uint16_t dist = Distances[j]; 105 | int16_t theta = Thetas[j]; 106 | int16_t left = theta; 107 | int16_t l = left; 108 | int16_t siz; 109 | uint8_t z; 110 | uint8_t color; 111 | 112 | if( t >= MAX_THINGS ) 113 | { 114 | uint8_t health = PylonHealths[t-MAX_THINGS]; 115 | siz = ((health>=128)?65536:(health<<9)) / dist; 116 | z = 0; 117 | color = (health==255)?255:((health>=128)?( (health-128)>>1 ):0); //Change color of pylons based on damage here? 118 | } 119 | else 120 | { 121 | siz = Things[t].size*50/dist; 122 | z = Things[t].z; 123 | color = (t RFB_WIDTH ) r = RFB_WIDTH; 131 | if( siz > RFB_HEIGHT ) siz = RFB_HEIGHT; 132 | 133 | int16_t top = RFB_HEIGHT/2-siz/2; 134 | top += (f->z-z)*400/dist; 135 | if( top < 0 ) top = 0; 136 | if( top > RFB_HEIGHT-16 ) top = RFB_HEIGHT-16; 137 | if( top+siz > RFB_HEIGHT-16 ) siz = RFB_HEIGHT-16-top; 138 | if( siz < 0 ) siz = 0; 139 | DrawRectAtAsPartOfRRE( l, top, r-l, siz, color ); 140 | } 141 | //Sight dot. 142 | DrawRectAtAsPartOfRRE( RFB_WIDTH/2-2, RFB_HEIGHT/2-2, 4, 4, 0x0f ); 143 | } 144 | else //If game over. 145 | { 146 | StartFrameDraw( conn, 1 ); 147 | } 148 | 149 | //Happens every other frame. 150 | struct FPS * show = f; 151 | int which = (f->sendmode >> 1)%6; 152 | 153 | char stabuffer[80]; 154 | 155 | int ypos = RFB_HEIGHT-16; 156 | 157 | int showplayer = conn; 158 | if( gameover ) 159 | { 160 | showplayer = ((f->sendmode >> 1)>>3)&7; 161 | ypos = ( f->rank + 2) * 36; 162 | show = &FPSs[showplayer]; 163 | } 164 | 165 | switch( which ) 166 | { 167 | case 0: sprintf( stabuffer, "%5d \003", show->health ); break; 168 | case 1: sprintf( stabuffer, "%5d \007", PlayerPoints[showplayer] ); break; 169 | case 2: sprintf( stabuffer, "%5d \002", show->kills ); break; 170 | case 3: sprintf( stabuffer, "%5d \001", show->deaths ); break; 171 | case 4: sprintf( stabuffer, "%5d \017", show->boolets ); break; 172 | case 5: sprintf( stabuffer, "%5d \xfe", pylons_remaining ); break; 173 | } 174 | 175 | PrintText( stabuffer, 0xff, PlayerColors[showplayer], (gameover==0)?0:6, which*100+40, ypos ); 176 | 177 | EndFrameDraw( conn ); 178 | 179 | f->sendmode++; 180 | } 181 | 182 | //negative numbers = color override. 183 | void EmitBoolet( int client, int size ) 184 | { 185 | struct FPS * f = &FPSs[client]; 186 | if( f->boolets <= 0 ) return; 187 | f->boolets--; 188 | if( last_boolet < 0 ) last_boolet = BOOLET_START-1; 189 | last_boolet++; 190 | if( last_boolet >= MAX_THINGS ) last_boolet = BOOLET_START; 191 | struct Thing * t = &Things[last_boolet]; 192 | t->x = f->x; t->y = f->y; 193 | t->size = size; 194 | t->z = f->z; 195 | t->dirx = tsin( (f->pointangle>>8) )>>3; 196 | t->diry = tcos( (f->pointangle>>8) )>>3; 197 | t->player_associated = client; 198 | } 199 | 200 | 201 | void GotKeyPress( int client, int key, int down ) 202 | { 203 | struct FPS * f = &FPSs[client]; 204 | int i; 205 | 206 | if( gameover ) return; 207 | 208 | 209 | if( key == '/' ) key = 227; //xxx hack make space also be control. 210 | 211 | for( i = 0; i < MAX_KEYS; i++ ) 212 | { 213 | if( key == keymap[i] ) 214 | { 215 | if( down ) 216 | { 217 | f->time_since_down[i] = 1; 218 | } 219 | else 220 | { 221 | f->time_since_down[i] = 3; 222 | } 223 | break; 224 | } 225 | } 226 | // printf( "%d %d %d\n", client, key, down ); 227 | } 228 | 229 | void GotMouseEvent( int client, int mask, int x, int y ) 230 | { 231 | // printf( "%d %d/%d,%d\n", client, mask, x, y ); 232 | } 233 | 234 | void GotClipboard( int client, int length, unsigned char * st ) 235 | { 236 | // printf( "%d %d:%s\n", client, length, st ); 237 | } 238 | 239 | 240 | void ToolStart() 241 | { 242 | int i; 243 | 244 | memset( PylonHealths, 0xff, sizeof( PylonHealths ) ); 245 | } 246 | 247 | void DisconnectEvent( int conn ) 248 | { 249 | FPSs[conn].in_use = 0; 250 | PlayerPoints[conn] = 0; 251 | } 252 | 253 | 254 | void RespawnPlayer( int c ) 255 | { 256 | uint8_t health; 257 | uint8_t boolets; 258 | 259 | struct FPS * f = &FPSs[c]; 260 | uint32_t i = GetRandomPos(c+1000); 261 | 262 | f->x = i>>16; 263 | f->y = i&0xffff; 264 | 265 | f->health = 100; 266 | f->boolets = 150; 267 | } 268 | 269 | void ConnectEvent( int c ) 270 | { 271 | int i; 272 | struct FPS * f = &FPSs[c]; 273 | memset( &FPSs[c], 0, sizeof( struct FPS ) ); 274 | 275 | for( i = 0; i < MAX_KEYS; i++ ) 276 | { 277 | f->time_since_down[i] = 255; 278 | } 279 | RespawnPlayer( c ); 280 | FPSs[c].in_use = 1; 281 | } 282 | 283 | void HitPylon( int pylon, int boolet ) 284 | { 285 | struct Thing * b = &Things[boolet]; 286 | struct Thing * p = &Things[pylon]; 287 | 288 | int ph = PylonHealths[pylon]; 289 | 290 | if( ph < 128 ) return; 291 | 292 | b->size = 0; 293 | ph-=8; 294 | PylonHealths[pylon] = ph; 295 | 296 | if( ph < 128 ) 297 | { 298 | FPSs[b->player_associated].boolets += 100; 299 | PlayerPoints[b->player_associated] += 50; 300 | } 301 | else 302 | { 303 | PlayerPoints[b->player_associated] ++; 304 | } 305 | 306 | } 307 | 308 | void HitPlayer( int player_hit, int boolet ) 309 | { 310 | struct Thing * t = &Things[boolet]; 311 | struct FPS * fFrom = &FPSs[t->player_associated]; 312 | struct FPS * fTo = &FPSs[player_hit]; 313 | 314 | if( fFrom == fTo ) return; //Can't hit self. 315 | 316 | //Erase boolet. 317 | t->size = 0; 318 | 319 | fTo->health -= 5; 320 | if( fTo->health <= 0 ) 321 | { 322 | fTo->deaths++; 323 | 324 | if( PlayerPoints[player_hit] > 10 ) 325 | PlayerPoints[player_hit] = 0; 326 | else 327 | PlayerPoints[player_hit] -= 100; 328 | 329 | PlayerPoints[t->player_associated] += 100; 330 | 331 | fFrom->kills++; 332 | RespawnPlayer( player_hit ); 333 | } 334 | 335 | //Add knockback 336 | fTo->wasjusthit = 1; 337 | fTo->x += t->dirx*4; 338 | fTo->y += t->diry*4; 339 | } 340 | 341 | void UpdateEvent( int slowtick ) 342 | { 343 | int i; 344 | int j; 345 | 346 | if( !slowtick ) 347 | { 348 | return; 349 | } 350 | 351 | if( !gameover ) 352 | { 353 | pylons_remaining = 0; 354 | for( i = 0; i < MAX_PYLONS; i++ ) 355 | { 356 | if( PylonHealths[i] ) pylons_remaining++; 357 | } 358 | if( pylons_remaining == 0 ) 359 | gameover = 1000; 360 | } 361 | else 362 | { 363 | gameover--; 364 | //Restart game. 365 | if( gameover == 0 ) 366 | { 367 | //Reset all pylons. 368 | ToolStart(); 369 | for( i = 0; i < MAX_RFB_CONNS; i++ ) 370 | { 371 | if( FPSs[i].in_use ) 372 | { 373 | ConnectEvent( i ); 374 | } 375 | } 376 | } 377 | } 378 | 379 | 380 | int rankcompplace = gtickcount % (MAX_RFB_CONNS*2); 381 | if( rankcompplace < MAX_RFB_CONNS ) 382 | { 383 | HeapAdd( RankingHeap, &RankingHeapPlace, rankcompplace, PlayerPoints ); 384 | } 385 | else 386 | { 387 | uint8_t hr = HeapRemove( RankingHeap, &RankingHeapPlace, PlayerPoints ); 388 | FPSs[hr].rank = rankcompplace - 8; 389 | } 390 | 391 | gtickcount++; 392 | 393 | 394 | for( i = 0; i < MAX_RFB_CONNS; i++ ) 395 | { 396 | struct Thing * t = &Things[i]; 397 | struct FPS * f = &FPSs[i]; 398 | int dxmotion = 0; 399 | int dymotion = 0; 400 | 401 | if( !f->in_use ) { t->size = 0; continue; } 402 | 403 | // printf( "%d %p\n", f->playercolor, &f->playercolor ); 404 | if( f->time_since_down[KEY_TURN_LEFT] <= 3 ) f->pointangle-=250; 405 | if( f->time_since_down[KEY_TURN_RIGHT] <= 3 ) f->pointangle+=250; 406 | if( f->time_since_down[KEY_MOVE_FWD] <= SLACKTIMING ) dymotion+=SLACKTIMING-f->time_since_down[KEY_MOVE_FWD]; 407 | if( f->time_since_down[KEY_MOVE_BKD] <= SLACKTIMING ) dymotion-=SLACKTIMING-f->time_since_down[KEY_MOVE_BKD]; 408 | if( f->time_since_down[KEY_MOVE_LEFT] <= SLACKTIMING ) dxmotion-=SLACKTIMING-f->time_since_down[KEY_MOVE_LEFT]; 409 | if( f->time_since_down[KEY_MOVE_RIGHT] <= SLACKTIMING ) dxmotion+=SLACKTIMING-f->time_since_down[KEY_MOVE_RIGHT]; 410 | 411 | int pointangle = f->pointangle; 412 | pointangle = pointangle >> 8; 413 | int omotionx = tcos( pointangle ) * dxmotion + tsin( pointangle ) * dymotion; 414 | int omotiony = tcos( pointangle ) * dymotion - tsin( pointangle ) * dxmotion; 415 | 416 | f->x += omotionx / 150; 417 | f->y += omotiony / 150; 418 | 419 | for( j = 0; j < MAX_KEYS; j++ ) 420 | { 421 | int tsd = f->time_since_down[j]; 422 | if( tsd == 1 ) 423 | { 424 | tsd = 2; 425 | } 426 | else if( tsd >= 3 && f->time_since_down[j] < 255 ) 427 | { 428 | f->time_since_down[j]++; 429 | } 430 | } 431 | if( f->z <= 0 ) 432 | { 433 | if( f->time_since_down[KEY_JUMP] < 2 ) 434 | { 435 | f->speedz = 21; 436 | } 437 | } 438 | 439 | 440 | if( f->z || f->speedz ); 441 | { 442 | f->speedz--; 443 | int newz = f->z; 444 | newz += f->speedz; 445 | if( newz < 0 ) 446 | { 447 | f->z = 0; 448 | f->speedz = 0; 449 | } 450 | else 451 | f->z = newz; 452 | } 453 | 454 | t->x = f->x; 455 | t->z = f->z; 456 | t->y = f->y; 457 | t->dirx = 0; t->diry = 0; 458 | f->shakepos += 1500/(f->health+10); 459 | t->size = 1500 + tsin( f->shakepos>>2 ); 460 | 461 | if( f->time_since_down[KEY_SHOOT] == 1 && f->shoot_cooldown == 0 ) 462 | { 463 | EmitBoolet( i, 400 ); 464 | f->shoot_cooldown = 6; 465 | } 466 | 467 | if( f->shoot_cooldown ) f->shoot_cooldown--; 468 | 469 | } 470 | 471 | 472 | for( i = BOOLET_START; i < MAX_THINGS; i++ ) 473 | { 474 | struct Thing * t = &Things[i]; 475 | 476 | if( t->size <= 0 ) continue; 477 | 478 | t->x += t->dirx; 479 | t->y += t->diry; 480 | 481 | t->size--; 482 | if( t->size < 200 ) { t->size = 0; continue; } 483 | 484 | //Check collision with pylons. 485 | int j; 486 | for( j = 0; j < MAX_PYLONS; j++ ) 487 | { 488 | if( !PylonHealths[j] ) continue; 489 | uint32_t pp = GetRandomPos(j); 490 | int x = pp>>16; 491 | int y = pp&0xFFFF; 492 | int dx = x - t->x; 493 | int dy = y - t->y; 494 | int dz = t->z; 495 | if( dx * dx + dy * dy + dz * dz < MIN_DIST_HIT_SQ ) HitPylon( j, i ); 496 | } 497 | 498 | for( j = 0; j < MAX_RFB_CONNS; j++ ) 499 | { 500 | struct Thing * ot = &Things[j]; 501 | if( !ot->size ) continue; 502 | int dx = ot->x - t->x; 503 | int dy = ot->y - t->y; 504 | int dz = ot->z - t->z; 505 | if( dx * dx + dy * dy + dz * dz < MIN_DIST_HIT_SQ ) HitPlayer( j, i ); 506 | } 507 | } 508 | 509 | //Animate pylon destruction 510 | for( i = 0; i < MAX_PYLONS; i++ ) 511 | { 512 | if( PylonHealths[i] < 128 && PylonHealths[i] ) 513 | PylonHealths[i]--; 514 | } 515 | 516 | } 517 | 518 | -------------------------------------------------------------------------------- /fps.h: -------------------------------------------------------------------------------- 1 | #ifndef _FPS_H 2 | #define _FPS_H 3 | 4 | #include "cnrfb.h" 5 | 6 | #define MAX_PYLONS 55 7 | 8 | #define MAX_VISIBLE_THINGS 100 //Can't send too many bytes per packet. 9 | #define BOOLETS 64 10 | #define BOOLET_START (MAX_RFB_CONNS) 11 | #define MAX_THINGS (MAX_RFB_CONNS+BOOLETS) 12 | 13 | #define MIN_DIST_HIT_SQ 12000 14 | 15 | #define FOV (30*256) 16 | #define SLACKTIMING 10 17 | 18 | 19 | //A totally incomplete FPS demo. 20 | 21 | #define KEY_TURN_LEFT 0 22 | #define KEY_TURN_RIGHT 1 23 | #define KEY_TURN_FWD 2 24 | #define KEY_TURN_BKD 3 25 | 26 | #define KEY_MOVE_LEFT 4 27 | #define KEY_MOVE_RIGHT 5 28 | #define KEY_MOVE_FWD 6 29 | #define KEY_MOVE_BKD 7 30 | 31 | #define KEY_SHOOT 8 32 | #define KEY_JUMP 9 33 | #define MAX_KEYS 10 34 | 35 | //20 bytes per player * 8 players = 160 bytes 36 | struct FPS 37 | { 38 | int wasjusthit:1; 39 | int in_use:1; 40 | int shoot_cooldown:3; 41 | uint8_t rank:3; 42 | uint8_t sendmode; 43 | int16_t x, y; 44 | int16_t pointangle; //-32768,32768, 0 is in front. 45 | uint8_t time_since_down[MAX_KEYS]; 46 | int8_t health; 47 | uint16_t boolets; 48 | uint8_t kills; 49 | uint8_t deaths; 50 | uint16_t shakepos; 51 | uint8_t z; 52 | int8_t speedz; 53 | }; 54 | 55 | extern const uint8_t PlayerColors[MAX_RFB_CONNS]; 56 | 57 | extern struct FPS FPSs[MAX_RFB_CONNS]; 58 | 59 | extern uint8_t RankingHeap[MAX_RFB_CONNS]; 60 | extern uint8_t RankingHeapPlace; 61 | extern uint16_t PlayerPoints[MAX_RFB_CONNS]; //Separate so it can be used with the heap for the leaderboard. 62 | 63 | extern const uint8_t PlayerColors[]; 64 | extern const uint8_t keymap[]; 65 | 66 | struct Thing //10 bytes 67 | { 68 | uint8_t player_associated; 69 | int16_t x, y; 70 | int8_t dirx, diry; 71 | int16_t size; //if 0, inactive. 72 | uint8_t z; 73 | }; 74 | 75 | extern struct Thing Things[MAX_THINGS]; 76 | 77 | extern uint8_t PylonHealths[MAX_PYLONS]; // <128 = dead, animating out to 0. >= 128 = alive, with health 78 | 79 | extern int last_boolet; 80 | extern uint8_t gtickcount; 81 | extern uint16_t gameover; 82 | extern uint8_t pylons_remaining; 83 | 84 | 85 | #endif 86 | 87 | -------------------------------------------------------------------------------- /heap.c: -------------------------------------------------------------------------------- 1 | #include "heap.h" 2 | 3 | 4 | uint8_t HeapRemove( uint8_t * heapdata, uint8_t * heaplen, uint16_t * heapvals ) 5 | { 6 | uint8_t ret = heapdata[0]; 7 | 8 | (*heaplen)--; 9 | 10 | if( *heaplen == 0 ) ret; 11 | 12 | heapdata[0] = heapdata[*heaplen]; 13 | 14 | uint8_t i = 0; 15 | while( !( (i >= *heaplen/2) && (i < *heaplen) ) ) //Not a leaf... 16 | { 17 | int j = i*2+1; //left child. 18 | if( j >= *heaplen ) break; 19 | 20 | if( j < *heaplen -1 && heapvals[heapdata[j]] < heapvals[heapdata[j+1]] ) //?? is the > here right? 21 | j++; //Get index of lowest? value. 22 | 23 | if( heapvals[heapdata[j]] < heapvals[heapdata[i]] ) break; 24 | 25 | uint8_t v = heapdata[j]; 26 | heapdata[j] = heapdata[i]; 27 | heapdata[i] = v; 28 | 29 | i = j; 30 | } 31 | 32 | return ret; 33 | } 34 | 35 | 36 | void HeapAdd( uint8_t * heapdata, uint8_t * heaplen, uint8_t data, uint16_t * heapvals ) 37 | { 38 | heapdata[*heaplen] = data; 39 | 40 | uint8_t curr = *heaplen; 41 | uint8_t parent = (curr-1)/2; 42 | 43 | while( curr != 0 && heapvals[heapdata[curr]] > heapvals[heapdata[parent]] ) 44 | { 45 | uint8_t d = heapdata[curr]; 46 | heapdata[curr] = heapdata[parent]; 47 | heapdata[parent] = d; 48 | 49 | curr = parent; 50 | parent = (curr-1)/2; 51 | } 52 | 53 | (*heaplen)++; 54 | } 55 | 56 | 57 | -------------------------------------------------------------------------------- /heap.h: -------------------------------------------------------------------------------- 1 | #ifndef _HEAP_H 2 | #define _HEAP_H 3 | 4 | #include 5 | 6 | uint8_t HeapRemove( uint8_t * heapdata, uint8_t * heaplen, uint16_t * heapvals ); 7 | 8 | void HeapAdd( uint8_t * heapdata, uint8_t * heaplen, uint8_t data, uint16_t * heapvals ); 9 | 10 | #endif 11 | 12 | 13 | -------------------------------------------------------------------------------- /linux_interface.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "cnrfb.h" 13 | 14 | 15 | #define MAX_SOCKETS 10 16 | 17 | int sockets[MAX_SOCKETS]; 18 | 19 | uint8_t sendbuffer[16384]; 20 | uint16_t sendptr; 21 | uint8_t sendconn; 22 | 23 | uint8_t readbuffer[65536]; 24 | uint16_t readbufferpos = 0; 25 | uint16_t readbuffersize = 0; 26 | 27 | 28 | void CNRFBDump( int i ) 29 | { 30 | while( i-- ) CNRFBRead1(); 31 | } 32 | 33 | int CNRFBCanSendData( int conn ) 34 | { 35 | int unsent; 36 | int error = ioctl( sockets[conn], SIOCOUTQ, &unsent ); 37 | 38 | if( error || ( unsent > 1530 ) ) 39 | { 40 | return 0; 41 | } 42 | else 43 | { 44 | return 1; 45 | } 46 | } 47 | 48 | int CNRFBStartSend( int conn ) 49 | { 50 | if( !CNRFBCanSendData( conn ) ) 51 | { 52 | return -1; 53 | } 54 | 55 | sendconn = conn; 56 | 57 | sendptr = 0; 58 | } 59 | 60 | void CNRFBSendData( const uint8_t * data, int len ) 61 | { 62 | memcpy( sendbuffer + sendptr, data, len ); 63 | sendptr += len; 64 | } 65 | 66 | void CNRFBSend1( uint8_t data ) 67 | { 68 | sendbuffer[sendptr++] = data; 69 | } 70 | 71 | void CNRFBSend2( uint16_t data ) 72 | { 73 | sendbuffer[sendptr++] = data>>8; 74 | sendbuffer[sendptr++] = data; 75 | } 76 | 77 | void CNRFBSend4( uint32_t data ) 78 | { 79 | sendbuffer[sendptr++] = data>>24; 80 | sendbuffer[sendptr++] = data>>16; 81 | sendbuffer[sendptr++] = data>>8; 82 | sendbuffer[sendptr++] = data; 83 | } 84 | 85 | void CNRFBEndSend( ) 86 | { 87 | if( sendconn >= 0 ) 88 | { 89 | int r = send( sockets[sendconn], sendbuffer, sendptr, MSG_NOSIGNAL | MSG_DONTWAIT ); 90 | if( r != sendptr ) 91 | { 92 | fprintf( stderr, "Error: could not send (%d) code %d (%p %d)\n", sockets[sendconn], r, sendbuffer, sendptr); 93 | CNRFBConnectionWasClosed( sockets[sendconn] ); 94 | } 95 | sendptr = 0; 96 | } 97 | } 98 | 99 | 100 | void CNRFBCloseConnection( int conn ) 101 | { 102 | DisconnectEvent( conn ); 103 | close( sockets[conn] ); 104 | sockets[conn] = -1; 105 | } 106 | 107 | 108 | int CNRFBReadRemain() 109 | { 110 | return readbuffersize - readbufferpos; 111 | } 112 | 113 | uint8_t CNRFBRead1() 114 | { 115 | if( readbufferpos + 1 > readbuffersize ) return 0; 116 | return readbuffer[readbufferpos++]; 117 | } 118 | 119 | uint16_t CNRFBRead2() 120 | { 121 | uint16_t r; 122 | if( readbufferpos + 2 > readbuffersize ) return 0; 123 | r = readbuffer[readbufferpos++]; 124 | r = (r<<8) | readbuffer[readbufferpos++]; 125 | return r; 126 | } 127 | 128 | uint32_t CNRFBRead4() 129 | { 130 | uint32_t r; 131 | if( readbufferpos + 4 > readbuffersize ) return 0; 132 | r = readbuffer[readbufferpos++]; 133 | r = (r<<8) | readbuffer[readbufferpos++]; 134 | r = (r<<8) | readbuffer[readbufferpos++]; 135 | r = (r<<8) | readbuffer[readbufferpos++]; 136 | return r; 137 | } 138 | 139 | 140 | int main() 141 | { 142 | int i; 143 | struct linger lin; 144 | int serversocket; 145 | struct sockaddr_in servaddr; 146 | struct pollfd fds[1]; 147 | int lastticktime = 0; 148 | 149 | lin.l_onoff=1; 150 | lin.l_linger=0; 151 | 152 | for( i = 0; i < MAX_SOCKETS; i++ ) 153 | sockets[i] = -1; 154 | 155 | if( ( serversocket = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 ) 156 | { 157 | fprintf( stderr, "Error: Could not create socket.\n" ); 158 | return -1; 159 | } 160 | 161 | memset( &servaddr, 0, sizeof( servaddr ) ); 162 | servaddr.sin_family = AF_INET; 163 | servaddr.sin_addr.s_addr = htonl( INADDR_ANY ); 164 | servaddr.sin_port = htons( 5900 ); 165 | printf( "Listening on port: %d\n", htons( servaddr.sin_port ) ); 166 | 167 | if( bind( serversocket, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0 ) 168 | { 169 | fprintf( stderr, "Error: could not bind to socket.\n" ); 170 | return -1; 171 | } 172 | 173 | if( listen( serversocket, 5 ) < 0 ) 174 | { 175 | fprintf( stderr, "Error: could not listen to socket.\n" ); 176 | return -1; 177 | } 178 | 179 | setsockopt( serversocket, SOL_SOCKET, SO_LINGER,(void*)(&lin), sizeof(lin) ); 180 | 181 | CNRFBInit(); 182 | 183 | ToolStart(); 184 | 185 | while(1) 186 | { 187 | int rc; 188 | // double thistime = OGGetAbsoluteTime(); 189 | struct timeval tv; 190 | gettimeofday( &tv, 0 ); 191 | 192 | memset( fds, 0, sizeof( fds ) ); 193 | fds[0].fd = serversocket; 194 | fds[0].events = POLLIN; 195 | 196 | rc = poll( fds, 1, 0 ); 197 | 198 | if( rc < 0 ) 199 | { 200 | fprintf( stderr, "Error: poll failed on server socket.\n" ); 201 | return -1; 202 | } 203 | if( rc != 0 ) 204 | { 205 | int foundsocketspot; 206 | int clientsocket = accept( serversocket, 0, 0 ); 207 | setsockopt( clientsocket, SOL_SOCKET, SO_LINGER,(void*)(&lin), sizeof(lin) ); 208 | 209 | if( clientsocket > 0 ) 210 | { 211 | int r = CNRFBNewConnection( ); 212 | if( r >= MAX_SOCKETS ) 213 | { 214 | fprintf( stderr, "Error: Got a connection ID too high from new connection.\n" ); 215 | CNRFBCloseConnection( r ); 216 | close( clientsocket ); 217 | } 218 | else if( r >= 0 ) 219 | { 220 | sockets[r] = clientsocket; 221 | } 222 | else 223 | { 224 | close( clientsocket ); 225 | } 226 | ConnectEvent( r ); 227 | } 228 | } 229 | 230 | for( i = 0; i < MAX_SOCKETS; i++ ) 231 | { 232 | int sock = sockets[i]; 233 | 234 | if( sock < 0 ) continue; 235 | 236 | fds[0].fd = sock; 237 | fds[0].events = POLLIN; 238 | 239 | rc = poll( fds, 1, 0 ); 240 | 241 | if( rc < 0 ) 242 | { 243 | CNRFBConnectionWasClosed( i ); 244 | continue; 245 | } 246 | else if( rc == 0 ) 247 | continue; 248 | 249 | rc = recv( sock, readbuffer, 65535, 0 ); 250 | if( rc <= 0 ) 251 | { 252 | CNRFBConnectionWasClosed( i ); 253 | continue; 254 | } 255 | readbufferpos = 0; 256 | readbuffersize = rc; 257 | 258 | if( rc > 0 ) 259 | { 260 | CNRFBGotData( i, rc ); 261 | } 262 | } 263 | 264 | CNRFBTick( 0 ); 265 | UpdateEvent( 0 ); 266 | 267 | if( ( ( tv.tv_usec - lastticktime + 1000000 ) % 1000000 ) > 20000 ) //50 Hz. 268 | { 269 | CNRFBTick( 1 ); 270 | UpdateEvent( 1 ); 271 | lastticktime = tv.tv_usec; 272 | } 273 | 274 | usleep( 1000 ); 275 | } 276 | return 0; 277 | } 278 | 279 | 280 | -------------------------------------------------------------------------------- /mathfuncts.c: -------------------------------------------------------------------------------- 1 | #include "mathfuncts.h" 2 | #include "mathtables.h" 3 | 4 | short tsin( unsigned char angle ) 5 | { 6 | if( angle < 128 ) 7 | { 8 | if( angle < 64 ) 9 | { 10 | return sintab[angle]; 11 | } 12 | else 13 | { 14 | return sintab[128-angle]; 15 | } 16 | } 17 | else 18 | { 19 | if( angle < (64+128) ) 20 | { 21 | return -sintab[angle-128]; 22 | } 23 | else 24 | { 25 | return -sintab[256-angle]; 26 | } 27 | } 28 | } 29 | 30 | short tatan2( short dy, short dx ) 31 | { 32 | unsigned short absx = (dx<0)?-dx:dx; 33 | unsigned short absy = (dy<0)?-dy:dy; 34 | 35 | unsigned char ang; 36 | char angmode; 37 | 38 | if( absx == 0 && absy == 0 ) return 0; 39 | 40 | if( absx < absy ) 41 | { 42 | ang = absx * 128 / absy; 43 | angmode = 1; 44 | } 45 | else 46 | { 47 | ang = absy * 128 / absx; 48 | angmode = 0; 49 | } 50 | 51 | //Ang is now 0..63 but could be from either mode. 52 | short tang = (atancorrect[ang]); 53 | if( angmode ) tang = 511 - tang; 54 | if( dx < 0 ) tang = 1023 - tang; 55 | if( dy < 0 ) tang = -tang; 56 | 57 | return tang<<5; 58 | } 59 | 60 | //from http://stackoverflow.com/questions/1100090/looking-for-an-efficient-integer-square-root-algorithm-for-arm-thumb2 61 | unsigned short tasqrt( unsigned long n ) 62 | { 63 | unsigned long res = 0; 64 | unsigned long one = 1uL << 30; 65 | 66 | // "one" starts at the highest power of four <= than the argument. 67 | while (one > n) 68 | { 69 | one >>= 2; 70 | } 71 | 72 | while (one != 0) 73 | { 74 | if (n >= res + one) 75 | { 76 | n = n - (res + one); 77 | res = res + 2 * one; 78 | } 79 | res >>= 1; 80 | one >>= 2; 81 | } 82 | return res; 83 | } 84 | 85 | -------------------------------------------------------------------------------- /mathfuncts.h: -------------------------------------------------------------------------------- 1 | #ifndef _MATHFUNCTS_H 2 | #define _MATHFUNCTS_H 3 | 4 | short tsin( unsigned char angle ); //Output is -255 to +255 5 | #define tcos( angle ) tsin( (angle) + 64 ) 6 | 7 | //If dx is close to 0, and dy is close to 1, answer will be close to 0. 8 | short tatan2( short dy, short dx ); 9 | 10 | unsigned short tasqrt( unsigned long totake ); 11 | 12 | #endif 13 | 14 | -------------------------------------------------------------------------------- /mathtables.h: -------------------------------------------------------------------------------- 1 | const unsigned char sintab[65] = { 2 | 0x00, 0x06, 0x0c, 0x12, 0x19, 0x1f, 0x25, 0x2b, 0x31, 0x37, 0x3e, 0x44, 0x4a, 0x50, 0x56, 0x5b, 3 | 0x61, 0x67, 0x6d, 0x72, 0x78, 0x7d, 0x83, 0x88, 0x8d, 0x93, 0x98, 0x9d, 0xa2, 0xa6, 0xab, 0xb0, 4 | 0xb4, 0xb9, 0xbd, 0xc1, 0xc5, 0xc9, 0xcd, 0xd0, 0xd4, 0xd7, 0xdb, 0xde, 0xe1, 0xe4, 0xe6, 0xe9, 5 | 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf7, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xfe, 0xff, 0xff, 6 | 0xff, }; 7 | 8 | const unsigned char atancorrect[129] = { 9 | 0x00, 0x02, 0x05, 0x07, 0x0a, 0x0c, 0x0f, 0x11, 0x14, 0x16, 0x19, 0x1b, 0x1e, 0x20, 0x23, 0x25, 10 | 0x28, 0x2a, 0x2d, 0x2f, 0x32, 0x34, 0x37, 0x39, 0x3c, 0x3e, 0x41, 0x43, 0x45, 0x48, 0x4a, 0x4d, 11 | 0x4f, 0x51, 0x54, 0x56, 0x59, 0x5b, 0x5d, 0x60, 0x62, 0x64, 0x67, 0x69, 0x6b, 0x6d, 0x70, 0x72, 12 | 0x74, 0x76, 0x78, 0x7b, 0x7d, 0x7f, 0x81, 0x83, 0x85, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 13 | 0x96, 0x98, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xaf, 0xb1, 0xb3, 14 | 0xb5, 0xb7, 0xb9, 0xba, 0xbc, 0xbe, 0xc0, 0xc1, 0xc3, 0xc5, 0xc7, 0xc8, 0xca, 0xcc, 0xcd, 0xcf, 15 | 0xd1, 0xd2, 0xd4, 0xd5, 0xd7, 0xd9, 0xda, 0xdc, 0xdd, 0xdf, 0xe0, 0xe2, 0xe3, 0xe5, 0xe6, 0xe8, 16 | 0xe9, 0xea, 0xec, 0xed, 0xef, 0xf0, 0xf1, 0xf3, 0xf4, 0xf6, 0xf7, 0xf8, 0xfa, 0xfb, 0xfc, 0xfd, 17 | 0xff, }; 18 | -------------------------------------------------------------------------------- /tabler.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | int i; 7 | 8 | //1/4 of a sinwave 9 | printf( "const unsigned char sintab[65] = {" ); 10 | for( i = 0; i < 65; i++ ) 11 | { 12 | float fv = i * 3.14159 / 128.0; 13 | float f = sin(fv); 14 | int iv = f*255.5; 15 | if( i % 16 == 0 ) printf( "\n\t" ); 16 | printf( "0x%02x, ", iv ); 17 | } 18 | printf( "};\n\n" ); 19 | 20 | printf( "const unsigned char atancorrect[129] = {" ); 21 | for( i = 0; i < 129; i++ ) 22 | { 23 | float fv = i / 128.0; 24 | float f = atan(fv); 25 | f = f / 3.15159 * 4 * 256; 26 | int iv = f; 27 | if( i % 16 == 0 ) printf( "\n\t" ); 28 | //printf( "%f, ", f ); 29 | printf( "0x%02x, ", iv ); 30 | } 31 | printf( "};\n" ); 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /vga8x12.pbm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cnlohr/pylotron/3147cc0a17870d26192613cc93133b9081a9bcaf/vga8x12.pbm --------------------------------------------------------------------------------