nodemcu-firmware/app/platform/u8x8_nodemcu_hal.c
Johny Mattsson 526d21dab4 Major cleanup - c_whatever is finally history. (#2838)
The PR removed the bulk of non-newlib headers from the NodeMCU source base.  
app/libc has now been cut down to the bare minimum overrides to shadow the 
corresponding functions in the SDK's libc. The old c_xyz.h headerfiles have been 
nuked in favour of the standard <xyz.h> headers, with a few exceptions over in 
sdk-overrides. Again, shipping a libc.a without headers is a terrible thing to do. We're 
still living on a prayer that libc was configured the same was as a default-configured
xtensa gcc toolchain assumes it is. That part I cannot do anything about, unfortunately, 
but it's no worse than it has been before.

This enables our source files to compile successfully using the standard header files, 
and use the typical malloc()/calloc()/realloc()/free(), the strwhatever()s and 
memwhatever()s. These end up, through macro and linker magic, mapped to the 
appropriate SDK or ROM functions.
2019-07-22 00:58:21 +03:00

310 lines
8.3 KiB
C

// Do not use the code from u8g2 submodule and skip the complete source here
// if the u8g2 module is not selected.
// Reason: The whole u8g2 submodule code tree might not even exist in this case.
#include "user_modules.h"
#ifdef LUA_USE_MODULES_U8G2
#include <string.h>
#include <stdlib.h>
#include "platform.h"
#define U8X8_USE_PINS
#define U8X8_WITH_USER_PTR
#include "u8x8_nodemcu_hal.h"
// static variables containing info about the i2c link
// TODO: move to user space in u8x8_t once available
typedef struct {
uint8_t id;
} hal_i2c_t;
// static variables containing info about the spi link
// TODO: move to user space in u8x8_t once available
typedef struct {
uint8_t host;
//spi_device_handle_t device;
uint8_t last_dc;
struct {
uint8_t *data;
size_t size, used;
} buffer;
} hal_spi_t;
static void flush_buffer_spi( hal_spi_t *hal )
{
if (hal->buffer.data && hal->buffer.used > 0) {
platform_spi_blkwrite( hal->host, hal->buffer.used, hal->buffer.data );
hal->buffer.used = 0;
}
}
static void force_flush_buffer(u8x8_t *u8x8)
{
// spi hal has a buffer that can be flushed
if (u8x8->byte_cb == u8x8_byte_nodemcu_spi) {
hal_spi_t *hal = u8x8->user_ptr;
flush_buffer_spi( hal );
}
}
uint8_t u8x8_gpio_and_delay_nodemcu(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
uint32_t temp;
switch(msg)
{
case U8X8_MSG_GPIO_AND_DELAY_INIT: // called once during init phase of u8g2/u8x8
// can be used to setup pins
for (int idx = 0; idx < U8X8_PIN_OUTPUT_CNT; idx++) {
if (u8x8->pins[idx] != U8X8_PIN_NONE) {
// configure pin as output
if (idx == U8X8_PIN_I2C_CLOCK || idx == U8X8_PIN_I2C_DATA) {
platform_gpio_mode( u8x8->pins[idx], PLATFORM_GPIO_OPENDRAIN, PLATFORM_GPIO_PULLUP );
} else {
platform_gpio_mode( u8x8->pins[idx], PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT );
}
}
}
break;
case U8X8_MSG_DELAY_NANO: // delay arg_int * 1 nano second
force_flush_buffer(u8x8);
os_delay_us( 1 );
break;
case U8X8_MSG_DELAY_100NANO: // delay arg_int * 100 nano seconds
force_flush_buffer(u8x8);
temp = arg_int * 100;
temp /= 1000;
os_delay_us( temp > 0 ? temp : 1 );
break;
case U8X8_MSG_DELAY_10MICRO: // delay arg_int * 10 micro seconds
force_flush_buffer(u8x8);
os_delay_us( arg_int * 10 );
break;
case U8X8_MSG_DELAY_MILLI: // delay arg_int * 1 milli second
force_flush_buffer(u8x8);
os_delay_us( arg_int * 1000 );
system_soft_wdt_feed();
break;
case U8X8_MSG_DELAY_I2C: // arg_int is the I2C speed in 100KHz, e.g. 4 = 400 KHz
force_flush_buffer(u8x8);
temp = 5000 / arg_int; // arg_int=1: delay by 5us, arg_int = 4: delay by 1.25us
temp /= 1000;
os_delay_us( temp > 0 ? temp : 1 );
break;
case U8X8_MSG_GPIO_D0: // D0 or SPI clock pin: Output level in arg_int
//case U8X8_MSG_GPIO_SPI_CLOCK:
break;
case U8X8_MSG_GPIO_D1: // D1 or SPI data pin: Output level in arg_int
//case U8X8_MSG_GPIO_SPI_DATA:
break;
case U8X8_MSG_GPIO_D2: // D2 pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_D3: // D3 pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_D4: // D4 pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_D5: // D5 pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_D6: // D6 pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_D7: // D7 pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_E: // E/WR pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_CS: // CS (chip select) pin: Output level in arg_int
platform_gpio_write( u8x8_GetPinValue( u8x8, msg ), arg_int );
break;
case U8X8_MSG_GPIO_DC: // DC (data/cmd, A0, register select) pin: Output level in arg_int
platform_gpio_write( u8x8_GetPinValue( u8x8, msg ), arg_int );
break;
case U8X8_MSG_GPIO_RESET: // Reset pin: Output level in arg_int
if (u8x8_GetPinValue( u8x8, msg ) != U8X8_PIN_NONE)
platform_gpio_write( u8x8_GetPinValue(u8x8, msg), arg_int );
break;
case U8X8_MSG_GPIO_CS1: // CS1 (chip select) pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_CS2: // CS2 (chip select) pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_I2C_CLOCK: // arg_int=0: Output low at I2C clock pin
// arg_int=1: Input dir with pullup high for I2C clock pin
// for SW comm routine
platform_gpio_write( u8x8_GetPinValue( u8x8, msg ), arg_int );
break;
case U8X8_MSG_GPIO_I2C_DATA: // arg_int=0: Output low at I2C data pin
// arg_int=1: Input dir with pullup high for I2C data pin
// for SW comm routine
platform_gpio_write( u8x8_GetPinValue( u8x8, msg ), arg_int );
break;
case U8X8_MSG_GPIO_MENU_SELECT:
case U8X8_MSG_GPIO_MENU_NEXT:
case U8X8_MSG_GPIO_MENU_PREV:
case U8X8_MSG_GPIO_MENU_HOME:
u8x8_SetGPIOResult( u8x8, /* get menu select pin state */ 0 );
break;
default:
u8x8_SetGPIOResult( u8x8, 1 ); // default return value
break;
}
return 1;
}
uint8_t u8x8_byte_nodemcu_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
uint8_t *data;
hal_i2c_t *hal = u8x8->user_ptr;
switch(msg) {
case U8X8_MSG_BYTE_SEND:
if (hal->id < NUM_I2C) {
data = (uint8_t *)arg_ptr;
while( arg_int > 0 ) {
platform_i2c_send_byte( hal->id, *data );
data++;
arg_int--;
}
} else {
// invalid id
return 0;
}
break;
case U8X8_MSG_BYTE_INIT:
{
// the user pointer initially contains the i2c id
int id = (int)hal;
if (!(hal = malloc( sizeof ( hal_i2c_t ) )))
return 0;
hal->id = id;
u8x8->user_ptr = hal;
}
break;
case U8X8_MSG_BYTE_SET_DC:
break;
case U8X8_MSG_BYTE_START_TRANSFER:
if (hal->id < NUM_I2C) {
platform_i2c_send_start( hal->id );
platform_i2c_send_address( hal->id, u8x8_GetI2CAddress(u8x8), PLATFORM_I2C_DIRECTION_TRANSMITTER );
} else {
// invalid id
return 0;
}
break;
case U8X8_MSG_BYTE_END_TRANSFER:
if (hal->id < NUM_I2C) {
platform_i2c_send_stop( hal->id );
} else {
// invalid id
return 0;
}
break;
default:
return 0;
}
return 1;
}
uint8_t u8x8_byte_nodemcu_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
hal_spi_t *hal = u8x8->user_ptr;
switch(msg) {
case U8X8_MSG_BYTE_INIT:
{
/* disable chipselect */
u8x8_gpio_SetCS( u8x8, u8x8->display_info->chip_disable_level );
// the user pointer initially contains the spi host id
int host = (int)hal;
if (!(hal = malloc( sizeof ( hal_spi_t ) )))
return 0;
hal->host = host;
u8x8->user_ptr = hal;
hal->buffer.data = NULL;
hal->last_dc = 0;
}
break;
case U8X8_MSG_BYTE_SET_DC:
if (hal->last_dc != arg_int)
flush_buffer_spi( hal );
u8x8_gpio_SetDC( u8x8, arg_int );
hal->last_dc = arg_int;
break;
case U8X8_MSG_BYTE_START_TRANSFER:
hal->buffer.size = 256;
if (!(hal->buffer.data = (uint8_t *)malloc( hal->buffer.size )))
return 0;
hal->buffer.used = 0;
u8x8_gpio_SetCS( u8x8, u8x8->display_info->chip_enable_level );
break;
case U8X8_MSG_BYTE_SEND:
if (!hal->buffer.data)
return 0;
while (hal->buffer.size - hal->buffer.used < arg_int) {
hal->buffer.size *= 2;
uint8_t *tmp;
if (!(tmp = (uint8_t *)malloc( hal->buffer.size ))) {
free( hal->buffer.data );
hal->buffer.data = NULL;
return 0;
}
os_memcpy( tmp, hal->buffer.data, hal->buffer.used );
free( hal->buffer.data );
hal->buffer.data = tmp;
}
os_memcpy( hal->buffer.data + hal->buffer.used, arg_ptr, arg_int );
hal->buffer.used += arg_int;
break;
case U8X8_MSG_BYTE_END_TRANSFER:
if (!hal->buffer.data)
return 0;
flush_buffer_spi( hal );
u8x8_gpio_SetCS( u8x8, u8x8->display_info->chip_disable_level );
free( hal->buffer.data );
hal->buffer.data = NULL;
break;
default:
return 0;
}
return 1;
}
#endif /* LUA_USE_MODULES_U8G2 */