Skip to content

Commit

Permalink
example: i2c-usb-bridge: Initial support
Browse files Browse the repository at this point in the history
This application bridges data to and from the serial console to the
I2C bus.
This allows a PC to communicate with an I2C device via a USB port.

On a PC you can connect to the UART of the device running this
application to access the I2C bus. The Tock device will then act as
a I2C master to interact with I2C devices.

Signed-off-by: Alistair Francis <[email protected]>
  • Loading branch information
alistair23 committed Jan 10, 2024
1 parent e361aa1 commit 6d016f9
Show file tree
Hide file tree
Showing 3 changed files with 210 additions and 0 deletions.
11 changes: 11 additions & 0 deletions examples/i2c-usb-bridge/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Makefile for user application

# Specify this directory relative to the current application.
TOCK_USERLAND_BASE_DIR = ../..

# Which files to compile.
C_SRCS := $(wildcard *.c)

# Include userland master makefile. Contains rules and flags for actually
# building the application.
include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk
39 changes: 39 additions & 0 deletions examples/i2c-usb-bridge/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
I2C USB Bridge
==============

This application bridges data to and from the serial console to the I2C bus.
This allows a PC to communicate with an I2C device via a USB port.

On a PC you can connect to the UART of the device running this application to
access the I2C bus. The Tock device will then act as a I2C master to interact
with I2C devices.

----------------------- --------------------------- ----------
| | | USB | Tock | I2C | I2C | I2C |
| PC (Linux) | UART | <---> | I2C USB Bridge | Master | <---> | Device |
| | | | | | | |
----------------------- --------------------------- ----------

Command Format
--------------

The command format is designed to match the
[I2C Driver](https://i2cdriver.com/i2cdriver.pdf) format.

The format is as follows

```
<r|w> <addr> <len> <data>
```

For example to read two bytes from address `0x23`

```
r 0x23 2
```

To write `0x12, 0x56` to address `0x23`

```
w 0x23 2 0x12,0x56
```
160 changes: 160 additions & 0 deletions examples/i2c-usb-bridge/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <console.h>
#include <i2c_master.h>

#define DATA_LEN 64

char command_buf[DATA_LEN];
uint8_t recieve_buf[DATA_LEN];
uint8_t send_buf[DATA_LEN];

static int get_command(void) {
int idx = 0;
memset(command_buf, 0, DATA_LEN);

// Read in characters until a new line
while (1) {
int c = getch();

if (c == RETURNCODE_FAIL) {
printf("getch() failed!\n");

return c;
} else {
putnstr((char*) &c, 1);

if (c == '\n' || c == '\r') {
return 0;
} else {
// If this is a valid number record it
command_buf[idx] = c;
idx += 1;

// If our buffer is full, quit
if (idx >= DATA_LEN) {
return 0;
}
}
}
}
}

static void read_data(char *command) {
char *op_string, *addr_string, *len_string;
long address, len;
int i;

op_string = strtok(command, " ");
if (op_string == NULL) {
printf("Unable to determine operation\n");
return;
}

addr_string = strtok(NULL, " ");
if (addr_string == NULL) {
printf("Unable to determine address\n");
return;
}

len_string = strtok(NULL, " ");
if (len_string == NULL) {
printf("Unable to determine length\n");
return;
}

address = strtol(addr_string, NULL, 16);
len = strtol(len_string, NULL, 16);

printf("Reading %ld bytes from 0x%lx\n", len, address);

i2c_master_read_sync(address, recieve_buf, len);

for (i = 0; i < len; i++) {
printf("%c ", recieve_buf[i]);
}

printf("Application Operation complete\n");
}

static void write_data(char *command) {
char *op_string, *addr_string, *len_string;
long address, len;
int i;

op_string = strtok(command, " ");
if (op_string == NULL) {
printf("Unable to determine operation\n");
return;
}

addr_string = strtok(NULL, " ");
if (addr_string == NULL) {
printf("Unable to determine address\n");
return;
}

len_string = strtok(NULL, " ");
if (len_string == NULL) {
printf("Unable to determine length\n");
return;
}

address = strtol(addr_string, NULL, 16);
len = strtol(len_string, NULL, 16);

if (len > DATA_LEN) {
printf("The data is larger then the maximum buffer size\n");
return;
}

printf("Writing %ld bytes to 0x%lx\n", len, address);

for (i = 0; i < len; i++) {
char *byte = strtok(NULL, ",");

if (byte == NULL) {
printf("Not enough data supplied\n");
return;
}

long value = strtol(byte, NULL, 16);

send_buf[i] = value;
}

for (i = 0; i < len; i++) {
printf("%c ", send_buf[i]);
}

i2c_master_write_sync(address, send_buf, len);

printf("Application Operation complete\n");
}

int main(void) {
printf("I2C USB Bridge\n");

while (1) {
int ret = get_command();

if (ret < 0) {
printf("Error reading stdin\n");
exit(-1);
}

if (strncmp(command_buf, "r", 1) == 0) {
read_data(command_buf);
} else if (strncmp(command_buf, "w", 1) == 0) {
write_data(command_buf);
} else {
printf("Invalid command: %s\n", command_buf);
printf("Check the app README for instructinos\n");
}
}

return 0;
}

0 comments on commit 6d016f9

Please sign in to comment.