diff --git a/CMakeLists.txt b/CMakeLists.txt index 768c7c15..64b00d23 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -134,6 +134,12 @@ if(NOT EMULATOR_BUILD) softwinner ) + #i2c_ext application + file(GLOB SRC_FILES_I2C_EXT "src/i2c_ext/*.c" "src/i2c_ext/*.h") + add_executable(i2c_ext + ${SRC_FILES_I2C_EXT} + ) + # rtspLive application file(GLOB SRC_FILES_RTSPLIVE "src/rtspLive/*.cpp" "src/rtspLive/*.hh") file(GLOB SRC_FILES_RTSPLIVE_STREAM "src/rtspLive/stream/*.c" "src/rtspLive/stream/*.h") diff --git a/src/i2c_ext/i2c_ext.c b/src/i2c_ext/i2c_ext.c new file mode 100644 index 00000000..72bc5a2d --- /dev/null +++ b/src/i2c_ext/i2c_ext.c @@ -0,0 +1,261 @@ +#include "i2c_ext.h" + +#include +#include +#include +#include +#include +#include +#include + +#define IIC_PORTS 4 +static char *IIC_DEVS[IIC_PORTS] = { + "/dev/i2c-0", + "/dev/i2c-1", + "/dev/i2c-2", + "/dev/i2c-3", +}; + +int i2c_fd; +bool i2c_report_once = false; +i2c_ext_mode_t mode; +arg_t arg; + +void i2c_ext_init(uint8_t port) { + i2c_fd = open(IIC_DEVS[port], O_RDONLY); + + if (port < 0 || port >= IIC_PORTS) { + printf("Port %d contains an invalid range [0=N/A,1=Right,2=Main,3=Left]", port); + return; + } else if (i2c_fd < 0) { + if (!i2c_report_once) { + i2c_report_once = true; + printf("Device %d:%s is not available [0=N/A,1=Right,2=Main,3=Left]", port, IIC_DEVS[port]); + } + return; + } +} + +static int i2c_write_ext(i2c_ext_mode_t mode, uint8_t slave_address, uint32_t reg_address, uint32_t reg_val) { + struct i2c_rdwr_ioctl_data work_queue; + struct i2c_msg msgs; + uint8_t obuf[8]; + const uint8_t alen = (mode >> 2) + 1; + const uint8_t dlen = (mode & 3) + 1; + const uint8_t len = alen + dlen; + int i; + int ret; + + work_queue.nmsgs = 1; + work_queue.msgs = &msgs; + msgs.buf = obuf; + + (work_queue.msgs[0]).len = len; + (work_queue.msgs[0]).flags = I2C_SMBUS_WRITE; + + (work_queue.msgs[0]).addr = slave_address; + + for (i = 0; i < alen; i++) { + (work_queue.msgs[0]).buf[i] = (reg_address >> (i << 3)) & 0xff; + } + + for (i = 0; i < dlen; i++) { + (work_queue.msgs[0]).buf[i + alen] = (reg_val >> (i << 3)) & 0xff; + } + + ret = ioctl(i2c_fd, I2C_RDWR, (unsigned long)&work_queue); + if (ret < 0) { + printf("iic_write[%x.%x]<-%x failed.", slave_address, reg_address, reg_val); + ret = 0; + } + return ret; +} + +static void i2c_read_ext(i2c_ext_mode_t mode, uint32_t slave_address, uint32_t reg_address) { + struct i2c_rdwr_ioctl_data work_queue; + struct i2c_msg msgs[2]; + const uint8_t alen = (mode >> 2) + 1; + const uint8_t dlen = (mode & 3) + 1; + const uint8_t len = alen + dlen; + int i, j; + int ret; + uint8_t reg_data[4]; + + reg_data[0] = (uint8_t)(reg_address & 0xff); + reg_data[1] = (uint8_t)((reg_address >> 8) & 0xff); + reg_data[2] = (uint8_t)((reg_address >> 16) & 0xff); + reg_data[3] = (uint8_t)((reg_address >> 24) & 0xff); + + work_queue.nmsgs = 2; + work_queue.msgs = msgs; + + (work_queue.msgs[0]).len = alen; + (work_queue.msgs[0]).flags = I2C_SMBUS_WRITE; + (work_queue.msgs[0]).addr = (uint8_t)slave_address; + (work_queue.msgs[0]).buf = reg_data; + + (work_queue.msgs[1]).len = dlen; + (work_queue.msgs[1]).flags = I2C_SMBUS_READ; + (work_queue.msgs[1]).addr = (uint8_t)slave_address; + (work_queue.msgs[1]).buf = reg_data; + ret = ioctl(i2c_fd, I2C_RDWR, (unsigned long)&work_queue); + + if (ret < 0) { + printf("\r\ni2c_read[%x.%x] failed.", slave_address, reg_address); + } else { + printf("\r\n0x%08x: 0x", reg_address); + for (i = 0; i < dlen; i++) { + printf("%02x", reg_data[i]); + } + } +} + +void display_usage(void) { + printf("\r\nusage:\r\n"); + printf("\r\n i2c_ext -p[port] -m[mode] -w/r [device address] [reg address] [reg value]"); + printf("\r\n -p: i2c bus port"); + printf("\r\n 0: None "); + printf("\r\n 1: Right "); + printf("\r\n 2: Main "); + printf("\r\n 3: Left "); + printf("\r\n -m: mode"); + printf("\r\n 0: A8D8 "); + printf("\r\n 1: A8D16 "); + printf("\r\n 2: A8D24 "); + printf("\r\n 3: A8D32 "); + printf("\r\n 4: A16D8 "); + printf("\r\n 5: A16D16"); + printf("\r\n 6: A16D24"); + printf("\r\n 7: A16D32"); + printf("\r\n -w/r: write or read"); + printf("\r\n -w: write"); + printf("\r\n -r: read"); + printf("\r\n [slave address(7 bits)]"); + printf("\r\n eg 64: means 0x64"); + printf("\r\n [reg address(hex)]"); + printf("\r\n eg ff: means ff"); + printf("\r\n [reg value(hex)]"); + printf("\r\n reg_value for write"); + printf("\r\n length for read"); + printf("\r\n eg 6: 0x06"); + printf("\r\n"); +} + +void arg_error(char cmd) { + printf("\r\n-%c:error", cmd); +} + +int is_hex_string(char c) { + if (c >= '0' && c <= '9') { + return c - '0'; + } else if (c >= 'A' && c <= 'F') { + return c - 'A' + 10; + } else if (c >= 'a' && c <= 'f') { + return c - 'a' + 10; + } else { + return -1; + } +} + +uint8_t parse_arg(int argc, char *argv[]) { + uint8_t ret = 0; + uint8_t i, j, k; + char cur_op[256] = {0}; + + if (argc <= 1) { + printf("No parameter detected"); + display_usage(); + ret = 1; + } else { + arg.data[0] = 0; + arg.data[1] = 0; + arg.data[2] = 0; + // parse + k = 0; + for (i = 1; i < argc; i++) { + memset(cur_op, 0, sizeof(cur_op)); + memcpy(cur_op, argv[i], sizeof(cur_op)); + + if (cur_op[0] == '-') { + switch (cur_op[1]) { + case 'p': + case 'P': + arg.port = cur_op[2] - '0'; + break; + case 'm': + case 'M': + arg.mode = cur_op[2] - '0'; + break; + + case 'w': + case 'W': + arg.is_write = 1; + break; + + case 'r': + case 'R': + arg.is_write = 0; + break; + + default: + break; + } + } else { + // parse data + j = 0; + while (1) { + if (cur_op[j] == 0) { + // string end + break; + } else { + if (is_hex_string(cur_op[j]) < 0) { + break; + } else { + arg.data[k] = arg.data[k] << 4; + arg.data[k] += is_hex_string(cur_op[j]); + } + j++; + } + } + k++; + k &= 3; + } + } + + // parse result + printf("\r\nmode: %d", arg.mode); + printf("\r\nis_write: %d", arg.is_write); + printf("\r\nslave address:0x%02x", arg.data[0]); + printf("\r\nreg_addr: 0x%08x", arg.data[1]); + if (arg.is_write) + printf("\r\nreg_data: 0x%08x", arg.data[2]); + else { + printf("\r\nlen: 0x%08x", arg.data[2]); + } + printf("\r\n"); + } + + return ret; +} + +int main(int argc, char *argv[]) { + if (parse_arg(argc, argv)) + return 0; + + i2c_ext_init(arg.port); + if (arg.is_write) { + i2c_write_ext(arg.mode, arg.data[0], arg.data[1], arg.data[2]); + i2c_read_ext(arg.mode, arg.data[0], arg.data[1]); + printf("\r\n"); + } else { + + if (arg.data[2] == 0) { + arg.data[2] = 1; + } + + for (int i = 0; i < arg.data[2]; i++) { + i2c_read_ext(arg.mode, arg.data[0], (arg.data[1] + i)); + } + printf("\r\n"); + } +} \ No newline at end of file diff --git a/src/i2c_ext/i2c_ext.h b/src/i2c_ext/i2c_ext.h new file mode 100644 index 00000000..f1fb9fa0 --- /dev/null +++ b/src/i2c_ext/i2c_ext.h @@ -0,0 +1,21 @@ +#pragma once +#include "stdbool.h" +#include + +typedef enum { + A8D8 = 0, + A8D16 = 1, + A8D24 = 2, + A8D32 = 3, + A16D8 = 4, + A16D16 = 5, + A16D24 = 6, + A16D32 = 7, +} i2c_ext_mode_t; + +typedef struct { + uint8_t port; + i2c_ext_mode_t mode; + bool is_write; + uint32_t data[3]; +} arg_t; \ No newline at end of file