wiringPi/example: Add i2c lcd example

Signed-off-by: Steve Jeong <how2soft@gmail.com>
Change-Id: I491a6aad8da6c606638f885921a7174017507ef1
diff --git a/examples/Makefile.am b/examples/Makefile.am
index ab6cacc..9da4f7f 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -3,7 +3,7 @@
 COMMON_CFLAGS = $(EXTRA_CFLAGS) $(LIBWIRINGPI_CFLAGS)
 LIBS = $(LIBWIRINGPI_LIBS)
 
-bin_PROGRAMS = blink blink12 blink12drcs blink8 clock delayTest ds1302 isr isr-osc lcd lcd-adafruit max31855 nes okLed pwm rht03 serialRead serialTest softPwm softTone speed wfi
+bin_PROGRAMS = blink blink12 blink12drcs blink8 clock delayTest ds1302 isr isr-osc i2c-lcd lcd lcd-adafruit max31855 nes okLed pwm rht03 serialRead serialTest softPwm softTone speed wfi
 
 blink_SOURCES = blink.c
 blink_CFLAGS = $(COMMON_CFLAGS)
@@ -33,6 +33,9 @@
 isr_osc_SOURCES = isr-osc.c
 isr_osc_CFLAGS = $(COMMON_CFLAGS)
 
+i2c_lcd_SOURCES = i2c-lcd.c
+i2c_lcd_CFLAGS = $(COMMON_CFLAGS)
+
 lcd_SOURCES = lcd.c
 lcd_CFLAGS = $(COMMON_CFLAGS)
 
diff --git a/examples/i2c-lcd.c b/examples/i2c-lcd.c
new file mode 100644
index 0000000..e19c9eb
--- /dev/null
+++ b/examples/i2c-lcd.c
@@ -0,0 +1,138 @@
+/*
+ * i2c_lcd.c:
+ *   Standard "i2c_lcd" program in wiringPi.
+ *   Supports 16x2 and 20x4 screens.
+ *   reference: lcd_i2c.py (https://bitbucket.org/MattHawkinsUK/rpispy-misc/raw/master/python/lcd_i2c.py)
+ *
+ * Copyright (C) 2023 Steve Jeong
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <wiringPiI2C.h>
+#include <wiringPi.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+// Define some device parameters
+#define I2C_ADDR  0x3f // I2C device address
+#define LCD_WIDTH  20
+
+// Define some device constants
+#define LCD_CHR  1 // Mode - Sending data
+#define LCD_CMD  0 // Mode - Sending command
+
+#define LINE1  0x80 // 1st line
+#define LINE2  0xC0 // 2nd line
+#define LINE3  0x94 // 3rd line
+#define LINE4  0xD4 // 4th line
+
+#define LCD_BACKLIGHT   0x08  // On
+// LCD_BACKLIGHT = 0x00  # Off
+
+#define ENABLE  0b00000100 // Enable bit
+
+void lcd_init(void);
+void lcd_byte(int bits, int mode);
+void lcd_toggle_enable(int bits);
+void display_string(const char *string, int line);
+
+int fd;
+char *bus; /* /dev/i2c-0 ~ /dev/i2c-9 */
+int address;
+
+int main(int argc, char *argv[]) {
+
+  char device[16] = "/dev/i2c-";
+
+  bus = "0";
+  address = 0x3f;
+
+  if (wiringPiSetup () == -1)
+    exit (1);
+
+  if (argc > 1)
+    address = strtoul(argv[1], NULL, 16);
+
+  if (argc > 2) {
+    bus = argv[1];
+    address = strtoul(argv[2], NULL, 16);
+  }
+
+  strncat(device, bus, 1);
+  fd = wiringPiI2CSetupInterface(device, address);
+
+  lcd_init(); // setup LCD
+
+  while (1) {
+    display_string("Hard Kernel", LINE1);
+    display_string("Hello ODROID", LINE2);
+  }
+
+  return 0;
+
+}
+
+void display_string(const char *string, int line) {
+  // go to location on LCD
+  lcd_byte(line, LCD_CMD);
+
+  if (strlen(string) > LCD_WIDTH) {
+    printf("message is too long!\n");
+    return;
+  }
+
+  while (*string) lcd_byte(*(string++), LCD_CHR);
+}
+
+void lcd_byte(int bits, int mode) {
+
+  //Send byte to data pins
+  // bits = the data
+  // mode = 1 for data, 0 for command
+  int bits_high;
+  int bits_low;
+  // uses the two half byte writes to LCD
+  bits_high = mode | (bits & 0xf0) | LCD_BACKLIGHT ;
+  bits_low = mode | ((bits << 4) & 0xf0) | LCD_BACKLIGHT ;
+
+  // High bits
+  wiringPiI2CReadReg8(fd, bits_high);
+  lcd_toggle_enable(bits_high);
+
+  // Low bits
+  wiringPiI2CReadReg8(fd, bits_low);
+  lcd_toggle_enable(bits_low);
+}
+
+void lcd_toggle_enable(int bits)   {
+  // Toggle enable pin on LCD display
+  delayMicroseconds(500);
+  wiringPiI2CReadReg8(fd, (bits | ENABLE));
+  delayMicroseconds(500);
+  wiringPiI2CReadReg8(fd, (bits & ~ENABLE));
+  delayMicroseconds(500);
+}
+
+void lcd_init()   {
+  // Initialise display
+  lcd_byte(0x33, LCD_CMD); // Initialise
+  lcd_byte(0x32, LCD_CMD); // Initialise
+  lcd_byte(0x06, LCD_CMD); // Cursor move direction
+  lcd_byte(0x0C, LCD_CMD); // 0x0F On, Blink Off
+  lcd_byte(0x28, LCD_CMD); // Data length, number of lines, font size
+  lcd_byte(0x01, LCD_CMD); // Clear display
+  delayMicroseconds(1000);
+}