u8g_glue.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. /*
  2. Functions for integrating U8glib into the nodemcu platform.
  3. */
  4. #include "lauxlib.h"
  5. #include "platform.h"
  6. #include "c_stdlib.h"
  7. #include "u8g.h"
  8. #include "u8g_glue.h"
  9. // ------------------------------------------------------------
  10. // comm functions
  11. //
  12. #define I2C_CMD_MODE 0x000
  13. #define I2C_DATA_MODE 0x040
  14. #define ESP_I2C_ID 0
  15. static uint8_t do_i2c_start(uint8_t id, uint8_t sla)
  16. {
  17. platform_i2c_send_start( id );
  18. // ignore return value -> tolerate missing ACK
  19. platform_i2c_send_address( id, sla, PLATFORM_I2C_DIRECTION_TRANSMITTER );
  20. return 1;
  21. }
  22. static uint8_t u8g_com_esp8266_ssd_start_sequence(struct _lu8g_userdata_t *lu8g)
  23. {
  24. /* are we requested to set the a0 state? */
  25. if ( lu8g->u8g.pin_list[U8G_PI_SET_A0] == 0 )
  26. return 1;
  27. /* setup bus, might be a repeated start */
  28. if ( do_i2c_start( ESP_I2C_ID, lu8g->i2c_addr ) == 0 )
  29. return 0;
  30. if ( lu8g->u8g.pin_list[U8G_PI_A0_STATE] == 0 )
  31. {
  32. // ignore return value -> tolerate missing ACK
  33. if ( platform_i2c_send_byte( ESP_I2C_ID, I2C_CMD_MODE ) == 0 )
  34. ; //return 0;
  35. }
  36. else
  37. {
  38. platform_i2c_send_byte( ESP_I2C_ID, I2C_DATA_MODE );
  39. }
  40. lu8g->u8g.pin_list[U8G_PI_SET_A0] = 0;
  41. return 1;
  42. }
  43. static void lu8g_digital_write( struct _lu8g_userdata_t *lu8g, uint8_t pin_index, uint8_t value )
  44. {
  45. uint8_t pin;
  46. pin = lu8g->u8g.pin_list[pin_index];
  47. if ( pin != U8G_PIN_NONE )
  48. platform_gpio_write( pin, value );
  49. }
  50. void u8g_Delay(u8g_t *u8g, uint16_t msec)
  51. {
  52. struct _lu8g_userdata_t *lu8g = (struct _lu8g_userdata_t *)u8g;
  53. const uint16_t chunk = 50;
  54. if (lu8g->use_delay == 0)
  55. return;
  56. while (msec > chunk)
  57. {
  58. os_delay_us( chunk*1000 );
  59. msec -= chunk;
  60. }
  61. if (msec > 0)
  62. os_delay_us( msec*1000 );
  63. }
  64. void u8g_MicroDelay(void)
  65. {
  66. os_delay_us( 1 );
  67. }
  68. void u8g_10MicroDelay(void)
  69. {
  70. os_delay_us( 10 );
  71. }
  72. uint8_t u8g_com_esp8266_hw_spi_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
  73. {
  74. struct _lu8g_userdata_t *lu8g = (struct _lu8g_userdata_t *)u8g;
  75. switch(msg)
  76. {
  77. case U8G_COM_MSG_STOP:
  78. break;
  79. case U8G_COM_MSG_INIT:
  80. // we assume that the SPI interface was already initialized
  81. // just care for the /CS and D/C pins
  82. lu8g_digital_write( lu8g, U8G_PI_CS, PLATFORM_GPIO_HIGH );
  83. platform_gpio_mode( lu8g->u8g.pin_list[U8G_PI_CS], PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT );
  84. platform_gpio_mode( lu8g->u8g.pin_list[U8G_PI_A0], PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT );
  85. break;
  86. case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */
  87. lu8g_digital_write( lu8g, U8G_PI_A0, arg_val == 0 ? PLATFORM_GPIO_LOW : PLATFORM_GPIO_HIGH );
  88. break;
  89. case U8G_COM_MSG_CHIP_SELECT:
  90. if (arg_val == 0)
  91. {
  92. /* disable */
  93. lu8g_digital_write( lu8g, U8G_PI_CS, PLATFORM_GPIO_HIGH );
  94. }
  95. else
  96. {
  97. /* enable */
  98. lu8g_digital_write( lu8g, U8G_PI_CS, PLATFORM_GPIO_LOW );
  99. }
  100. break;
  101. case U8G_COM_MSG_RESET:
  102. if ( lu8g->u8g.pin_list[U8G_PI_RESET] != U8G_PIN_NONE )
  103. lu8g_digital_write( lu8g, U8G_PI_RESET, arg_val == 0 ? PLATFORM_GPIO_LOW : PLATFORM_GPIO_HIGH );
  104. break;
  105. case U8G_COM_MSG_WRITE_BYTE:
  106. platform_spi_send( 1, 8, arg_val );
  107. break;
  108. case U8G_COM_MSG_WRITE_SEQ:
  109. case U8G_COM_MSG_WRITE_SEQ_P:
  110. {
  111. register uint8_t *ptr = arg_ptr;
  112. while( arg_val > 0 )
  113. {
  114. platform_spi_send( 1, 8, *ptr++ );
  115. arg_val--;
  116. }
  117. }
  118. break;
  119. }
  120. return 1;
  121. }
  122. uint8_t u8g_com_esp8266_ssd_i2c_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
  123. {
  124. struct _lu8g_userdata_t *lu8g = (struct _lu8g_userdata_t *)u8g;
  125. switch(msg)
  126. {
  127. case U8G_COM_MSG_INIT:
  128. // we assume that the i2c bus was already initialized
  129. //u8g_i2c_init(u8g->pin_list[U8G_PI_I2C_OPTION]);
  130. break;
  131. case U8G_COM_MSG_STOP:
  132. break;
  133. case U8G_COM_MSG_RESET:
  134. /* Currently disabled, but it could be enable. Previous restrictions have been removed */
  135. /* u8g_com_arduino_digital_write(u8g, U8G_PI_RESET, arg_val); */
  136. break;
  137. case U8G_COM_MSG_CHIP_SELECT:
  138. lu8g->u8g.pin_list[U8G_PI_A0_STATE] = 0;
  139. lu8g->u8g.pin_list[U8G_PI_SET_A0] = 1; /* force a0 to set again, also forces start condition */
  140. if ( arg_val == 0 )
  141. {
  142. /* disable chip, send stop condition */
  143. platform_i2c_send_stop( ESP_I2C_ID );
  144. }
  145. else
  146. {
  147. /* enable, do nothing: any byte writing will trigger the i2c start */
  148. }
  149. break;
  150. case U8G_COM_MSG_WRITE_BYTE:
  151. //u8g->pin_list[U8G_PI_SET_A0] = 1;
  152. if ( u8g_com_esp8266_ssd_start_sequence(lu8g) == 0 )
  153. return platform_i2c_send_stop( ESP_I2C_ID ), 0;
  154. // ignore return value -> tolerate missing ACK
  155. if ( platform_i2c_send_byte( ESP_I2C_ID, arg_val) == 0 )
  156. ; //return platform_i2c_send_stop( ESP_I2C_ID ), 0;
  157. // platform_i2c_send_stop( ESP_I2C_ID );
  158. break;
  159. case U8G_COM_MSG_WRITE_SEQ:
  160. case U8G_COM_MSG_WRITE_SEQ_P:
  161. //u8g->pin_list[U8G_PI_SET_A0] = 1;
  162. if ( u8g_com_esp8266_ssd_start_sequence(lu8g) == 0 )
  163. return platform_i2c_send_stop( ESP_I2C_ID ), 0;
  164. {
  165. register uint8_t *ptr = arg_ptr;
  166. while( arg_val > 0 )
  167. {
  168. // ignore return value -> tolerate missing ACK
  169. if ( platform_i2c_send_byte( ESP_I2C_ID, *ptr++) == 0 )
  170. ; //return platform_i2c_send_stop( ESP_I2C_ID ), 0;
  171. arg_val--;
  172. }
  173. }
  174. // platform_i2c_send_stop( ESP_I2C_ID );
  175. break;
  176. case U8G_COM_MSG_ADDRESS: /* define cmd (arg_val = 0) or data mode (arg_val = 1) */
  177. lu8g->u8g.pin_list[U8G_PI_A0_STATE] = arg_val;
  178. lu8g->u8g.pin_list[U8G_PI_SET_A0] = 1; /* force a0 to set again */
  179. break;
  180. }
  181. return 1;
  182. }
  183. // ***************************************************************************
  184. // Generic framebuffer device and RLE comm driver
  185. //
  186. uint8_t u8g_dev_gen_fb_fn(u8g_t *u8g, u8g_dev_t *dev, uint8_t msg, void *arg)
  187. {
  188. switch(msg)
  189. {
  190. case U8G_DEV_MSG_PAGE_FIRST:
  191. // tell comm driver to start new framebuffer
  192. u8g_SetChipSelect(u8g, dev, 1);
  193. break;
  194. case U8G_DEV_MSG_PAGE_NEXT:
  195. {
  196. u8g_pb_t *pb = (u8g_pb_t *)(dev->dev_mem);
  197. if ( u8g_pb_WriteBuffer(pb, u8g, dev) == 0 )
  198. return 0;
  199. }
  200. break;
  201. }
  202. return u8g_dev_pb8v1_base_fn(u8g, dev, msg, arg);
  203. }
  204. static int bit_at( uint8_t *buf, int line, int x )
  205. {
  206. uint8_t byte = buf[x];
  207. return buf[x] & (1 << line) ? 1 : 0;
  208. }
  209. struct _lu8g_fbrle_item
  210. {
  211. uint8_t start_x;
  212. uint8_t len;
  213. };
  214. struct _lu8g_fbrle_line
  215. {
  216. uint8_t num_valid;
  217. struct _lu8g_fbrle_item items[0];
  218. };
  219. uint8_t u8g_com_esp8266_fbrle_fn(u8g_t *u8g, uint8_t msg, uint8_t arg_val, void *arg_ptr)
  220. {
  221. struct _lu8g_userdata_t *lud = (struct _lu8g_userdata_t *)u8g;
  222. switch(msg)
  223. {
  224. case U8G_COM_MSG_INIT:
  225. // allocate memory -> done
  226. // init buffer
  227. break;
  228. case U8G_COM_MSG_CHIP_SELECT:
  229. if (arg_val == 1) {
  230. // new frame starts
  231. if (lud->cb_ref != LUA_NOREF) {
  232. // fire callback with nil argument
  233. lua_State *L = lua_getstate();
  234. lua_rawgeti( L, LUA_REGISTRYINDEX, lud->cb_ref );
  235. lua_pushnil( L );
  236. lua_call( L, 1, 0 );
  237. }
  238. }
  239. break;
  240. case U8G_COM_MSG_WRITE_SEQ:
  241. case U8G_COM_MSG_WRITE_SEQ_P:
  242. {
  243. uint8_t xwidth = u8g->pin_list[U8G_PI_EN];
  244. size_t fbrle_line_size = sizeof( struct _lu8g_fbrle_line ) + sizeof( struct _lu8g_fbrle_item ) * (xwidth/2);
  245. int num_lines = arg_val / (xwidth/8);
  246. uint8_t *buf = (uint8_t *)arg_ptr;
  247. struct _lu8g_fbrle_line *fbrle_line;
  248. if (!(fbrle_line = (struct _lu8g_fbrle_line *)c_malloc( fbrle_line_size ))) {
  249. break;
  250. }
  251. for (int line = 0; line < num_lines; line++) {
  252. int start_run = -1;
  253. fbrle_line->num_valid = 0;
  254. for (int x = 0; x < xwidth; x++) {
  255. if (bit_at( buf, line, x ) == 0) {
  256. if (start_run >= 0) {
  257. // inside run, end it and enter result
  258. fbrle_line->items[fbrle_line->num_valid].start_x = start_run;
  259. fbrle_line->items[fbrle_line->num_valid++].len = x - start_run;
  260. //NODE_ERR( " line: %d x: %d len: %d\n", line, start_run, x - start_run );
  261. start_run = -1;
  262. }
  263. } else {
  264. if (start_run < 0) {
  265. // outside run, start it
  266. start_run = x;
  267. }
  268. }
  269. if (fbrle_line->num_valid >= xwidth/2) break;
  270. }
  271. // active run?
  272. if (start_run >= 0 && fbrle_line->num_valid < xwidth/2) {
  273. fbrle_line->items[fbrle_line->num_valid].start_x = start_run;
  274. fbrle_line->items[fbrle_line->num_valid++].len = xwidth - start_run;
  275. }
  276. // line done, trigger callback
  277. if (lud->cb_ref != LUA_NOREF) {
  278. lua_State *L = lua_getstate();
  279. lua_rawgeti( L, LUA_REGISTRYINDEX, lud->cb_ref );
  280. lua_pushlstring( L, (const char *)fbrle_line, fbrle_line_size );
  281. lua_call( L, 1, 0 );
  282. }
  283. }
  284. c_free( fbrle_line );
  285. }
  286. break;
  287. }
  288. return 1;
  289. }