Update
authorNilsForssen <forssennils@gmail.com>
Mon, 2 Aug 2021 23:48:52 +0000 (01:48 +0200)
committerNilsForssen <forssennils@gmail.com>
Mon, 2 Aug 2021 23:48:52 +0000 (01:48 +0200)
components/u8g2 [new submodule]
main/Audiolib.cpp
main/Audiolib.h
main/CMakeLists.txt
main/Peripherals.cpp
main/Peripherals.h
main/main.cpp
main/u8g2_esp32_hal.cpp [new file with mode: 0644]
main/u8g2_esp32_hal.h [new file with mode: 0644]

diff --git a/components/u8g2 b/components/u8g2
new file mode 160000 (submodule)
index 0000000..7b2b60f
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit 7b2b60f4184acb8524142061e306d916e7e34ebd
index aeae0b0af8b7260900144c670b84e722eb4ad8ae..29a02264be1eff09cdee72fb4ef1dc1c0fea8d83 100644 (file)
@@ -5,15 +5,21 @@ void a2d_cb_redirect(esp_a2d_cb_event_t, esp_a2d_cb_param_t *);
 void a2d_data_cb_redirect(const uint8_t *, uint32_t);
 void avrc_cb_redirect(esp_avrc_ct_cb_event_t, esp_avrc_ct_cb_param_t *);
 
-Audiolib::Audiolib(const char *device_name)
+static al_event_cb_param_t sending_param;
+
+static bool sent_title = false;
+static bool sent_artist = false;
+static bool sent_album = false;
+
+Audiolib::Audiolib(const char *device_name, void (*on_change)(al_event_cb_t, al_event_cb_param_t*))
 {
     _devname = device_name;
     Audiolib_redirect = this;
+    this->on_change_cb = on_change;
 }
 
 void Audiolib::start()
 {
-
     nvs_flash_init();
     
     esp_bt_controller_config_t cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
@@ -118,14 +124,31 @@ void Audiolib::avrc_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *par
         {
         case ESP_AVRC_MD_ATTR_TITLE:
             title = text;
+            sent_title = true;
             break;
         case ESP_AVRC_MD_ATTR_ARTIST:
             artist = text;
+            sent_artist = true;
             break;
         case ESP_AVRC_MD_ATTR_ALBUM:
             album = text;
+            sent_album = true;
             break;
         }
+        if (sent_title && sent_artist && sent_album) {
+            sending_param.metadata = {
+            .title = this->title,
+            .artist = this->artist,
+            .album = this->album, 
+            };
+
+            on_change_cb(AL_META_UPDATE, &sending_param);
+
+            sent_title = false;
+            sent_artist = false;
+            sent_album = false;
+        }
+
         break;
     case ESP_AVRC_CT_PLAY_STATUS_RSP_EVT:
         printf("AVRC, Play status\n");
@@ -142,19 +165,18 @@ void Audiolib::avrc_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *par
             printf("AVRC, play status change\n");
             switch(param->change_ntf.event_parameter.playback) {
             case ESP_AVRC_PLAYBACK_STOPPED:
-                playing = false;
                 printf("AVRC, Playback stopped\n");
+                on_change_cb(AL_STOPPED, NULL);
                 break;
             case ESP_AVRC_PLAYBACK_PLAYING:
-                playing = true;
                 printf("AVRC, Playback playing\n");
+                on_change_cb(AL_PLAYING, NULL);
                 break;
             case ESP_AVRC_PLAYBACK_PAUSED:
-                playing = false;
                 printf("AVRC, Playback paused\n");
+                on_change_cb(AL_PAUSED, NULL);
                 break;
             case ESP_AVRC_PLAYBACK_ERROR:
-                playing = false;
                 printf("AVRC, Playback erorr\n");
                 break;
             default:
index 5fc6c914a0217bf32fd4fefa92c40c226f5662a8..916546c8fcbf70408d23c9b478cc31d78bde044f 100644 (file)
@@ -27,18 +27,34 @@ typedef enum {
     PEAK
 } filter_t;
 
+typedef enum {
+    AL_CONNECTED,
+    AL_DISCONNECTED,
+    AL_PLAYING,
+    AL_PAUSED,
+    AL_STOPPED,
+    AL_META_UPDATE
+} al_event_cb_t;
+
+typedef union {
+
+    struct al_meta_update_cb_param_t {
+        char* title;
+        char* artist;
+        char* album;
+    } metadata;
+
+} al_event_cb_param_t;
+
 class Audiolib;
 class Filter;
 struct CombinedChannelFilter;
 
+
+
 class Audiolib {
 public:
-    char* title = (char*)"";
-    char* artist = (char*)"";
-    char* album = (char*)"";
-    bool playing = false;
-
-    Audiolib(const char* device_name);
+    Audiolib(const char* device_name, void (*)(al_event_cb_t, al_event_cb_param_t*));
 
     void start();
     void stop();
@@ -66,6 +82,13 @@ public:
     
 
 private:
+
+    char* title = (char*)"";
+    char* artist = (char*)"";
+    char* album = (char*)"";
+
+    void (*on_change_cb)(al_event_cb_t, al_event_cb_param_t*);
+
     void getMeta();
     uint16_t supportedNotifications = 0x00;
     bool _filtering = true;
index 4f6aa19c3e9954849042d29b45e5a65b87efaea0..54f9ce8a1d5c0cf01eb458a4d7f5e18ec3ab1b74 100644 (file)
@@ -1,2 +1,2 @@
-idf_component_register(SRCS "Peripherals.cpp" "Audiolib.cpp" "main.cpp"
+idf_component_register(SRCS "Peripherals.cpp" "Audiolib.cpp" "main.cpp" "u8g2_esp32_hal.cpp"
                     INCLUDE_DIRS ".")
\ No newline at end of file
index 94d270d18a6ffebf391174c9e14714423f93f4ab..3bb459b471b8f6ec956d5580ede25b955cdbea75 100644 (file)
@@ -1,8 +1,5 @@
 #include "Peripherals.h"
 
-static const adc_atten_t atten = ADC_ATTEN_DB_0;
-static const adc_bits_width_t width = ADC_WIDTH_BIT_12;
-
 Potentiometer::Potentiometer(const int min, const int max, update_callback_t update_ntfy)
     : Potentiometer(ADC_UNIT_1, ADC_CHANNEL_1, min, max, update_ntfy) {}
 
@@ -90,4 +87,4 @@ int Potentiometer::update() {
 float Potentiometer::get_percent() {
     int raw = get_raw();
     return ((float)raw / (4096)) * 100;
-}
\ No newline at end of file
+}
index d65d612042ba618edb6d534b9ea5b35de5966b06..45e213cedaeb15ec46679e880268b7230e0ea751 100644 (file)
@@ -1,6 +1,5 @@
 #include "driver/adc.h"
 #include "esp_adc_cal.h"
-#include "esp_adc_cal.h"
 
 #ifndef Peripherals_H
 #define Peripherals_H
@@ -9,16 +8,13 @@
 #define VREF 1100
 #define AVERAGESUM 5
 
+#define atten ADC_ATTEN_DB_2_5
+#define width ADC_WIDTH_BIT_12
+
 typedef void(*update_callback_t)(float);
 
 class Potentiometer {
 public:
-    adc_unit_t adc_unit;
-    adc_channel_t adc_channel;
-    int min_raw;
-    int max_raw;
-    update_callback_t on_change;
-    int prev_raw;
     Potentiometer(const int, const int, update_callback_t = NULL);
     Potentiometer(const adc_unit_t, const adc_channel_t, const int, const int, update_callback_t = NULL);
     int get_raw();
@@ -26,13 +22,16 @@ public:
     float get_percent();
 
 private:
-
+    adc_unit_t adc_unit;
+    adc_channel_t adc_channel;
+    int min_raw;
+    int max_raw;
+    update_callback_t on_change;
+    int prev_raw;
+    
     static bool init_adc(const adc_unit_t, const adc_channel_t);
     static void check_efuse();
     static void print_char_val_type(esp_adc_cal_value_t);
-
-
-    
 };
 
 
index a63c0633cb37d8efb0b2b4dd6bafe200fe3442e2..27dbf6d5eee53845a31f8a79cdb5566dc4346e6a 100644 (file)
@@ -3,8 +3,9 @@
 #include "freertos/FreeRTOS.h"
 #include "freertos/task.h"
 #include "driver/gpio.h"
-#include <cmath>
-
+#include "u8g2.h"
+#include "u8g2_esp32_hal.h"
+#include "cstring"
 
 //void updateFilter(const uint8_t, float*, float*, CombinedChannelFilter*);
 Potentiometer* pot1 = new Potentiometer(ADC_UNIT_2, ADC_CHANNEL_5, 70, 1010); //65/66 -> 572/573 -> 1019
@@ -12,18 +13,53 @@ Potentiometer* pot1 = new Potentiometer(ADC_UNIT_2, ADC_CHANNEL_5, 70, 1010); //
 //Potentiometer* pot3 = new Potentiometer(ADC1_CHANNEL_6, 38, 988);
 //Potentiometer* pot4 = new Potentiometer(ADC1_CHANNEL_7, 29, 990);
 
-int sample_pot_percent(const adc1_channel_t*, float*);
-
-Audiolib Audiosource = Audiolib("Bluetooth Speaker");
-
 CombinedChannelFilter* highshelf_filter = new CombinedChannelFilter(new Filter(HIGHSHELF, 2000, 44100, 0.8, 0), new Filter(HIGHSHELF, 2000, 44100, 0.8, 0));
 CombinedChannelFilter* lowshelf_filter = new CombinedChannelFilter(new Filter(LOWSHELF, 250, 44100, 0.8, 0), new Filter(LOWSHELF, 250, 44100, 0.8, 0));
 CombinedChannelFilter* highpass_filter = new CombinedChannelFilter(new Filter(LOWPASS, 8000, 44100, 0.75, 0), new Filter(LOWPASS, 8000, 44100, 0.75, 0));
 CombinedChannelFilter* lowpass_filter = new CombinedChannelFilter(new Filter(HIGHPASS, 60, 44100, 0.75, 0), new Filter(HIGHPASS, 60, 44100, 0.75, 0));
 CombinedChannelFilter* peak_filter = new CombinedChannelFilter(new Filter(PEAK, 700, 44100, 0.8, 0), new Filter(PEAK, 700, 44100, 0.8, 0));
 
+u8g2_t u8g2;
+u8g2_uint_t displayHeight = u8g2_GetDisplayHeight(&u8g2);
+u8g2_uint_t displayWidth = u8g2_GetDisplayWidth(&u8g2);
+
+u8g2_esp32_hal_t u8g2_esp32_hal;
+
+struct timeval tv_now;
+
+static int x;
+static char* text;
+static int textWidth;
+static bool scrolling = false;
+static connected = false;
+
+void scrollText(char*);
+void update_display(al_event_cb_t, al_event_cb_param_t*);
+void draw_string(char* string, int x = 0);
+
+Audiolib Audiosource = Audiolib("Titta vad jag heter", &update_display);
+
 extern "C" {
     void app_main(void){
+
+       
+        u8g2_esp32_hal.sda = GPIO_NUM_32;
+        u8g2_esp32_hal.scl = GPIO_NUM_33;
+        u8g2_esp32_hal_init(u8g2_esp32_hal);
+
+        
+        u8g2_Setup_ssd1306_i2c_128x32_univision_f(
+            &u8g2,
+            U8G2_R0,
+            u8g2_esp32_i2c_byte_cb,
+            u8g2_esp32_gpio_and_delay_cb);
+
+        u8x8_SetI2CAddress(&u8g2.u8x8, 0x3C);
+        u8g2_InitDisplay(&u8g2);
+        u8g2_SetPowerSave(&u8g2, 0);
+        u8g2_SetFont(&u8g2, u8g2_font_ncenR24_tf);
+
+
         Audiosource.set_I2S(26, 27, 25);
 
         Audiosource.add_combined_filter(highpass_filter);
@@ -34,123 +70,110 @@ extern "C" {
         Audiosource.start();
     
         while (true) {
-            //printf("%d\n", pot1->update());
-            printf("%d\n", pot1->update());
-            printf("%f\n", pot1->get_percent());
+            while (connected) {
+
+
+
+
+
+            }
+            draw();
             vTaskDelay(pdMS_TO_TICKS(100));
         }
     }
 }
 
+void draw() {
+    u8g2_ClearBuffer(&u8g2);
+    u8g2_DrawStr(&u8g2, x, 32, text);
+    u8g2_SendBuffer(&ug82);
+}
 
-int sample_pot_percent(const adc1_channel_t* adc_channel, float* pot_val) {
-    float adc_val = 0;
-    for (int i = 0; i < 100; i++) {
-        adc_val += adc1_get_raw(*adc_channel);
+void scrollText(char* text) {
+    u8g2_ClearBuffer(&u8g2);
+    u8g2_DrawStr(&u8g2, x, 32, text);
+    u8g2_SendBuffer(&u8g2);
+    if (x == 0) {
+        vTaskDelay(pdMS_TO_TICKS(990));
+    }
+    
+    if ((textWidth + x) > u8g2_GetDisplayWidth(&u8g2)) {
+        x -= 1; 
     }
-    adc_val = adc_val/100;
-    if (*pot_val == 0) {
-        *pot_val = adc_val;
+    
+    else {
+        x = 0;
+        vTaskDelay(pdMS_TO_TICKS(990));
     }
-    *pot_val = (adc_val + (9*(*pot_val)) ) / 10;
+    vTaskDelay(pdMS_TO_TICKS(10));
+}
 
-    printf("%f\n", round(*pot_val) );
-    return 1;
+void update_display(al_event_cb_t event, al_event_cb_param_t* param) {
+    x = 0;
+    switch (event) {
+    case AL_CONNECTED:
+        scrolling = true;
+        text = (char*) "Connected!";
+        printf("AL, Connected\n");
+        connected = true;
+        break;
+    
+    case AL_DISCONNECTED:
+        scrolling = true;
+        text = (char*) "Disconnected!";
+        printf("AL, Disconnected\n");
+        break;
+    
+    case AL_PLAYING:
+        scrolling = false;
+        text = (char*) "PLAY";
+        printf("AL, Playing\n");
+        break;
+
+    case AL_PAUSED:
+        scrolling = false;
+        text = (char*) "PAUSE";
+        printf("AL, Paused\n");
+        break;
+
+    case AL_STOPPED:
+        printf("AL, Stopped\n");
+        break;
+
+    case AL_META_UPDATE:
+        scrolling = true;
+
+        int titleLen = strlen(param->metadata.title);
+        int artistLen = strlen(param->metadata.artist);
+
+        text = (char*) malloc(titleLen + artistLen + 3 + 1);        //Maybe runaway pointer every time this is done?
+        memcpy(text, param->metadata.title, titleLen);
+        memcpy(text + titleLen, (char*)" - ", 3);
+        memcpy(text + titleLen + 3, param->metadata.artist, artistLen);
+        *(text + titleLen + 3 + artistLen) = *"\0";
+
+        textWidth = u8g2_GetUTF8Width(&u8g2, text);
+        printf("%d\n", textWidth);
+        printf("%s\n", text);
+
+        printf("AL, Meta_Update\n");
+        break;
+    }
 }
 
-// void setup()
-// {
-//     pinMode(BUTTON1, INPUT);
-//     pinMode(BUTTON2, INPUT);
-//     pinMode(BUTTON3, INPUT);
-
-//     analogReadResolution(12);
-//     Serial.begin(115200);
-//     Audiosource.set_I2S(26, 27, 25);
-
-//     Audiosource.add_combined_filter(highpass_filter);
-//     Audiosource.add_combined_filter(lowshelf_filter);  
-//     Audiosource.add_combined_filter(peak_filter); 
-//     Audiosource.add_combined_filter(highshelf_filter);
-//     Audiosource.add_combined_filter(lowpass_filter);
-
-//     Audiosource.start();
-// }
-
-// void loop()
-// {
-//     currentMillis = millis();
-//     if (currentMillis - previousPotMillis >= potPollInterval)
-//     {
-//         previousPotMillis = currentMillis;
-//         updateFilter(POT1, &pot1val, &filter1gain, highshelf_filter);
-//         updateFilter(POT2, &pot2val, &filter2gain, peak_filter);
-//         updateFilter(POT3, &pot3val, &filter3gain, lowshelf_filter);
-//     }
-//     currentMillis = millis();
-//     if (currentMillis - previousButtonMillis >= buttonPollInterval)
-//     {
-//         previousButtonMillis = currentMillis;
-//         if (digitalRead(BUTTON1))
-//         {
-//             if (!prevButton1)
-//             {
-//                 printf("Start filter\n"); // Button 1
-//                 prevButton1 = true;
-//                 Audiosource.start_filter();
-//             }
-//         }
-//         else
-//         {
-//             prevButton1 = false;
-//         }
-//         if (digitalRead(BUTTON2))
-//         {
-//             if (!prevButton2)
-//             {
-//                 printf("Stop filter\n"); // Button 2
-//                 prevButton2 = true;
-//                 Audiosource.stop_filter();
-//             }
-//         }
-//         else
-//         {
-//             prevButton2 = false;
-//         }
-//         if (digitalRead(BUTTON3))
-//         {
-//             if (!prevButton3)
-//             {
-//                 printf("Button3\n"); // Button 3
-//                 Audiosource.pause();
-//                 printf("%s, %s, %s\n", Audiosource.title, Audiosource.artist, Audiosource.album);
-//                 prevButton3 = true;
-//             }
-//         }
-//         else
-//         {
-//             prevButton3 = false;
-//         }
-//     }
-// }
-
-// void updateFilter(const adc_channel_t adc_channel, float* potVal, float* prevGain, CombinedChannelFilter* filter)
-// {   
-//     *potVal = ((float(adc1_get_raw(adc_channel_1) adc_channel) * 20.00002 / 4095) - 10.00001 + (4*(*potVal))) / 5;
-
-//     printf
-
-//     if (!int(((fabs(*potVal)) * 2) + 0.75) * ((*potVal > 0) - (*potVal < 0))){
-//         if (*prevGain != 0){
-//             *prevGain = 0;
-//             filter->update(*prevGain);
-//         }
-//         return;
-//     }
-//     float diff = fabs(*potVal) - fabs(*prevGain);
-//     if (diff >= gainStep || diff <= -gainStep) {
-//         *prevGain = float(int(((fabs(*potVal)) * 2) + 0.5)) / 2 * ((*potVal > 0) - (*potVal < 0));
-//         filter->update(*prevGain);
-//         return;
-//     }
-// }
+
+/*
+int substr(char* string, int startPixel, int totPixels) {
+
+    int len = strlen(strin);
+    int newlen = (int) len/2;
+
+    char* newstr = (char*) malloc(newlen + 1);
+    memcpy(newstr, &str[start], newlen);
+    newstr[newlen] = *"\0";
+
+
+    if (pixels > u8g2_GetUTF8Width((int) len/2)
+    for (int i = 0; i < strlen(string))
+    
+}*/
\ No newline at end of file
diff --git a/main/u8g2_esp32_hal.cpp b/main/u8g2_esp32_hal.cpp
new file mode 100644 (file)
index 0000000..d44fef0
--- /dev/null
@@ -0,0 +1,239 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "sdkconfig.h"
+#include "esp_log.h"
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+
+#include "u8g2_esp32_hal.h"
+
+static const char *TAG = "u8g2_esp32_hal";
+static const unsigned int I2C_TIMEOUT_MS = 1000;
+
+static spi_device_handle_t handle_spi;      // SPI handle.
+static i2c_cmd_handle_t    handle_i2c;      // I2C handle.
+static u8g2_esp32_hal_t    u8g2_esp32_hal;  // HAL state data.
+
+#undef ESP_ERROR_CHECK
+#define ESP_ERROR_CHECK(x)   do { esp_err_t rc = (x); if (rc != ESP_OK) { ESP_LOGE("err", "esp_err_t = %d", rc); assert(0 && #x);} } while(0);
+
+/*
+ * Initialze the ESP32 HAL.
+ */
+void u8g2_esp32_hal_init(u8g2_esp32_hal_t u8g2_esp32_hal_param) {
+       u8g2_esp32_hal = u8g2_esp32_hal_param;
+} // u8g2_esp32_hal_init
+
+/*
+ * HAL callback function as prescribed by the U8G2 library.  This callback is invoked
+ * to handle SPI communications.
+ */
+uint8_t u8g2_esp32_spi_byte_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) {
+       ESP_LOGD(TAG, "spi_byte_cb: Received a msg: %d, arg_int: %d, arg_ptr: %p", msg, arg_int, arg_ptr);
+       switch(msg) {
+               case U8X8_MSG_BYTE_SET_DC:
+                       if (u8g2_esp32_hal.dc != U8G2_ESP32_HAL_UNDEFINED) {
+                               gpio_set_level(u8g2_esp32_hal.dc, arg_int);
+                       }
+                       break;
+
+               case U8X8_MSG_BYTE_INIT: {
+                       if (u8g2_esp32_hal.clk == U8G2_ESP32_HAL_UNDEFINED ||
+                                       u8g2_esp32_hal.mosi == U8G2_ESP32_HAL_UNDEFINED ||
+                                       u8g2_esp32_hal.cs == U8G2_ESP32_HAL_UNDEFINED) {
+                               break;
+                       }
+
+                 spi_bus_config_t bus_config;
+                  memset(&bus_config, 0, sizeof(spi_bus_config_t));
+                 bus_config.sclk_io_num   = u8g2_esp32_hal.clk; // CLK
+                 bus_config.mosi_io_num   = u8g2_esp32_hal.mosi; // MOSI
+                 bus_config.miso_io_num   = -1; // MISO
+                 bus_config.quadwp_io_num = -1; // Not used
+                 bus_config.quadhd_io_num = -1; // Not used
+                 //ESP_LOGI(TAG, "... Initializing bus.");
+                 ESP_ERROR_CHECK(spi_bus_initialize(HSPI_HOST, &bus_config, 1));
+
+                 spi_device_interface_config_t dev_config;
+                 memset(&dev_config, 0, sizeof(spi_device_interface_config_t));
+//               dev_config.address_bits     = 0;
+//               dev_config.command_bits     = 0;
+//               dev_config.dummy_bits       = 0;
+//               dev_config.mode             = 0;
+//               dev_config.duty_cycle_pos   = 0;
+//               dev_config.cs_ena_posttrans = 0;
+//               dev_config.cs_ena_pretrans  = 0;
+                 dev_config.clock_speed_hz   = 10000;
+                 dev_config.spics_io_num     = u8g2_esp32_hal.cs;
+//               dev_config.flags            = 0;
+                 dev_config.queue_size       = 200;
+//               dev_config.pre_cb           = NULL;
+//               dev_config.post_cb          = NULL;
+                 //ESP_LOGI(TAG, "... Adding device bus.");
+                 ESP_ERROR_CHECK(spi_bus_add_device(HSPI_HOST, &dev_config, &handle_spi));
+
+                 break;
+               }
+
+               case U8X8_MSG_BYTE_SEND: {
+                       spi_transaction_t trans_desc;
+                       trans_desc.addr      = 0;
+                       trans_desc.cmd           = 0;
+                       trans_desc.flags     = 0;
+                       trans_desc.length    = 8 * arg_int; // Number of bits NOT number of bytes.
+                       trans_desc.rxlength  = 0;
+                       trans_desc.tx_buffer = arg_ptr;
+                       trans_desc.rx_buffer = NULL;
+
+                       //ESP_LOGI(TAG, "... Transmitting %d bytes.", arg_int);
+                       ESP_ERROR_CHECK(spi_device_transmit(handle_spi, &trans_desc));
+                       break;
+               }
+       }
+       return 0;
+} // u8g2_esp32_spi_byte_cb
+
+/*
+ * HAL callback function as prescribed by the U8G2 library.  This callback is invoked
+ * to handle I2C communications.
+ */
+uint8_t u8g2_esp32_i2c_byte_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) {
+       ESP_LOGD(TAG, "i2c_cb: Received a msg: %d, arg_int: %d, arg_ptr: %p", msg, arg_int, arg_ptr);
+
+       switch(msg) {
+               case U8X8_MSG_BYTE_SET_DC:  //32
+                       if (u8g2_esp32_hal.dc != U8G2_ESP32_HAL_UNDEFINED) {
+                               gpio_set_level(u8g2_esp32_hal.dc, arg_int);
+                       }
+                       break;
+
+               case U8X8_MSG_BYTE_INIT:  //20
+                       if (u8g2_esp32_hal.sda == U8G2_ESP32_HAL_UNDEFINED ||
+                                       u8g2_esp32_hal.scl == U8G2_ESP32_HAL_UNDEFINED) {
+                               break;
+                       }
+                   //i2c_driver_delete(I2C_MASTER_NUM); // delete if already installed
+                   i2c_config_t conf;
+                   memset(&conf, 0, sizeof(i2c_config_t));
+                   conf.mode = I2C_MODE_MASTER;
+                   ESP_LOGI(TAG, "sda_io_num %d", u8g2_esp32_hal.sda);
+                   conf.sda_io_num = u8g2_esp32_hal.sda;
+                   //conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
+                   conf.sda_pullup_en = GPIO_PULLUP_DISABLE;                   // External pull-up required, 3K3 for Vcc=3.3V
+                   ESP_LOGI(TAG, "scl_io_num %d", u8g2_esp32_hal.scl);
+                   conf.scl_io_num = u8g2_esp32_hal.scl;
+                   //conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
+                   conf.scl_pullup_en = GPIO_PULLUP_DISABLE;                   // External pull-up required, 3K3 for Vcc=3.3V
+                   ESP_LOGI(TAG, "clk_speed %d", I2C_MASTER_FREQ_HZ);
+                   conf.master.clk_speed = I2C_MASTER_FREQ_HZ;
+                   ESP_LOGI(TAG, "clk_flags 0x%X", conf.clk_flags);
+                   ESP_LOGI(TAG, "i2c_param_config %d", conf.mode);
+                   ESP_ERROR_CHECK(i2c_param_config(I2C_MASTER_NUM, &conf));
+                   ESP_LOGI(TAG, "i2c_driver_install for I2C bus %d", I2C_MASTER_NUM);
+                   ESP_ERROR_CHECK(i2c_driver_install(I2C_MASTER_NUM, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0));
+                   ESP_LOGI(TAG, "i2c_driver_install done.");
+                       break;
+
+               case U8X8_MSG_BYTE_SEND: { //23
+                       uint8_t* data_ptr = (uint8_t*)arg_ptr;
+                       ESP_LOG_BUFFER_HEXDUMP(TAG, data_ptr, arg_int, ESP_LOG_VERBOSE);
+
+                       while( arg_int > 0 ) {
+                          ESP_ERROR_CHECK(i2c_master_write_byte(handle_i2c, *data_ptr, ACK_CHECK_EN));
+                          data_ptr++;
+                          arg_int--;
+                       }
+               }
+               break;
+
+               case U8X8_MSG_BYTE_START_TRANSFER: { //24
+                       uint8_t i2c_address = u8x8_GetI2CAddress(u8x8);
+                       handle_i2c = i2c_cmd_link_create();
+                       ESP_LOGD(TAG, "Start I2C transfer to 0x%02X", i2c_address);
+                       ESP_ERROR_CHECK(i2c_master_start(handle_i2c));
+                       ESP_ERROR_CHECK(i2c_master_write_byte(handle_i2c, ((i2c_address << 1) | I2C_MASTER_WRITE), ACK_CHECK_EN));
+               }
+               break;
+
+               case U8X8_MSG_BYTE_END_TRANSFER:  //25
+                       ESP_LOGD(TAG, "End I2C transfer.");
+                       ESP_ERROR_CHECK(i2c_master_stop(handle_i2c));
+                       ESP_ERROR_CHECK(i2c_master_cmd_begin(I2C_MASTER_NUM, handle_i2c, I2C_TIMEOUT_MS / portTICK_RATE_MS));
+                       i2c_cmd_link_delete(handle_i2c);
+                       break;
+       }
+       return 0;
+} // u8g2_esp32_i2c_byte_cb
+
+
+/*
+ * HAL callback function as prescribed by the U8G2 library.  This callback is invoked
+ * to handle callbacks for GPIO and delay functions.
+ */
+uint8_t u8g2_esp32_gpio_and_delay_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) {
+       ESP_LOGD(TAG, "gpio_and_delay_cb: Received a msg: %d, arg_int: %d, arg_ptr: %p", msg, arg_int, arg_ptr);
+
+       switch(msg) {
+       // Initialize the GPIO and DELAY HAL functions.  If the pins for DC and RESET have been
+       // specified then we define those pins as GPIO outputs.
+               case U8X8_MSG_GPIO_AND_DELAY_INIT: {
+                       uint64_t bitmask = 0;
+                       if (u8g2_esp32_hal.dc != U8G2_ESP32_HAL_UNDEFINED) {
+                               bitmask = bitmask | (1ull<<u8g2_esp32_hal.dc);
+                       }
+                       if (u8g2_esp32_hal.reset != U8G2_ESP32_HAL_UNDEFINED) {
+                               bitmask = bitmask | (1ull<<u8g2_esp32_hal.reset);
+                       }
+                       if (u8g2_esp32_hal.cs != U8G2_ESP32_HAL_UNDEFINED) {
+                               bitmask = bitmask | (1ull<<u8g2_esp32_hal.cs);
+                       }
+
+            if (bitmask==0) {
+               break;
+            }
+                       gpio_config_t gpioConfig;
+                       gpioConfig.pin_bit_mask = bitmask;
+                       gpioConfig.mode         = GPIO_MODE_OUTPUT;
+                       gpioConfig.pull_up_en   = GPIO_PULLUP_DISABLE;
+                       gpioConfig.pull_down_en = GPIO_PULLDOWN_ENABLE;
+                       gpioConfig.intr_type    = GPIO_INTR_DISABLE;
+                       gpio_config(&gpioConfig);
+                       break;
+               }
+
+       // Set the GPIO reset pin to the value passed in through arg_int.
+               case U8X8_MSG_GPIO_RESET:
+                       if (u8g2_esp32_hal.reset != U8G2_ESP32_HAL_UNDEFINED) {
+                               gpio_set_level(u8g2_esp32_hal.reset, arg_int);
+                       }
+                       break;
+       // Set the GPIO client select pin to the value passed in through arg_int.
+               case U8X8_MSG_GPIO_CS:
+                       if (u8g2_esp32_hal.cs != U8G2_ESP32_HAL_UNDEFINED) {
+                               gpio_set_level(u8g2_esp32_hal.cs, arg_int);
+                       }
+                       break;
+       // Set the Software I²C pin to the value passed in through arg_int.
+               case U8X8_MSG_GPIO_I2C_CLOCK:
+                       if (u8g2_esp32_hal.scl != U8G2_ESP32_HAL_UNDEFINED) {
+                               gpio_set_level(u8g2_esp32_hal.scl, arg_int);
+//                             printf("%c",(arg_int==1?'C':'c'));
+                       }
+                       break;
+       // Set the Software I²C pin to the value passed in through arg_int.
+               case U8X8_MSG_GPIO_I2C_DATA:
+                       if (u8g2_esp32_hal.sda != U8G2_ESP32_HAL_UNDEFINED) {
+                               gpio_set_level(u8g2_esp32_hal.sda, arg_int);
+//                             printf("%c",(arg_int==1?'D':'d'));
+                       }
+                       break;
+
+       // Delay for the number of milliseconds passed in through arg_int.
+               case U8X8_MSG_DELAY_MILLI:
+                       vTaskDelay(arg_int/portTICK_PERIOD_MS);
+                       break;
+       }
+       return 0;
+} // u8g2_esp32_gpio_and_delay_cb
diff --git a/main/u8g2_esp32_hal.h b/main/u8g2_esp32_hal.h
new file mode 100644 (file)
index 0000000..c341015
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * u8g2_esp32_hal.h
+ *
+ *  Created on: Feb 12, 2017
+ *      Author: kolban
+ */
+
+#ifndef U8G2_ESP32_HAL_H_
+#define U8G2_ESP32_HAL_H_
+#include "u8g2.h"
+
+#include "driver/gpio.h"
+#include "driver/spi_master.h"
+#include "driver/i2c.h"
+
+#define U8G2_ESP32_HAL_UNDEFINED GPIO_NUM_NC
+
+#define I2C_MASTER_NUM I2C_NUM_1           //  I2C port number for master dev
+#define I2C_MASTER_TX_BUF_DISABLE   0      //  I2C master do not need buffer
+#define I2C_MASTER_RX_BUF_DISABLE   0      //  I2C master do not need buffer
+#define I2C_MASTER_FREQ_HZ          1200000  //  I2C master clock frequency
+#define ACK_CHECK_EN   0x1                 //  I2C master will check ack from slave
+#define ACK_CHECK_DIS  0x0                 //  I2C master will not check ack from slave
+
+typedef struct {
+       gpio_num_t clk;
+       gpio_num_t mosi;
+       gpio_num_t sda; // data for I²C
+       gpio_num_t scl; // clock for I²C
+       gpio_num_t cs;
+       gpio_num_t reset;
+       gpio_num_t dc;
+} u8g2_esp32_hal_t ;
+
+#define U8G2_ESP32_HAL_DEFAULT {U8G2_ESP32_HAL_UNDEFINED, U8G2_ESP32_HAL_UNDEFINED, U8G2_ESP32_HAL_UNDEFINED, U8G2_ESP32_HAL_UNDEFINED, U8G2_ESP32_HAL_UNDEFINED, U8G2_ESP32_HAL_UNDEFINED, U8G2_ESP32_HAL_UNDEFINED }
+
+void u8g2_esp32_hal_init(u8g2_esp32_hal_t u8g2_esp32_hal_param);
+uint8_t u8g2_esp32_spi_byte_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8g2_esp32_i2c_byte_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8g2_esp32_gpio_and_delay_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+#endif /* U8G2_ESP32_HAL_H_ */