323 lines
8.0 KiB
C
323 lines
8.0 KiB
C
/*
|
||
* Copyright (c) 2021 Talkweb Co.,ltd.
|
||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
* you may not use this file except in compliance with the License.
|
||
* You may obtain a copy of the License at
|
||
*
|
||
* http://www.apache.org/licenses/LICENSE-2.0
|
||
*
|
||
* Unless required by applicable law or agreed to in writing, software
|
||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
* See the License for the specific language governing permissions and
|
||
* limitations under the License.
|
||
*/
|
||
|
||
#include <stdio.h>
|
||
#include <unistd.h>
|
||
|
||
#include "ohos_init.h"
|
||
#include "cmsis_os2.h"
|
||
#include "iot_gpio.h"
|
||
#include "iot_i2c.h"
|
||
#include "u8g2.h"
|
||
#include "u8x8.h"
|
||
|
||
#include "oled_u8g2.h"
|
||
#include "boot_animation.h"
|
||
|
||
volatile osSemaphoreId_t g_gpioIsrSemId = NULL;
|
||
volatile char g_startBootAnimationFlag = 0;
|
||
|
||
static u8g2_t u8g2;
|
||
|
||
I2C_SEND_STATES g_i2cSendState = STATE_SEND_IDLE;
|
||
|
||
#define MAX_DATAS 1200
|
||
#define EVERY_DATA_SEND 16
|
||
unsigned char g_send_data[2] = {0};
|
||
unsigned char g_send_datas[MAX_DATAS] = {0};
|
||
|
||
//OLED通信端口
|
||
#define WIFI_IOT_I2C_IDX_0 0
|
||
#define OLED_I2C_BAUDRATE (100 * 1000) // 400k 频率
|
||
#define SSD1306_I2C_ADDR (0x3C << 1)
|
||
#define SSD1306_CTRL_CMD 0x00
|
||
#define SSD1306_CTRL_DATA 0x40
|
||
#define FEATURE_ISQ_CONTROLL 1
|
||
|
||
//信号管脚
|
||
#define WIFI_IOT_IO_NAME_GPIO_13 13
|
||
#define WIFI_IOT_IO_NAME_GPIO_14 14
|
||
|
||
static uint32_t HALI2cWriteDatas(unsigned int id, uint16_t device_addr, uint32_t send_len)
|
||
{
|
||
unsigned int status;
|
||
status = IoTI2cWrite(id, device_addr, g_send_datas, send_len);
|
||
|
||
if (status != 0)
|
||
{
|
||
printf("===== Error: I2C write status = 0x%x! =====\r\n", status);
|
||
return status;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* SSD1306写data数据
|
||
*/
|
||
static void WriteIICDatas(unsigned char *IIC_Datas, uint32_t length)
|
||
{
|
||
memset_s(g_send_datas, MAX_DATAS, 0, MAX_DATAS);
|
||
g_send_datas[0] = SSD1306_CTRL_DATA;
|
||
memcpy_s(g_send_datas + 1, MAX_DATAS, IIC_Datas, length);
|
||
HALI2cWriteDatas(WIFI_IOT_I2C_IDX_0, SSD1306_I2C_ADDR, length + 1);
|
||
}
|
||
|
||
/**
|
||
* SSD1306写CMD数据
|
||
*/
|
||
static void WriteIICCmds(unsigned char *IIC_Datas, uint32_t length)
|
||
{
|
||
memset_s(g_send_datas, MAX_DATAS, 0, MAX_DATAS);
|
||
g_send_datas[0] = SSD1306_CTRL_CMD;
|
||
memcpy_s(g_send_datas + 1, MAX_DATAS, IIC_Datas, length);
|
||
HALI2cWriteDatas(WIFI_IOT_I2C_IDX_0, SSD1306_I2C_ADDR, length + 1);
|
||
}
|
||
|
||
static void HalDelayMs(uint32_t ms)
|
||
{
|
||
uint32_t msPerTick = 1000 / osKernelGetTickFreq(); // 10ms
|
||
if (ms >= msPerTick)
|
||
{
|
||
osDelay((ms / msPerTick));
|
||
}
|
||
|
||
uint32_t restMs = ms % msPerTick;
|
||
if (restMs > 0)
|
||
{
|
||
usleep(restMs * 1000);
|
||
}
|
||
}
|
||
|
||
static void HalI2cInit()
|
||
{
|
||
IoTGpioInit(WIFI_IOT_IO_NAME_GPIO_13);
|
||
IoTGpioInit(WIFI_IOT_IO_NAME_GPIO_14);
|
||
IotIoSetFunc(WIFI_IOT_IO_NAME_GPIO_13, HI_IO_FUNC_GPIO_13_I2C0_SDA);
|
||
IotIoSetFunc(WIFI_IOT_IO_NAME_GPIO_14, HI_IO_FUNC_GPIO_14_I2C0_SCL);
|
||
IoTI2cInit(WIFI_IOT_I2C_IDX_0, OLED_I2C_BAUDRATE);
|
||
}
|
||
|
||
uint8_t U8g2Hi3861I2cByteCb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
|
||
{
|
||
uint8_t *data;
|
||
uint8_t index;
|
||
switch (msg)
|
||
{
|
||
case U8X8_MSG_BYTE_SEND:
|
||
data = (uint8_t *)arg_ptr;
|
||
if (g_i2cSendState == STATE_SEND_START && arg_int == 1)
|
||
{
|
||
if (*data == 0x00)
|
||
{
|
||
g_i2cSendState = STATE_SEND_CMD;
|
||
break;
|
||
}
|
||
else if (*data == 0x40)
|
||
{
|
||
g_i2cSendState = STATE_SEND_DATA;
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
// do nonthing
|
||
}
|
||
}
|
||
|
||
if (g_i2cSendState == STATE_SEND_CMD)
|
||
{
|
||
WriteIICCmds(data, arg_int);
|
||
}
|
||
else if (g_i2cSendState == STATE_SEND_DATA)
|
||
{
|
||
WriteIICDatas(data, arg_int);
|
||
}
|
||
else
|
||
{
|
||
// do nothing
|
||
}
|
||
break;
|
||
|
||
case U8X8_MSG_BYTE_INIT:
|
||
HalI2cInit();
|
||
break;
|
||
|
||
case U8X8_MSG_BYTE_START_TRANSFER:
|
||
if (g_i2cSendState == STATE_SEND_IDLE)
|
||
{
|
||
g_i2cSendState = STATE_SEND_START;
|
||
}
|
||
else
|
||
{
|
||
g_i2cSendState = STATE_SEND_IDLE;
|
||
}
|
||
break;
|
||
case U8X8_MSG_BYTE_END_TRANSFER: // send all at once
|
||
if (g_i2cSendState == STATE_SEND_CMD || g_i2cSendState == STATE_SEND_DATA)
|
||
{
|
||
g_i2cSendState = STATE_SEND_IDLE;
|
||
}
|
||
break;
|
||
default:
|
||
return 0;
|
||
}
|
||
return 1;
|
||
}
|
||
|
||
uint8_t U8g2Hi3861GpioAndDelayCb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
|
||
{
|
||
switch (msg)
|
||
{
|
||
case U8X8_MSG_DELAY_NANO: // delay arg_int * 1 nano second
|
||
__asm__ volatile("nop");
|
||
break;
|
||
case U8X8_MSG_DELAY_100NANO: // delay arg_int * 100 nano seconds
|
||
__asm__ volatile("nop");
|
||
break;
|
||
case U8X8_MSG_DELAY_10MICRO: // delay arg_int * 10 micro seconds
|
||
usleep(10);
|
||
break;
|
||
case U8X8_MSG_DELAY_MILLI:
|
||
HalDelayMs(arg_int);
|
||
break;
|
||
case U8X8_MSG_GPIO_AND_DELAY_INIT:
|
||
break;
|
||
case U8X8_MSG_GPIO_RESET:
|
||
break;
|
||
case U8X8_MSG_GPIO_I2C_DATA:
|
||
break;
|
||
case U8X8_MSG_GPIO_I2C_CLOCK:
|
||
break;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
static unsigned int g_lastTickCount = 0;
|
||
|
||
static void GpioSsdIsrFunc(char *arg)
|
||
{
|
||
(void)arg;
|
||
|
||
//消除按键抖动
|
||
unsigned int tickCount = osKernelGetTickCount();
|
||
unsigned int count = tickCount - g_lastTickCount;
|
||
g_lastTickCount = tickCount;
|
||
|
||
if (count > 50)
|
||
{
|
||
g_startBootAnimationFlag ^= 1;
|
||
osSemaphoreRelease(g_gpioIsrSemId);
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
/**
|
||
* 初始化开发板上的按键GPIO中断
|
||
*/
|
||
static void InitOledKeyGpioIsr(void)
|
||
{
|
||
g_gpioIsrSemId = osSemaphoreNew(32, 0, NULL);
|
||
|
||
IoTGpioInit(IOT_GPIO_IO_GPIO_5);
|
||
IotIoSetFunc(IOT_GPIO_IO_GPIO_5, HI_IO_FUNC_GPIO_5_GPIO);
|
||
IotIoSetPull(IOT_GPIO_IO_GPIO_5, IOT_IO_PULL_UP);
|
||
|
||
uint32_t ret = 0;
|
||
ret = IoTGpioSetDir(IOT_GPIO_IO_GPIO_5, IOT_GPIO_DIR_IN);
|
||
if (ret != 0)
|
||
{
|
||
printf("===== ERROR ======gpio -> hi_gpio_set_dir1 ret:%d\r\n", ret);
|
||
return;
|
||
}
|
||
ret = IoTGpioRegisterIsrFunc(IOT_GPIO_IO_GPIO_5, IOT_INT_TYPE_EDGE, IOT_GPIO_EDGE_RISE_LEVEL_HIGH, GpioSsdIsrFunc, NULL);
|
||
|
||
return;
|
||
}
|
||
|
||
/**
|
||
* 绘制HarmonyOS开机动画
|
||
*/
|
||
static void DrawHarmonyOSAnimation(void)
|
||
{
|
||
for (int i = 0; i < 58; i++)
|
||
{
|
||
u8g2_FirstPage(&u8g2);
|
||
do
|
||
{
|
||
u8g2_DrawXBMP(&u8g2, 0, 0, 128, 64, openHarmony_All[i]);
|
||
} while (u8g2_NextPage(&u8g2));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 绘制Talkweb LOGO,未来已来,远方不远
|
||
*/
|
||
static void DrawTalkwebLogo(void)
|
||
{
|
||
u8g2_FirstPage(&u8g2);
|
||
do
|
||
{
|
||
u8g2_DrawXBMP(&u8g2, 0, 0, 128, 64, talkweb_end);
|
||
} while (u8g2_NextPage(&u8g2));
|
||
}
|
||
|
||
static void OledU8g2Task(void)
|
||
{
|
||
//初始化OLED开发板上的按键中断事件
|
||
InitOledKeyGpioIsr();
|
||
|
||
//U8G2_R0:屏幕旋转方向,横屏不旋转。
|
||
u8g2_Setup_ssd1306_i2c_128x64_noname_f(&u8g2, U8G2_R0, U8g2Hi3861I2cByteCb, U8g2Hi3861GpioAndDelayCb);
|
||
|
||
//初始OLED显示器,将向OLED显示器发送init消息
|
||
//此函数会触发两种操作,一种是OLED硬件初始,一种是OLED显示屏初始清屏。
|
||
u8g2_InitDisplay(&u8g2);
|
||
|
||
//开启省电模式
|
||
u8g2_SetPowerSave(&u8g2, 0);
|
||
|
||
while (1)
|
||
{
|
||
DrawTalkwebLogo();
|
||
osSemaphoreAcquire(g_gpioIsrSemId, osWaitForever);
|
||
|
||
while (g_startBootAnimationFlag)
|
||
{
|
||
DrawHarmonyOSAnimation();
|
||
osDelay(300U);
|
||
DrawTalkwebLogo();
|
||
osDelay(300U);
|
||
}
|
||
}
|
||
}
|
||
|
||
bool StartBootAnimation()
|
||
{
|
||
osThreadAttr_t attr;
|
||
attr.name = "OledU8g2Task";
|
||
attr.attr_bits = 0U;
|
||
attr.cb_mem = NULL;
|
||
attr.cb_size = 0U;
|
||
attr.stack_mem = NULL;
|
||
attr.stack_size = 1024 * 10;
|
||
attr.priority = osPriorityNormal;
|
||
if (osThreadNew((osThreadFunc_t)OledU8g2Task, NULL, &attr) == NULL)
|
||
{
|
||
printf("[Talkweb Niobe] Falied to create OledU8g2Task!\n");
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|