366 lines
13 KiB
C
366 lines
13 KiB
C
|
// Copyright 2020 Beken Systems (Shanghai) PTE 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 <string.h>
|
||
|
#include "FreeRTOS.h"
|
||
|
#include "semphr.h"
|
||
|
#include "iot_i2c.h"
|
||
|
#include "driver/i2c.h"
|
||
|
#include "i2c_driver.h"
|
||
|
|
||
|
#include <os/mem.h>
|
||
|
|
||
|
//#define SEM_WAIT_TICKS 0
|
||
|
#define WAITFOREVER 0xFFFFFFFF
|
||
|
#define WAITNOTICKS 0x02
|
||
|
static volatile uint8_t i2c_bit_mask;
|
||
|
|
||
|
typedef struct IotI2CDescriptor{
|
||
|
IotI2CConfig_t iot_i2c_config;
|
||
|
int32_t i2c_port_num;
|
||
|
bool driver_installed;
|
||
|
void (*func)(IotI2COperationStatus_t arg1, void *arg2);
|
||
|
void *arg;
|
||
|
void *pvBuffer;
|
||
|
size_t xBytes;
|
||
|
bool is_slave_addr_set;
|
||
|
bool is_send_no_stop_flag_set;
|
||
|
uint32_t bytes_to_read;
|
||
|
uint32_t bytes_to_write;
|
||
|
uint8_t slave_addr;
|
||
|
unsigned async_op: 1;
|
||
|
} IotI2CDescriptor_t;
|
||
|
|
||
|
typedef struct IotCallback{
|
||
|
void (*func)(IotI2COperationStatus_t arg1, void *arg2);
|
||
|
void *arg;
|
||
|
int callbackset_flag;
|
||
|
beken2_timer_t myTimer;
|
||
|
} IotCallback_t;
|
||
|
|
||
|
static IotCallback_t iottimercallback[SOC_I2C_UNIT_NUM] = {0};
|
||
|
|
||
|
|
||
|
static void i2c_TimerCallback(void *param, unsigned int ulparam)
|
||
|
{
|
||
|
IotI2CDescriptor_t * i2c_desc = (IotI2CDescriptor_t *) param;
|
||
|
int time_id = i2c_desc->i2c_port_num;
|
||
|
uint8_t status = bk_i2c_get_transstate(time_id);
|
||
|
|
||
|
if (iottimercallback[time_id].callbackset_flag){
|
||
|
if (iottimercallback[time_id].func) {
|
||
|
iottimercallback[time_id].func(status, iottimercallback[time_id].arg);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
IotI2CHandle_t iot_i2c_open(int32_t lI2CInstance)
|
||
|
{
|
||
|
if (lI2CInstance < 0 || lI2CInstance > SOC_I2C_UNIT_NUM) {
|
||
|
I2C_LOGE("Invalid arguments(%d).\n",lI2CInstance);
|
||
|
return NULL;
|
||
|
}
|
||
|
if (0x01 & (i2c_bit_mask >> lI2CInstance)) {
|
||
|
I2C_LOGE( "I2C Handler is already initialised (%d).\n",lI2CInstance);
|
||
|
return NULL;
|
||
|
}
|
||
|
IotI2CDescriptor_t *i2c_ctx = (IotI2CDescriptor_t *)os_zalloc(sizeof(IotI2CDescriptor_t));
|
||
|
if (i2c_ctx == NULL) {
|
||
|
I2C_LOGE("Could not allocate memory for i2c context(%d).\n",lI2CInstance);
|
||
|
return NULL;
|
||
|
}
|
||
|
IotI2CHandle_t iot_i2c_handler = (void *) i2c_ctx;
|
||
|
i2c_ctx->i2c_port_num = lI2CInstance;
|
||
|
i2c_bit_mask |= BIT(lI2CInstance);
|
||
|
|
||
|
return iot_i2c_handler;
|
||
|
}
|
||
|
|
||
|
int32_t iot_i2c_ioctl( IotI2CHandle_t const pxI2CPeripheral, IotI2CIoctlRequest_t xI2CRequest, void *const pvBuffer)
|
||
|
{
|
||
|
bk_err_t ret;
|
||
|
I2C_LOGI ("iot_i2c_ioctl %d.\n",xI2CRequest);
|
||
|
if (xI2CRequest != eI2CSendNoStopFlag) {
|
||
|
if (pxI2CPeripheral == NULL || pvBuffer == NULL) {
|
||
|
I2C_LOGE("Invalid arguments %d.\n",xI2CRequest);
|
||
|
return IOT_I2C_INVALID_VALUE;
|
||
|
}
|
||
|
}
|
||
|
IotI2CDescriptor_t *i2c_ctx = (IotI2CDescriptor_t *) pxI2CPeripheral;
|
||
|
int32_t i2c_port_num = (int32_t) i2c_ctx->i2c_port_num;
|
||
|
|
||
|
switch (xI2CRequest) {
|
||
|
case eI2CSetMasterConfig : {
|
||
|
|
||
|
IotI2CConfig_t *iot_i2c_handler = (IotI2CConfig_t *) pvBuffer;
|
||
|
i2c_ctx->iot_i2c_config.ulBusFreq = iot_i2c_handler->ulBusFreq;
|
||
|
i2c_ctx->iot_i2c_config.ulMasterTimeout = iot_i2c_handler->ulMasterTimeout;
|
||
|
|
||
|
if (i2c_ctx->driver_installed) {
|
||
|
if (bk_i2c_get_busstate(i2c_port_num)== pdFALSE) {
|
||
|
return IOT_I2C_BUSY;
|
||
|
}
|
||
|
bk_err_t ret = bk_i2c_deinit(i2c_port_num);
|
||
|
if (ret != BK_OK) {
|
||
|
I2C_LOGE("i2c driver delete failed.\n");
|
||
|
return IOT_I2C_INVALID_VALUE;
|
||
|
}
|
||
|
i2c_ctx->driver_installed = false;
|
||
|
I2C_LOGI( "i2c driver delete success.\n");
|
||
|
}
|
||
|
i2c_config_t i2c_conf = {
|
||
|
.baud_rate = i2c_ctx->iot_i2c_config.ulBusFreq,
|
||
|
.addr_mode = I2C_ADDR_MODE_7BIT,
|
||
|
};
|
||
|
ret = bk_i2c_init(i2c_port_num, &i2c_conf);
|
||
|
if (ret != BK_OK) {
|
||
|
I2C_LOGE( "bk_i2c_init failed.\n");
|
||
|
return IOT_I2C_INVALID_VALUE;
|
||
|
}
|
||
|
i2c_ctx->driver_installed = true;
|
||
|
I2C_LOGI("I2C(%d) init ok, baud_rate:%d ,timeout : %d \r\n", i2c_port_num,
|
||
|
i2c_ctx->iot_i2c_config.ulBusFreq ,i2c_ctx->iot_i2c_config.ulMasterTimeout);
|
||
|
return IOT_I2C_SUCCESS;
|
||
|
}
|
||
|
break;
|
||
|
case eI2CGetMasterConfig : {
|
||
|
IotI2CConfig_t *iot_i2c_handler = (IotI2CConfig_t *) pvBuffer;
|
||
|
iot_i2c_handler->ulBusFreq = i2c_ctx->iot_i2c_config.ulBusFreq;
|
||
|
iot_i2c_handler->ulMasterTimeout = i2c_ctx->iot_i2c_config.ulMasterTimeout;
|
||
|
return IOT_I2C_SUCCESS;
|
||
|
}
|
||
|
case eI2CSetSlaveAddr : {
|
||
|
if (bk_i2c_get_busstate(i2c_port_num)== pdFALSE) {
|
||
|
return IOT_I2C_BUSY;
|
||
|
}
|
||
|
i2c_ctx->slave_addr = (*(uint8_t *)pvBuffer);
|
||
|
i2c_ctx->is_slave_addr_set = true;
|
||
|
return IOT_I2C_SUCCESS;
|
||
|
}
|
||
|
case eI2CGetBusState : {
|
||
|
IotI2CBusStatus_t *bus_state = (IotI2CBusStatus_t *) pvBuffer;
|
||
|
*bus_state = (bk_i2c_get_busstate(i2c_port_num)== pdFALSE) ? eI2cBusBusy : eI2CBusIdle;
|
||
|
I2C_LOGI( "Get bus state [%d].\n" ,*bus_state );
|
||
|
|
||
|
return IOT_I2C_SUCCESS;
|
||
|
}
|
||
|
case eI2CGetTxNoOfbytes : {
|
||
|
uint16_t *tx_bytes = (uint16_t *) pvBuffer;
|
||
|
*tx_bytes = i2c_ctx->bytes_to_write;
|
||
|
return IOT_I2C_SUCCESS;
|
||
|
}
|
||
|
case eI2CGetRxNoOfbytes : {
|
||
|
uint16_t *rx_bytes = (uint16_t *) pvBuffer;
|
||
|
*rx_bytes = i2c_ctx->bytes_to_read;
|
||
|
return IOT_I2C_SUCCESS;
|
||
|
}
|
||
|
case eI2CSendNoStopFlag : {
|
||
|
i2c_ctx->is_send_no_stop_flag_set = true;
|
||
|
return IOT_I2C_SUCCESS;
|
||
|
}
|
||
|
default :
|
||
|
I2C_LOGE( "Invalid argument");
|
||
|
return IOT_I2C_INVALID_VALUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void iot_i2c_set_callback(IotI2CHandle_t const pxI2CPeripheral, IotI2CCallback_t xCallback, void *pvUserContext)
|
||
|
{
|
||
|
if (pxI2CPeripheral == NULL || xCallback == NULL) {
|
||
|
I2C_LOGE( "Invalid arguments.\n");
|
||
|
}
|
||
|
IotI2CDescriptor_t *iot_i2c_handler = (IotI2CDescriptor_t *) pxI2CPeripheral;
|
||
|
int i2c_id = iot_i2c_handler->i2c_port_num;
|
||
|
if(iottimercallback[i2c_id].callbackset_flag == 1){
|
||
|
os_memset(&iottimercallback[i2c_id],0,sizeof(IotCallback_t));
|
||
|
}
|
||
|
iottimercallback[i2c_id].arg = pvUserContext;
|
||
|
iottimercallback[i2c_id].func = (void *)xCallback;
|
||
|
iottimercallback[i2c_id].callbackset_flag = 1;
|
||
|
bk_err_t ret = rtos_init_oneshot_timer(&iottimercallback[i2c_id].myTimer, 200,
|
||
|
(timer_2handler_t)i2c_TimerCallback,
|
||
|
(void *) iot_i2c_handler, 0);
|
||
|
if (ret!= BK_OK) {
|
||
|
I2C_LOGE("error xTimerCreate.\n");
|
||
|
} else {
|
||
|
bk_i2c_timer_callback(i2c_id, &iottimercallback[i2c_id].myTimer);
|
||
|
}
|
||
|
I2C_LOGD( "iot_i2c_set_callback ok.\n");
|
||
|
}
|
||
|
|
||
|
int32_t iot_i2c_read_async( IotI2CHandle_t const pxI2CPeripheral, uint8_t *const pvBuffer, size_t xBytes)
|
||
|
{
|
||
|
bk_err_t ret = BK_OK;
|
||
|
if (pxI2CPeripheral == NULL || pvBuffer == NULL) {
|
||
|
I2C_LOGD( "Invalid arguments.\n");
|
||
|
return IOT_I2C_INVALID_VALUE;
|
||
|
}
|
||
|
IotI2CDescriptor_t *iot_i2c_handler = (IotI2CDescriptor_t *) pxI2CPeripheral;
|
||
|
int32_t i2c_port_num = (int32_t) iot_i2c_handler->i2c_port_num;
|
||
|
uint8_t *src_buf = (uint8_t *) pvBuffer;
|
||
|
if (!iot_i2c_handler->is_slave_addr_set) {
|
||
|
I2C_LOGE( "Slave address not set.\n");
|
||
|
return IOT_I2C_SLAVE_ADDRESS_NOT_SET;
|
||
|
}
|
||
|
if (!iot_i2c_handler->driver_installed) {
|
||
|
return IOT_I2C_INVALID_VALUE;
|
||
|
}
|
||
|
if ( bk_i2c_get_busstate(i2c_port_num) == pdFALSE) {
|
||
|
return IOT_I2C_BUSY;
|
||
|
}
|
||
|
iot_i2c_handler->async_op = true;
|
||
|
ret = bk_i2c_master_read(i2c_port_num, iot_i2c_handler->slave_addr,src_buf, xBytes, WAITNOTICKS );
|
||
|
if (ret != BK_OK) {
|
||
|
I2C_LOGE( "i2c master read failed");
|
||
|
return IOT_I2C_READ_FAILED;
|
||
|
}
|
||
|
iot_i2c_handler->is_send_no_stop_flag_set = false;
|
||
|
iot_i2c_handler->bytes_to_read = xBytes;
|
||
|
|
||
|
I2C_LOGD( "iot_i2c_read_async.\n");
|
||
|
return (ret == BK_OK) ? IOT_I2C_SUCCESS : IOT_I2C_READ_FAILED;
|
||
|
}
|
||
|
|
||
|
int32_t iot_i2c_write_async( IotI2CHandle_t const pxI2CPeripheral, uint8_t *const pvBuffer, size_t xBytes)
|
||
|
{
|
||
|
bk_err_t ret = BK_OK;
|
||
|
if (pxI2CPeripheral == NULL || pvBuffer == NULL) {
|
||
|
I2C_LOGE( "Invalid arguments.\n");
|
||
|
return IOT_I2C_INVALID_VALUE;
|
||
|
}
|
||
|
IotI2CDescriptor_t *iot_i2c_handler = (IotI2CDescriptor_t *) pxI2CPeripheral;
|
||
|
int32_t i2c_port_num = (int32_t) iot_i2c_handler->i2c_port_num;
|
||
|
uint8_t *src_buf = (uint8_t *) pvBuffer;
|
||
|
if (!iot_i2c_handler->is_slave_addr_set) {
|
||
|
I2C_LOGE( "Slave address not set.\n");
|
||
|
return IOT_I2C_SLAVE_ADDRESS_NOT_SET;
|
||
|
}
|
||
|
if (!iot_i2c_handler->driver_installed) {
|
||
|
return IOT_I2C_INVALID_VALUE;
|
||
|
}
|
||
|
if (bk_i2c_get_busstate(i2c_port_num)== pdFALSE) {
|
||
|
return IOT_I2C_BUSY;
|
||
|
}
|
||
|
iot_i2c_handler->async_op = true;
|
||
|
ret = bk_i2c_master_write(i2c_port_num, iot_i2c_handler->slave_addr,src_buf, xBytes, WAITNOTICKS);
|
||
|
if (ret != BK_OK) {
|
||
|
I2C_LOGE( "i2c master write failed");
|
||
|
return IOT_I2C_WRITE_FAILED;
|
||
|
}
|
||
|
iot_i2c_handler->bytes_to_write = xBytes;
|
||
|
iot_i2c_handler->is_send_no_stop_flag_set = false;
|
||
|
I2C_LOGD( "iot_i2c_write_async.\n");
|
||
|
return (ret == BK_OK) ? IOT_I2C_SUCCESS : IOT_I2C_WRITE_FAILED;
|
||
|
}
|
||
|
|
||
|
int32_t iot_i2c_read_sync( IotI2CHandle_t const pxI2CPeripheral, uint8_t *const pvBuffer, size_t xBytes)
|
||
|
{
|
||
|
bk_err_t ret = BK_OK;
|
||
|
if (pxI2CPeripheral == NULL || pvBuffer == NULL) {
|
||
|
I2C_LOGD( "Invalid arguments");
|
||
|
return IOT_I2C_INVALID_VALUE;
|
||
|
}
|
||
|
IotI2CDescriptor_t *iot_i2c_handler = (IotI2CDescriptor_t *) pxI2CPeripheral;
|
||
|
int32_t i2c_port_num = (int32_t) iot_i2c_handler->i2c_port_num;
|
||
|
uint8_t *src_buf = (uint8_t *) pvBuffer;
|
||
|
if (!iot_i2c_handler->is_slave_addr_set) {
|
||
|
I2C_LOGE( "Slave address not set.\n");
|
||
|
return IOT_I2C_SLAVE_ADDRESS_NOT_SET;
|
||
|
}
|
||
|
if (bk_i2c_get_busstate(i2c_port_num)== pdFALSE) {
|
||
|
return IOT_I2C_BUSY;
|
||
|
}
|
||
|
iot_i2c_handler->async_op = false;
|
||
|
|
||
|
ret = bk_i2c_master_write(i2c_port_num, iot_i2c_handler->slave_addr,src_buf, xBytes, WAITFOREVER);
|
||
|
if (ret != BK_OK) {
|
||
|
I2C_LOGE( "i2c master read failed");
|
||
|
return IOT_I2C_READ_FAILED;
|
||
|
}
|
||
|
iot_i2c_handler->is_send_no_stop_flag_set = false;
|
||
|
iot_i2c_handler->bytes_to_read = xBytes;
|
||
|
|
||
|
I2C_LOGI( "iot_i2c_read_sync.\n");
|
||
|
return (ret == BK_OK) ? IOT_I2C_SUCCESS : IOT_I2C_READ_FAILED;
|
||
|
}
|
||
|
|
||
|
int32_t iot_i2c_write_sync( IotI2CHandle_t const pxI2CPeripheral, uint8_t *const pvBuffer, size_t xBytes)
|
||
|
{
|
||
|
bk_err_t ret = BK_OK;
|
||
|
if (pxI2CPeripheral == NULL || pvBuffer == NULL) {
|
||
|
I2C_LOGE( "Invalid arguments");
|
||
|
return IOT_I2C_INVALID_VALUE;
|
||
|
}
|
||
|
IotI2CDescriptor_t *iot_i2c_handler = (IotI2CDescriptor_t *) pxI2CPeripheral;
|
||
|
int32_t i2c_port_num = (int32_t) iot_i2c_handler->i2c_port_num;
|
||
|
uint8_t *src_buf = (uint8_t *) pvBuffer;
|
||
|
if (!iot_i2c_handler->is_slave_addr_set) {
|
||
|
I2C_LOGE( "Slave address not set.\n");
|
||
|
return IOT_I2C_SLAVE_ADDRESS_NOT_SET;
|
||
|
}
|
||
|
if (bk_i2c_get_busstate(i2c_port_num) == pdFALSE) {
|
||
|
return IOT_I2C_BUSY;
|
||
|
}
|
||
|
iot_i2c_handler->async_op = false;
|
||
|
|
||
|
ret = bk_i2c_master_write(i2c_port_num, iot_i2c_handler->slave_addr,src_buf, xBytes, WAITFOREVER );
|
||
|
if (ret != BK_OK) {
|
||
|
I2C_LOGE( "i2c master write failed");
|
||
|
return IOT_I2C_WRITE_FAILED;
|
||
|
}
|
||
|
iot_i2c_handler->bytes_to_write = xBytes;
|
||
|
iot_i2c_handler->is_send_no_stop_flag_set = false;
|
||
|
|
||
|
I2C_LOGI( "iot_i2c_write_sync.\n");
|
||
|
return (ret == BK_OK) ? IOT_I2C_SUCCESS : IOT_I2C_WRITE_FAILED;
|
||
|
}
|
||
|
|
||
|
int32_t iot_i2c_close(IotI2CHandle_t const pxI2CPeripheral)
|
||
|
{
|
||
|
bk_err_t ret ;
|
||
|
if (pxI2CPeripheral == NULL) {
|
||
|
I2C_LOGE( "Invalid I2C Handler.\n");
|
||
|
return IOT_I2C_INVALID_VALUE;
|
||
|
}
|
||
|
IotI2CDescriptor_t *iot_i2c_handler = (IotI2CDescriptor_t *) pxI2CPeripheral;
|
||
|
if (!(0x01 & (i2c_bit_mask >> iot_i2c_handler->i2c_port_num))) {
|
||
|
I2C_LOGE( "I2C Handler is not initialised.\n");
|
||
|
return IOT_I2C_INVALID_VALUE;
|
||
|
}
|
||
|
|
||
|
i2c_bit_mask = i2c_bit_mask & ~(BIT(iot_i2c_handler->i2c_port_num));
|
||
|
int32_t i2c_port_num = (int32_t) iot_i2c_handler->i2c_port_num;
|
||
|
if (iot_i2c_handler->driver_installed) {
|
||
|
if (bk_i2c_get_busstate(iot_i2c_handler->i2c_port_num) == pdFALSE) {
|
||
|
return IOT_I2C_BUSY;
|
||
|
}
|
||
|
ret = bk_i2c_deinit(i2c_port_num);
|
||
|
if (ret != BK_OK) {
|
||
|
I2C_LOGE( "bk_i2c_deinit failed.\n");
|
||
|
return IOT_I2C_INVALID_VALUE;
|
||
|
}
|
||
|
//os_memset(&iottimercallback[i2c_port_num],0,sizeof(IotCallback_t));
|
||
|
I2C_LOGI( "bk_i2c_deinit ok.\n");
|
||
|
}
|
||
|
|
||
|
os_free(pxI2CPeripheral);
|
||
|
return IOT_I2C_SUCCESS;
|
||
|
}
|
||
|
|
||
|
int32_t iot_i2c_cancel(IotI2CHandle_t const pxI2CPeripheral)
|
||
|
|
||
|
{
|
||
|
return IOT_I2C_FUNCTION_NOT_SUPPORTED;
|
||
|
}
|