st7032.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095
  1. /****************************************************************************
  2. * drivers/lcd/st7032.c
  3. *
  4. * Licensed to the Apache Software Foundation (ASF) under one or more
  5. * contributor license agreements. See the NOTICE file distributed with
  6. * this work for additional information regarding copyright ownership. The
  7. * ASF licenses this file to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance with the
  9. * License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  15. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  16. * License for the specific language governing permissions and limitations
  17. * under the License.
  18. *
  19. ****************************************************************************/
  20. /* Alphanumeric LCD driver for ST7032i (tested on JLX1602G-390) */
  21. /****************************************************************************
  22. * Included Files
  23. ****************************************************************************/
  24. #include <nuttx/config.h>
  25. #include <stdlib.h>
  26. #include <errno.h>
  27. #include <debug.h>
  28. #include <string.h>
  29. #include <nuttx/kmalloc.h>
  30. #include <nuttx/signal.h>
  31. #include <nuttx/ascii.h>
  32. #include <nuttx/fs/fs.h>
  33. #include <nuttx/lcd/slcd_codec.h>
  34. #include <nuttx/lcd/slcd_ioctl.h>
  35. #include <nuttx/i2c/i2c_master.h>
  36. #include <nuttx/lcd/st7032.h>
  37. #ifndef CONFIG_LIB_SLCDCODEC
  38. # error please also select Library Routines, Segment LCD CODEC
  39. #endif
  40. #if defined(CONFIG_I2C) && defined(CONFIG_LCD_ST7032)
  41. /****************************************************************************
  42. * Pre-processor Definitions
  43. ****************************************************************************/
  44. /* I2C frequency */
  45. #ifndef CONFIG_ST7032_I2C_FREQ
  46. # define CONFIG_ST7032_I2C_FREQ 400000
  47. #endif
  48. /****************************************************************************
  49. * Private Types
  50. ****************************************************************************/
  51. struct st7032_dev_s
  52. {
  53. FAR struct i2c_master_s *i2c; /* I2C interface */
  54. uint8_t row; /* Current row position to write on display */
  55. uint8_t col; /* Current col position to write on display */
  56. uint8_t buffer[ST7032_MAX_ROW * ST7032_MAX_COL];
  57. bool pendscroll;
  58. sem_t sem_excl;
  59. };
  60. struct lcd_instream_s
  61. {
  62. struct lib_instream_s stream;
  63. FAR const char *buffer;
  64. ssize_t nbytes;
  65. };
  66. /****************************************************************************
  67. * Private Function Prototypes
  68. ****************************************************************************/
  69. static inline void st7032_write_inst(FAR struct st7032_dev_s *priv,
  70. uint8_t cmd);
  71. static inline void st7032_write_data(FAR struct st7032_dev_s *priv,
  72. uint8_t value);
  73. static inline void st7032_setcontrast(FAR struct st7032_dev_s *priv,
  74. int8_t contrast);
  75. static void lcd_scroll_up(FAR struct st7032_dev_s *priv);
  76. /* Character driver methods */
  77. static int st7032_open(FAR struct file *filep);
  78. static int st7032_close(FAR struct file *filep);
  79. static ssize_t st7032_read(FAR struct file *filep, FAR char *buffer,
  80. size_t buflen);
  81. static ssize_t st7032_write(FAR struct file *filep, FAR const char *buffer,
  82. size_t buflen);
  83. static off_t st7032_seek(FAR struct file *filep, off_t offset, int whence);
  84. static int st7032_ioctl(FAR struct file *filep, int cmd,
  85. unsigned long arg);
  86. /****************************************************************************
  87. * Private Data
  88. ****************************************************************************/
  89. static const struct file_operations g_st7032fops =
  90. {
  91. st7032_open, /* open */
  92. st7032_close, /* close */
  93. st7032_read, /* read */
  94. st7032_write, /* write */
  95. st7032_seek, /* seek */
  96. st7032_ioctl, /* ioctl */
  97. NULL, /* poll */
  98. #ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  99. NULL /* unlink */
  100. #endif
  101. };
  102. /****************************************************************************
  103. * Private Functions
  104. ****************************************************************************/
  105. /****************************************************************************
  106. * Name: st7032_write_inst
  107. *
  108. * Description:
  109. * Write an Instruction command to ST7032
  110. *
  111. ****************************************************************************/
  112. static inline void st7032_write_inst(FAR struct st7032_dev_s *priv,
  113. uint8_t cmd)
  114. {
  115. struct i2c_msg_s msg;
  116. uint8_t data[2];
  117. int ret;
  118. /* Prepare data to send */
  119. data[0] = 0x00;
  120. data[1] = cmd;
  121. /* Setup the ST7032 Co command */
  122. msg.frequency = CONFIG_ST7032_I2C_FREQ; /* I2C frequency */
  123. msg.addr = ST7032_I2C_ADDR; /* 7-bit address */
  124. msg.flags = 0; /* Write transaction, beginning with START */
  125. msg.buffer = (FAR uint8_t *) data; /* Transfer from this address */
  126. msg.length = 2; /* Send two bytes */
  127. /* Perform the transfer */
  128. ret = I2C_TRANSFER(priv->i2c, &msg, 1);
  129. if (ret < 0)
  130. {
  131. lcderr("ERROR: I2C_TRANSFER failed: %d\n", ret);
  132. }
  133. /* Delay 30us */
  134. nxsig_usleep(30);
  135. }
  136. /****************************************************************************
  137. * Name: st7032_write_data
  138. *
  139. * Description:
  140. * Write a Data command to ST7032
  141. *
  142. ****************************************************************************/
  143. static inline void st7032_write_data(FAR struct st7032_dev_s *priv,
  144. uint8_t value)
  145. {
  146. struct i2c_msg_s msg;
  147. uint8_t data[2];
  148. int ret;
  149. /* Prepare data to send */
  150. data[0] = ST7032_CTRLBIT_RS;
  151. data[1] = value;
  152. /* Setup the ST7032 Co command */
  153. msg.frequency = CONFIG_ST7032_I2C_FREQ; /* I2C frequency */
  154. msg.addr = ST7032_I2C_ADDR; /* 7-bit address */
  155. msg.flags = 0; /* Write transaction, beginning with START */
  156. msg.buffer = (FAR uint8_t *) data; /* Transfer from this address */
  157. msg.length = 2; /* Send two bytes: Co command + cmd */
  158. /* Perform the transfer */
  159. ret = I2C_TRANSFER(priv->i2c, &msg, 1);
  160. if (ret < 0)
  161. {
  162. lcderr("ERROR: I2C_TRANSFER failed: %d\n", ret);
  163. }
  164. /* Delay 30us */
  165. nxsig_usleep(30);
  166. }
  167. static inline void st7032_setcontrast(FAR struct st7032_dev_s *priv,
  168. int8_t contrast)
  169. {
  170. if (contrast < ST7032_CONTRAST_MIN)
  171. {
  172. contrast = ST7032_CONTRAST_MIN;
  173. }
  174. else if (contrast > ST7032_CONTRAST_MAX)
  175. {
  176. contrast = ST7032_CONTRAST_MAX;
  177. }
  178. st7032_write_inst(priv, ST7032_CONTRAST_SET | (contrast & 0x0f));
  179. st7032_write_inst(priv, (contrast >> 4) | ST7032_POWER_ICON_CTRL_SET |
  180. POWER_ICON_BOST_CTRL_BON);
  181. }
  182. /****************************************************************************
  183. * Name: lcd_getdata
  184. *
  185. * Description:
  186. * Simulate reading data from LCD, we are reading from internal buffer
  187. *
  188. ****************************************************************************/
  189. static inline uint8_t lcd_getdata(FAR struct st7032_dev_s *priv)
  190. {
  191. uint8_t data;
  192. data = priv->buffer[priv->row * priv->col];
  193. return data;
  194. }
  195. /****************************************************************************
  196. * Name: rc2addr
  197. *
  198. * Description:
  199. * This converts a row/column pair to a screen memory address.
  200. *
  201. ****************************************************************************/
  202. static inline uint8_t rc2addr(FAR struct st7032_dev_s *priv)
  203. {
  204. /* line0 @ 0x00 - 0x27, line1 @ 0x40-0x67 */
  205. return priv->row * 0x40 + priv->col;
  206. }
  207. /****************************************************************************
  208. * Name: addr2rc
  209. *
  210. * Description:
  211. * This converts a screen memory address to a row/column pair.
  212. *
  213. ****************************************************************************/
  214. static inline void addr2rc(FAR struct st7032_dev_s *priv, uint8_t addr,
  215. FAR uint8_t *row, FAR uint8_t *col)
  216. {
  217. *row = addr / 0x40;
  218. *col = addr % 0x40;
  219. }
  220. /****************************************************************************
  221. * Name: lcd_set_curpos
  222. *
  223. * Description:
  224. * This sets the cursor position based on row, column addressing.
  225. *
  226. * Input Parameters:
  227. * priv - device instance
  228. *
  229. ****************************************************************************/
  230. static void lcd_set_curpos(FAR struct st7032_dev_s *priv)
  231. {
  232. uint8_t addr;
  233. addr = rc2addr(priv);
  234. st7032_write_inst(priv, ST7032_SET_DDRAM_ADDR | addr); /* set DDRAM address */
  235. }
  236. /****************************************************************************
  237. * Name: lcd_putdata
  238. *
  239. * Description:
  240. * Write a byte to the LCD and update column/row position
  241. *
  242. ****************************************************************************/
  243. static inline void lcd_putdata(FAR struct st7032_dev_s *priv, uint8_t data)
  244. {
  245. /* Send data to display */
  246. st7032_write_data(priv, data);
  247. /* Save it in the buffer because we cannot read from display */
  248. priv->buffer[priv->col * priv->row] = data;
  249. /* Update col/row positions */
  250. priv->col++;
  251. if (priv->col >= ST7032_MAX_COL)
  252. {
  253. priv->col = 0;
  254. priv->row++;
  255. }
  256. if (priv->row >= ST7032_MAX_ROW)
  257. {
  258. priv->pendscroll = true;
  259. priv->row = ST7032_MAX_ROW - 1;
  260. }
  261. /* Update cursor position */
  262. lcd_set_curpos(priv);
  263. }
  264. /****************************************************************************
  265. * Name: lcd_scroll_up
  266. *
  267. * Description:
  268. * Scroll the display up, and clear the new (last) line.
  269. *
  270. ****************************************************************************/
  271. static void lcd_scroll_up(FAR struct st7032_dev_s *priv)
  272. {
  273. FAR uint8_t *data;
  274. int currow;
  275. int curcol;
  276. data = (FAR uint8_t *)kmm_malloc(ST7032_MAX_COL);
  277. if (NULL == data)
  278. {
  279. lcdinfo("Failed to allocate buffer in lcd_scroll_up()\n");
  280. return;
  281. }
  282. /* Clear display */
  283. st7032_write_inst(priv, ST7032_CLEAR_DISPLAY);
  284. for (currow = 1; currow < ST7032_MAX_ROW; ++currow)
  285. {
  286. priv->row = currow;
  287. for (curcol = 0; curcol < ST7032_MAX_COL; ++curcol)
  288. {
  289. priv->col = curcol;
  290. data[curcol] = lcd_getdata(priv);
  291. }
  292. priv->col = 0;
  293. priv->row = currow - 1;
  294. lcd_set_curpos(priv);
  295. for (curcol = 0; curcol < ST7032_MAX_COL; ++curcol)
  296. {
  297. lcd_putdata(priv, data[curcol]);
  298. }
  299. }
  300. priv->col = 0;
  301. priv->row = ST7032_MAX_ROW - 1;
  302. lcd_set_curpos(priv);
  303. for (curcol = 0; curcol < ST7032_MAX_COL; ++curcol)
  304. {
  305. lcd_putdata(priv, ' ');
  306. }
  307. priv->col = 0;
  308. priv->row = ST7032_MAX_ROW - 1;
  309. lcd_set_curpos(priv);
  310. kmm_free(data);
  311. return;
  312. }
  313. /****************************************************************************
  314. * Name: lcd_codec_action
  315. *
  316. * Description:
  317. * Perform an 'action' as per the Segment LCD codec.
  318. *
  319. * Input Parameters:
  320. * priv - device instance
  321. * code - SLCD code action code
  322. * count - count param for those actions that take it
  323. *
  324. ****************************************************************************/
  325. static void lcd_codec_action(FAR struct st7032_dev_s *priv,
  326. enum slcdcode_e code, uint8_t count)
  327. {
  328. switch (code)
  329. {
  330. /* Erasure */
  331. case SLCDCODE_BACKDEL: /* Backspace (backward delete) N characters */
  332. {
  333. if (count <= 0) /* we need to delete more 0 positions */
  334. {
  335. break;
  336. }
  337. else
  338. {
  339. if (count > priv->col) /* saturate to preceding columns available */
  340. {
  341. count = priv->col;
  342. }
  343. priv->col = priv->col - count;
  344. lcd_set_curpos(priv);
  345. }
  346. /* ... and conscientiously fall through to next case ... */
  347. }
  348. case SLCDCODE_FWDDEL: /* Delete (forward delete) N characters, moving text */
  349. {
  350. if (count <= 0) /* we need to delete more 0 positions */
  351. {
  352. break;
  353. }
  354. else
  355. {
  356. uint8_t start;
  357. uint8_t end;
  358. uint8_t i;
  359. uint8_t data;
  360. start = priv->col + count;
  361. if (start >= ST7032_MAX_COL) /* silly case of nothing left */
  362. {
  363. break;
  364. }
  365. end = start + count;
  366. if (end > ST7032_MAX_COL) /* saturate */
  367. {
  368. end = ST7032_MAX_COL;
  369. }
  370. for (i = priv->col; i < end; ++start, ++i) /* much like memmove */
  371. {
  372. priv->col = start;
  373. lcd_set_curpos(priv);
  374. data = lcd_getdata(priv);
  375. priv->col = i;
  376. lcd_set_curpos(priv);
  377. lcd_putdata(priv, data);
  378. }
  379. for (; i < ST7032_MAX_COL; ++i) /* much like memset */
  380. {
  381. lcd_putdata(priv, ' ');
  382. }
  383. lcd_set_curpos(priv);
  384. }
  385. }
  386. break;
  387. case SLCDCODE_ERASE: /* Erase N characters from the cursor position */
  388. if (count > 0)
  389. {
  390. uint8_t end;
  391. uint8_t i;
  392. end = priv->col + count;
  393. if (end > ST7032_MAX_COL)
  394. {
  395. end = ST7032_MAX_COL;
  396. }
  397. for (i = priv->col; i < end; ++i)
  398. {
  399. lcd_putdata(priv, ' ');
  400. }
  401. lcd_set_curpos(priv);
  402. }
  403. break;
  404. case SLCDCODE_CLEAR: /* Home the cursor and erase the entire display */
  405. {
  406. st7032_write_inst(priv, ST7032_CLEAR_DISPLAY);
  407. }
  408. break;
  409. case SLCDCODE_ERASEEOL: /* Erase from the cursor position to the end of line */
  410. {
  411. uint8_t i;
  412. for (i = priv->col; i < ST7032_MAX_COL; ++i)
  413. {
  414. lcd_putdata(priv, ' ');
  415. }
  416. lcd_set_curpos(priv);
  417. }
  418. break;
  419. /* Cursor movement */
  420. case SLCDCODE_LEFT: /* Cursor left by N characters */
  421. {
  422. if (count > priv->col)
  423. {
  424. priv->col = 0;
  425. }
  426. else
  427. {
  428. priv->col -= count;
  429. }
  430. lcd_set_curpos(priv);
  431. }
  432. break;
  433. case SLCDCODE_RIGHT: /* Cursor right by N characters */
  434. {
  435. priv->col += count;
  436. if (priv->col >= ST7032_MAX_COL)
  437. {
  438. priv->col = ST7032_MAX_COL - 1;
  439. }
  440. lcd_set_curpos(priv);
  441. }
  442. break;
  443. case SLCDCODE_UP: /* Cursor up by N lines */
  444. {
  445. if (count > priv->row)
  446. {
  447. priv->row = 0;
  448. }
  449. else
  450. {
  451. priv->row -= count;
  452. }
  453. lcd_set_curpos(priv);
  454. }
  455. break;
  456. case SLCDCODE_DOWN: /* Cursor down by N lines */
  457. {
  458. priv->row += count;
  459. if (priv->row >= ST7032_MAX_ROW)
  460. {
  461. priv->row = ST7032_MAX_ROW - 1;
  462. }
  463. lcd_set_curpos(priv);
  464. }
  465. break;
  466. case SLCDCODE_HOME: /* Cursor home */
  467. {
  468. priv->col = 0;
  469. lcd_set_curpos(priv);
  470. }
  471. break;
  472. case SLCDCODE_END: /* Cursor end */
  473. {
  474. priv->col = ST7032_MAX_COL - 1;
  475. lcd_set_curpos(priv);
  476. }
  477. break;
  478. case SLCDCODE_PAGEUP: /* Cursor up by N pages */
  479. case SLCDCODE_PAGEDOWN: /* Cursor down by N pages */
  480. break; /* Not supportable on this SLCD */
  481. /* Blinking */
  482. case SLCDCODE_BLINKSTART: /* Start blinking with current cursor position */
  483. st7032_write_inst(priv, ST7032_DISPLAY_ON_OFF | DISPLAY_ON_OFF_D |
  484. DISPLAY_ON_OFF_C | DISPLAY_ON_OFF_B);
  485. break;
  486. case SLCDCODE_BLINKEND: /* End blinking after the current cursor position */
  487. case SLCDCODE_BLINKOFF: /* Turn blinking off */
  488. st7032_write_inst(priv, ST7032_DISPLAY_ON_OFF | DISPLAY_ON_OFF_D |
  489. DISPLAY_ON_OFF_C);
  490. break; /* Not implemented */
  491. /* These are actually unreportable errors */
  492. default:
  493. case SLCDCODE_NORMAL: /* Not a special keycode */
  494. break;
  495. }
  496. }
  497. /****************************************************************************
  498. * Name: lcd_getstream
  499. *
  500. * Description:
  501. * Get one character from the LCD codec stream.
  502. *
  503. ****************************************************************************/
  504. static int lcd_getstream(FAR struct lib_instream_s *instream)
  505. {
  506. FAR struct lcd_instream_s *lcdstream =
  507. (FAR struct lcd_instream_s *)instream;
  508. if (lcdstream->nbytes > 0)
  509. {
  510. lcdstream->nbytes--;
  511. lcdstream->stream.nget++;
  512. return (int)*lcdstream->buffer++;
  513. }
  514. return EOF;
  515. }
  516. /****************************************************************************
  517. * Name: lcd_init
  518. *
  519. * Description:
  520. * perform the initialization sequence to get the LCD into a known state.
  521. *
  522. ****************************************************************************/
  523. static void lcd_init(FAR struct st7032_dev_s *priv)
  524. {
  525. uint8_t data;
  526. /* Initialize the Display */
  527. data = ST7032_FUNCTION_SET | FUNCTION_SET_DL | FUNCTION_SET_N |
  528. FUNCTION_SET_IS;
  529. st7032_write_inst(priv, data);
  530. data = ST7032_INT_OSC_FREQ | INT_OSC_FREQ_BS | INT_OSC_FREQ_F2;
  531. st7032_write_inst(priv, data);
  532. data = ST7032_POWER_ICON_CTRL_SET | POWER_ICON_BOST_CTRL_ION;
  533. st7032_write_inst(priv, data);
  534. /* Set contrast */
  535. st7032_setcontrast(priv, DEFAULT_CONTRAST);
  536. data = ST7032_FOLLOWER_CTRL | FOLLOWER_CTRL_FON | FOLLOWER_CTRL_RAB2;
  537. st7032_write_inst(priv, data);
  538. /* Turn ON Display and Cursor Blinking */
  539. data = ST7032_DISPLAY_ON_OFF | DISPLAY_ON_OFF_D | DISPLAY_ON_OFF_C |
  540. DISPLAY_ON_OFF_B;
  541. st7032_write_inst(priv, data);
  542. /* Increasing Mode: Writing from Left to Right */
  543. data = ST7032_ENTRY_MODE_SET | ENTRY_MODE_SET_ID;
  544. st7032_write_inst(priv, data);
  545. /* Clear Display */
  546. data = ST7032_CLEAR_DISPLAY;
  547. st7032_write_inst(priv, data);
  548. }
  549. /****************************************************************************
  550. * Name: lcd_curpos_to_fpos
  551. *
  552. * Description:
  553. * Convert a screen cursor pos (row,col) to a file logical offset. This
  554. * includes 'synthesized' line feeds at the end of screen lines.
  555. *
  556. ****************************************************************************/
  557. static void lcd_curpos_to_fpos(FAR struct st7032_dev_s *priv,
  558. uint8_t row, uint8_t col, FAR off_t *fpos)
  559. {
  560. /* the logical file position is the linear position plus any synthetic LF */
  561. *fpos = (row * ST7032_MAX_COL) + col + row;
  562. }
  563. /****************************************************************************
  564. * Name: st7032_open
  565. *
  566. * Description:
  567. * This function is called whenever the ST7032 device is opened.
  568. *
  569. ****************************************************************************/
  570. static int st7032_open(FAR struct file *filep)
  571. {
  572. return OK;
  573. }
  574. /****************************************************************************
  575. * Name: st7032_close
  576. *
  577. * Description:
  578. * This routine is called when the LM-75 device is closed.
  579. *
  580. ****************************************************************************/
  581. static int st7032_close(FAR struct file *filep)
  582. {
  583. return OK;
  584. }
  585. /****************************************************************************
  586. * Name: st7032_read
  587. ****************************************************************************/
  588. static ssize_t st7032_read(FAR struct file *filep, FAR char *buffer,
  589. size_t buflen)
  590. {
  591. return -ENOSYS;
  592. }
  593. /****************************************************************************
  594. * Name: st7032_write
  595. ****************************************************************************/
  596. static ssize_t st7032_write(FAR struct file *filep, FAR const char *buffer,
  597. size_t buflen)
  598. {
  599. FAR struct inode *inode = filep->f_inode;
  600. FAR struct st7032_dev_s *priv = inode->i_private;
  601. struct lcd_instream_s instream;
  602. struct slcdstate_s state;
  603. enum slcdret_e result;
  604. uint8_t ch;
  605. uint8_t count;
  606. nxsem_wait(&priv->sem_excl);
  607. /* Initialize the stream for use with the SLCD CODEC */
  608. instream.stream.get = lcd_getstream;
  609. instream.stream.nget = 0;
  610. instream.buffer = buffer;
  611. instream.nbytes = buflen;
  612. /* Now decode and process every byte in the input buffer */
  613. memset(&state, 0, sizeof(struct slcdstate_s));
  614. while ((result = slcd_decode(&instream.stream, &state, &ch, &count)) !=
  615. SLCDRET_EOF)
  616. {
  617. /* Is there some pending scroll? */
  618. if (priv->pendscroll)
  619. {
  620. lcd_scroll_up(priv);
  621. priv->pendscroll = false;
  622. }
  623. if (result == SLCDRET_CHAR) /* A normal character was returned */
  624. {
  625. /* Check for ASCII control characters */
  626. if (ch == ASCII_TAB)
  627. {
  628. /* Blink Cursor? Shouldn't it be just 4 spaces to indicate
  629. * TAB?
  630. */
  631. st7032_write_inst(priv, ST7032_DISPLAY_ON_OFF |
  632. DISPLAY_ON_OFF_D | DISPLAY_ON_OFF_C |
  633. DISPLAY_ON_OFF_B);
  634. }
  635. else if (ch == ASCII_VT)
  636. {
  637. /* Turn the backlight on */
  638. /* TODO: lcd_backlight(priv, true); */
  639. }
  640. else if (ch == ASCII_FF)
  641. {
  642. /* Turn the backlight off */
  643. /* TODO: lcd_backlight(priv, false); */
  644. }
  645. else if (ch == ASCII_CR)
  646. {
  647. /* Perform a Home */
  648. priv->col = 0;
  649. lcd_set_curpos(priv);
  650. }
  651. else if (ch == ASCII_SO)
  652. {
  653. st7032_write_inst(priv, ST7032_DISPLAY_ON_OFF |
  654. DISPLAY_ON_OFF_D);
  655. }
  656. else if (ch == ASCII_SI)
  657. {
  658. /* Perform the re-initialize */
  659. lcd_init(priv);
  660. priv->row = 0;
  661. priv->col = 0;
  662. }
  663. else if (ch == ASCII_LF)
  664. {
  665. /* unixian line term; go to start of next line */
  666. priv->row += 1;
  667. if (priv->row >= ST7032_MAX_ROW)
  668. {
  669. priv->pendscroll = true;
  670. priv->row = ST7032_MAX_ROW - 1;
  671. }
  672. priv->col = 0;
  673. lcd_set_curpos(priv);
  674. }
  675. else if (ch == ASCII_BS)
  676. {
  677. /* Perform the backward deletion */
  678. lcd_codec_action(priv, SLCDCODE_BACKDEL, 1);
  679. }
  680. else if (ch == ASCII_DEL)
  681. {
  682. /* Perform the forward deletion */
  683. lcd_codec_action(priv, SLCDCODE_FWDDEL, 1);
  684. }
  685. else
  686. {
  687. /* Just print it! */
  688. lcd_putdata(priv, ch);
  689. }
  690. }
  691. else /* (result == SLCDRET_SPEC) */ /* A special SLCD action was returned */
  692. {
  693. lcd_codec_action(priv, (enum slcdcode_e)ch, count);
  694. }
  695. }
  696. /* Wherever we wound up, update our logical file pos to reflect it */
  697. lcd_curpos_to_fpos(priv, priv->row, priv->col, &filep->f_pos);
  698. nxsem_post(&priv->sem_excl);
  699. return buflen;
  700. }
  701. /****************************************************************************
  702. * Name: st7032_seek
  703. *
  704. * Description:
  705. * Seek the logical file pointer to the specified position. This is
  706. * probably not very interesting except possibly for (SEEK_SET, 0) to
  707. * rewind the pointer for a subsequent read().
  708. * The file pointer is logical, and includes synthesized LF chars at the
  709. * end of the display lines.
  710. *
  711. ****************************************************************************/
  712. static off_t st7032_seek(FAR struct file *filep, off_t offset, int whence)
  713. {
  714. FAR struct inode *inode = filep->f_inode;
  715. FAR struct st7032_dev_s *priv =
  716. (FAR struct st7032_dev_s *)inode->i_private;
  717. off_t maxpos;
  718. off_t pos;
  719. nxsem_wait(&priv->sem_excl);
  720. maxpos = ST7032_MAX_ROW * ST7032_MAX_COL + (ST7032_MAX_ROW - 1);
  721. pos = filep->f_pos;
  722. switch (whence)
  723. {
  724. case SEEK_CUR:
  725. pos += offset;
  726. if (pos > maxpos)
  727. {
  728. pos = maxpos;
  729. }
  730. else if (pos < 0)
  731. {
  732. pos = 0;
  733. }
  734. filep->f_pos = pos;
  735. break;
  736. case SEEK_SET:
  737. pos = offset;
  738. if (pos > maxpos)
  739. {
  740. pos = maxpos;
  741. }
  742. else if (pos < 0)
  743. {
  744. pos = 0;
  745. }
  746. filep->f_pos = pos;
  747. break;
  748. case SEEK_END:
  749. pos = maxpos + offset;
  750. if (pos > maxpos)
  751. {
  752. pos = maxpos;
  753. }
  754. else if (pos < 0)
  755. {
  756. pos = 0;
  757. }
  758. filep->f_pos = pos;
  759. break;
  760. default:
  761. /* Return EINVAL if the whence argument is invalid */
  762. pos = (off_t)-EINVAL;
  763. break;
  764. }
  765. nxsem_post(&priv->sem_excl);
  766. return pos;
  767. }
  768. /****************************************************************************
  769. * Name: st7032_ioctl
  770. *
  771. * Description:
  772. * Perform device operations that are outside the standard I/O model.
  773. *
  774. ****************************************************************************/
  775. static int st7032_ioctl(FAR struct file *filep, int cmd,
  776. unsigned long arg)
  777. {
  778. switch (cmd)
  779. {
  780. case SLCDIOC_GETATTRIBUTES: /* Get the attributes of the SLCD */
  781. {
  782. FAR struct inode *inode = filep->f_inode;
  783. FAR struct slcd_attributes_s *attr =
  784. (FAR struct slcd_attributes_s *)((uintptr_t)arg);
  785. lcdinfo("SLCDIOC_GETATTRIBUTES:\n");
  786. if (!attr)
  787. {
  788. return -EINVAL;
  789. }
  790. attr->nrows = ST7032_MAX_ROW;
  791. attr->ncolumns = ST7032_MAX_COL;
  792. attr->nbars = 0;
  793. attr->maxcontrast = 0;
  794. attr->maxbrightness = 1; /* 'brightness' for us is the backlight */
  795. }
  796. break;
  797. case SLCDIOC_CURPOS: /* Get the SLCD cursor position */
  798. {
  799. FAR struct inode *inode = filep->f_inode;
  800. FAR struct st7032_dev_s *priv =
  801. (FAR struct st7032_dev_s *)inode->i_private;
  802. FAR struct slcd_curpos_s *attr =
  803. (FAR struct slcd_curpos_s *)((uintptr_t)arg);
  804. attr->row = priv->row;
  805. attr->column = priv->col;
  806. }
  807. break;
  808. case SLCDIOC_GETBRIGHTNESS: /* Get the current brightness setting */
  809. {
  810. FAR struct inode *inode = filep->f_inode;
  811. FAR struct st7032_dev_s *priv =
  812. (FAR struct st7032_dev_s *)inode->i_private;
  813. nxsem_wait(&priv->sem_excl);
  814. *(FAR int *)((uintptr_t)arg) = 1; /* Hardcoded */
  815. nxsem_post(&priv->sem_excl);
  816. }
  817. break;
  818. case SLCDIOC_SETBRIGHTNESS: /* Set the brightness to a new value */
  819. {
  820. FAR struct inode *inode = filep->f_inode;
  821. FAR struct st7032_dev_s *priv =
  822. (FAR struct st7032_dev_s *)inode->i_private;
  823. nxsem_wait(&priv->sem_excl);
  824. /* TODO: set display contrast */
  825. nxsem_post(&priv->sem_excl);
  826. }
  827. break;
  828. case SLCDIOC_SETBAR: /* Set bars on a bar display */
  829. case SLCDIOC_GETCONTRAST: /* Get the current contrast setting */
  830. case SLCDIOC_SETCONTRAST: /* Set the contrast to a new value */
  831. default:
  832. return -ENOTTY;
  833. }
  834. return OK;
  835. }
  836. /****************************************************************************
  837. * Public Functions
  838. ****************************************************************************/
  839. /****************************************************************************
  840. * Name: st7032_register
  841. *
  842. * Description:
  843. * Register the ST7032 character device as 'devpath'
  844. *
  845. * Input Parameters:
  846. * devpath - The full path to the driver to register. E.g., "/dev/temp0"
  847. * i2c - An instance of the I2C interface to use to communicate with
  848. * ST7032
  849. *
  850. * Returned Value:
  851. * Zero (OK) on success; a negated errno value on failure.
  852. *
  853. ****************************************************************************/
  854. int st7032_register(FAR const char *devpath, FAR struct i2c_master_s *i2c)
  855. {
  856. FAR struct st7032_dev_s *priv;
  857. int ret;
  858. /* Initialize the ST7032 device structure */
  859. priv = (FAR struct st7032_dev_s *)kmm_malloc(sizeof(struct st7032_dev_s));
  860. if (!priv)
  861. {
  862. snerr("ERROR: Failed to allocate instance\n");
  863. return -ENOMEM;
  864. }
  865. /* Setup priv with initial values */
  866. priv->i2c = i2c;
  867. priv->col = 0;
  868. priv->row = 0;
  869. priv->pendscroll = false;
  870. nxsem_init(&priv->sem_excl, 0, 1);
  871. /* Initialize the display */
  872. lcd_init(priv);
  873. /* Register the driver */
  874. ret = register_driver(devpath, &g_st7032fops, 0666, priv);
  875. if (ret < 0)
  876. {
  877. snerr("ERROR: Failed to register driver: %d\n", ret);
  878. kmm_free(priv);
  879. }
  880. return ret;
  881. }
  882. #endif /* CONFIG_SPI && CONFIG_ST7032 */