u8x8_d_framebuffer.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. /*
  2. u8x8_framebuffer.c
  3. a framebuffer device
  4. */
  5. #include <unistd.h>
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include <fcntl.h>
  9. #include <stdlib.h>
  10. #include <linux/fb.h>
  11. #include <sys/mman.h>
  12. #include <sys/ioctl.h>
  13. #include "u8g2.h" /* because of u8g2_Setup... */
  14. /*========================================================*/
  15. /* framebuffer struct */
  16. struct _u8x8_linuxfb_struct
  17. {
  18. u8x8_msg_cb u8x8_bitmap_display_old_cb;
  19. int fbfd;
  20. struct fb_var_screeninfo vinfo;
  21. struct fb_fix_screeninfo finfo;
  22. uint8_t *u8x8_buf;
  23. uint8_t *u8g2_buf;
  24. uint8_t *fbp;
  25. uint32_t active_color;
  26. };
  27. typedef struct _u8x8_linuxfb_struct u8x8_linuxfb_t;
  28. /*========================================================*/
  29. /* framebuffer functions */
  30. uint8_t u8x8_LinuxFb_alloc(int fbfd, u8x8_linuxfb_t *fb)
  31. {
  32. size_t tile_width;
  33. size_t tile_height;
  34. size_t screensize = 0;
  35. // Make sure that the display is on.
  36. if (ioctl(fbfd, FBIOBLANK, FB_BLANK_UNBLANK) != 0) {
  37. perror("ioctl(FBIOBLANK)");
  38. return 0;
  39. }
  40. // Get fixed screen information
  41. if (ioctl(fbfd, FBIOGET_FSCREENINFO, &fb->finfo)) {
  42. fprintf(stderr,"Error reading fixed information.\n");
  43. return 0;
  44. }
  45. // Get variable screen information
  46. if (ioctl(fbfd, FBIOGET_VSCREENINFO, &fb->vinfo)) {
  47. fprintf(stderr,"Error reading variable information.\n");
  48. return 0;
  49. }
  50. if ( fb->u8x8_buf != NULL )
  51. free(fb->u8x8_buf);
  52. fb->fbfd = fbfd;
  53. fb->active_color = 0xFFFFFF;
  54. tile_width = (fb->vinfo.xres+7)/8;
  55. tile_height = (fb->vinfo.yres+7)/8;
  56. screensize = tile_width*tile_height * 8;
  57. /* allocate the tile buffer twice, one for u8x8 and another bitmap for u8g2 */
  58. fb->u8x8_buf = (uint8_t *)malloc(screensize*2);
  59. fb->u8g2_buf = (uint8_t *)fb->u8x8_buf + screensize;
  60. if ( fb->u8x8_buf == NULL ) {
  61. fb->u8g2_buf = NULL;
  62. return 0;
  63. }
  64. // Map the device to memory
  65. fb->fbp = mmap(0, fb->finfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
  66. if (fb->fbp == MAP_FAILED) {
  67. printf("Error: failed to map framebuffer device to memory.\n");
  68. return 0;
  69. }
  70. memset(fb->fbp,0x00,screensize);
  71. return 1;
  72. }
  73. void u8x8_LinuxFb_DrawTiles(u8x8_linuxfb_t *fb, uint16_t tx, uint16_t ty, uint8_t tile_cnt, uint8_t *tile_ptr)
  74. {
  75. uint8_t byte;
  76. memset(fb->u8x8_buf,0x00,8*tile_cnt);
  77. for(int i=0; i < tile_cnt * 8; i++){
  78. byte = *tile_ptr++;
  79. for(int bit=0; bit < 8;bit++){
  80. if(byte & (1 << bit))
  81. fb->u8x8_buf[tile_cnt*bit+(i/8)] |= (1 << i%8);
  82. }
  83. }
  84. switch (fb->vinfo.bits_per_pixel) {
  85. case 1:
  86. memcpy(fb->fbp+ty*8*tile_cnt, fb->u8x8_buf, tile_cnt*8);
  87. break;
  88. case 16:{
  89. uint16_t pixel;
  90. uint16_t *fbp16 = (uint16_t *)fb->fbp;
  91. long int location = 0;
  92. uint8_t b = (fb->active_color & 0x0000FF) >> 0;
  93. uint8_t g = (fb->active_color & 0x00FF00) >> 8;
  94. uint8_t r = (fb->active_color & 0xFF0000) >> 16;
  95. for(int y=0; y<8;y++){
  96. for(int x=0; x<8*tile_cnt;x++){
  97. if(fb->u8x8_buf[(x/8) + (y*tile_cnt) ] & (1 << x%8))
  98. pixel = r<<11 | g << 5 | b;
  99. else
  100. pixel = 0x000000;
  101. location = (x + fb->vinfo.xoffset) + ((ty*8)+y + fb->vinfo.yoffset) * fb->finfo.line_length / 2;
  102. memcpy(&fbp16[location], &pixel, sizeof(pixel));
  103. }
  104. }
  105. }break;
  106. case 32:{
  107. uint32_t pixel;
  108. uint32_t *fbp32 = (uint32_t *)fb->fbp;
  109. long int location = 0;
  110. for(int y=0; y<8;y++){
  111. for(int x=0; x<8*tile_cnt;x++){
  112. if(fb->u8x8_buf[(x/8) + (y*tile_cnt) ] & (1 << x%8))
  113. pixel = fb->active_color;
  114. else
  115. pixel = 0x000000;
  116. location = (x + fb->vinfo.xoffset) + ((ty*8)+y + fb->vinfo.yoffset) * fb->finfo.line_length / 4;
  117. memcpy(&fbp32[location], &pixel, sizeof(pixel));
  118. }
  119. }
  120. }break;
  121. //TODO support 24/16/8 bits_per_pixel
  122. default:
  123. break;
  124. }
  125. }
  126. /*========================================================*/
  127. /* global objects for the framebuffer */
  128. static u8x8_linuxfb_t u8x8_linuxfb;
  129. static u8x8_display_info_t u8x8_libuxfb_info =
  130. {
  131. /* chip_enable_level = */ 0,
  132. /* chip_disable_level = */ 1,
  133. /* post_chip_enable_wait_ns = */ 0,
  134. /* pre_chip_disable_wait_ns = */ 0,
  135. /* reset_pulse_width_ms = */ 0,
  136. /* post_reset_wait_ms = */ 0,
  137. /* sda_setup_time_ns = */ 0,
  138. /* sck_pulse_width_ns = */ 0,
  139. /* sck_clock_hz = */ 4000000UL,
  140. /* spi_mode = */ 1,
  141. /* i2c_bus_clock_100kHz = */ 0,
  142. /* data_setup_time_ns = */ 0,
  143. /* write_pulse_width_ns = */ 0,
  144. /* tile_width = */ 8, /* dummy value */
  145. /* tile_hight = */ 4, /* dummy value */
  146. /* default_x_offset = */ 0,
  147. /* flipmode_x_offset = */ 0,
  148. /* pixel_width = */ 64, /* dummy value */
  149. /* pixel_height = */ 32 /* dummy value */
  150. };
  151. /*========================================================*/
  152. /* functions for handling of the global objects */
  153. /* allocate bitmap */
  154. /* will be called by u8x8_SetupBitmap or u8g2_SetupBitmap */
  155. static uint8_t u8x8_SetLinuxFbDevice(U8X8_UNUSED u8x8_t *u8x8, int fbfd)
  156. {
  157. struct fb_var_screeninfo *vinfo = &u8x8_linuxfb.vinfo;
  158. /* update the global framebuffer object, allocate memory */
  159. if ( u8x8_LinuxFb_alloc(fbfd, &u8x8_linuxfb) == 0 )
  160. return 0;
  161. /* update the u8x8 info object */
  162. u8x8_libuxfb_info.tile_width = (u8x8_linuxfb.vinfo.xres+7)/8;
  163. u8x8_libuxfb_info.tile_height = (vinfo->yres+7)/8;
  164. u8x8_libuxfb_info.pixel_width = vinfo->xres;
  165. u8x8_libuxfb_info.pixel_height = vinfo->yres;
  166. return 1;
  167. }
  168. /* draw tiles to the bitmap, called by the device procedure */
  169. static void u8x8_DrawLinuxFbTiles(U8X8_UNUSED u8x8_t *u8x8, uint16_t tx, uint16_t ty, uint8_t tile_cnt, uint8_t *tile_ptr)
  170. {
  171. u8x8_LinuxFb_DrawTiles(&u8x8_linuxfb, tx, ty, tile_cnt, tile_ptr);
  172. }
  173. /*========================================================*/
  174. static uint8_t u8x8_framebuffer_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
  175. {
  176. u8g2_uint_t x, y, c;
  177. uint8_t *ptr;
  178. switch(msg)
  179. {
  180. case U8X8_MSG_DISPLAY_SETUP_MEMORY:
  181. u8x8_d_helper_display_setup_memory(u8x8, &u8x8_libuxfb_info);
  182. break;
  183. case U8X8_MSG_DISPLAY_INIT:
  184. u8x8_d_helper_display_init(u8x8); /* update low level interfaces (not required here) */
  185. break;
  186. case U8X8_MSG_DISPLAY_SET_POWER_SAVE:
  187. break;
  188. case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
  189. break;
  190. case U8X8_MSG_DISPLAY_DRAW_TILE:
  191. x = ((u8x8_tile_t *)arg_ptr)->x_pos;
  192. y = ((u8x8_tile_t *)arg_ptr)->y_pos;
  193. c = ((u8x8_tile_t *)arg_ptr)->cnt;
  194. ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;
  195. do
  196. {
  197. u8x8_DrawLinuxFbTiles(u8x8, x, y, c, ptr);
  198. x += c;
  199. arg_int--;
  200. } while( arg_int > 0 );
  201. break;
  202. default:
  203. return 0;
  204. }
  205. return 1;
  206. }
  207. /*========================================================*/
  208. /* u8x8 and u8g2 setup functions */
  209. void u8x8_SetupLinuxFb(u8x8_t *u8x8, int fbfd)
  210. {
  211. u8x8_SetLinuxFbDevice(u8x8,fbfd);
  212. /* setup defaults */
  213. u8x8_SetupDefaults(u8x8);
  214. /* setup specific callbacks */
  215. u8x8->display_cb = u8x8_framebuffer_cb;
  216. /* setup display info */
  217. u8x8_SetupMemory(u8x8);
  218. }
  219. void u8g2_SetupLinuxFb(u8g2_t *u8g2, const u8g2_cb_t *u8g2_cb, const char *fb_device)
  220. {
  221. int fbfd = open(fb_device,O_RDWR);
  222. if (fbfd == -1) {
  223. perror(fb_device);
  224. return;
  225. }
  226. /* allocate bitmap, assign the device callback to u8x8 */
  227. u8x8_SetupLinuxFb(u8g2_GetU8x8(u8g2), fbfd);
  228. /* configure u8g2 in full buffer mode */
  229. u8g2_SetupBuffer(u8g2, u8x8_linuxfb.u8g2_buf, (u8x8_libuxfb_info.pixel_height+7)/8, u8g2_ll_hvline_vertical_top_lsb, u8g2_cb);
  230. }
  231. void u8x8_LinuxFbSetActiveColor(uint32_t color)
  232. {
  233. u8x8_linuxfb.active_color = color;
  234. }