Mock out mgos_i2c.h to work with Linux.
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
build/
|
||||
mgos_i2c
|
32
Makefile
Normal file
32
Makefile
Normal file
@ -0,0 +1,32 @@
|
||||
TARGET = mgos_i2c
|
||||
CC = gcc
|
||||
CFLAGS = -g -O -Wall -I include/
|
||||
LINKER = gcc
|
||||
LFLAGS = -O -Wall -I. -lm
|
||||
|
||||
.PHONY: default all clean
|
||||
|
||||
default: $(TARGET)
|
||||
all: default
|
||||
|
||||
SRCDIR = src
|
||||
INCDIR = include
|
||||
OBJDIR = build
|
||||
BINDIR = .
|
||||
|
||||
SOURCES := $(wildcard $(SRCDIR)/*.c)
|
||||
INCLUDES := $(wildcard $(SRCDIR)/*.h)
|
||||
OBJECTS := $(SOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
|
||||
RM = rm -f
|
||||
|
||||
|
||||
$(BINDIR)/$(TARGET): $(OBJECTS)
|
||||
$(LINKER) $(OBJECTS) $(LFLAGS) -o $@
|
||||
|
||||
$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
$(RM) $(OBJECTS)
|
||||
$(RM) $(BINDIR)/$(TARGET)
|
14
include/mgos.h
Normal file
14
include/mgos.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef __MGOS_H
|
||||
#define __MGOS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "mgos_mock.h"
|
||||
|
||||
#endif // __MGOS_H
|
117
include/mgos_i2c.h
Normal file
117
include/mgos_i2c.h
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2015 Cesanta
|
||||
* All rights reserved
|
||||
*/
|
||||
|
||||
/*
|
||||
* I2C API.
|
||||
*
|
||||
* See https://en.wikipedia.org/wiki/I%C2%B2C for the background information.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "mgos.h"
|
||||
|
||||
/* Each platform defines its own I2C connection parameters. */
|
||||
struct mgos_i2c;
|
||||
|
||||
/* If this special address is passed to read or write, START is not generated
|
||||
* and address is not put on the bus. It is assumed that this is a continuation
|
||||
* of a previous operation which (after read or write with stop = false). */
|
||||
#define MGOS_I2C_ADDR_CONTINUE ((uint16_t) -1)
|
||||
|
||||
/*
|
||||
* Read specified number of bytes from the specified address.
|
||||
* Address should not include the R/W bit. If addr is -1, START is not
|
||||
* performed.
|
||||
* If |stop| is true, then at the end of the operation bus will be released.
|
||||
*/
|
||||
bool mgos_i2c_read(struct mgos_i2c *i2c, uint16_t addr, void *data, size_t len,
|
||||
bool stop);
|
||||
|
||||
/*
|
||||
* Write specified number of bytes from the specified address.
|
||||
* Address should not include the R/W bit. If addr is -1, START is not
|
||||
* performed.
|
||||
* If |stop| is true, then at the end of the operation bus will be released.
|
||||
*/
|
||||
bool mgos_i2c_write(struct mgos_i2c *i2c, uint16_t addr, const void *data,
|
||||
size_t len, bool stop);
|
||||
|
||||
/*
|
||||
* Release the bus (when left unreleased after read or write).
|
||||
*/
|
||||
void mgos_i2c_stop(struct mgos_i2c *i2c);
|
||||
|
||||
/* Most implementations should support these two, support for other frequencies
|
||||
* is platform-dependent. */
|
||||
#define MGOS_I2C_FREQ_100KHZ 100000
|
||||
#define MGOS_I2C_FREQ_400KHZ 400000
|
||||
|
||||
/*
|
||||
* Get I2C interface frequency.
|
||||
*/
|
||||
int mgos_i2c_get_freq(struct mgos_i2c *i2c);
|
||||
|
||||
/*
|
||||
* Set I2C interface frequency.
|
||||
*/
|
||||
bool mgos_i2c_set_freq(struct mgos_i2c *i2c, int freq);
|
||||
|
||||
/*
|
||||
* Helper for reading 1-byte register `reg` from a device at address `addr`.
|
||||
* In case of success return a numeric byte value from 0x00 to 0xff; otherwise
|
||||
* return -1.
|
||||
*/
|
||||
int mgos_i2c_read_reg_b(struct mgos_i2c *conn, uint16_t addr, uint8_t reg);
|
||||
|
||||
/*
|
||||
* Helper for reading 2-byte register `reg` from a device at address `addr`.
|
||||
* In case of success returns a numeric big-endian value: e.g. if 0x01, 0x02
|
||||
* was read from a device, 0x0102 will be returned.
|
||||
*
|
||||
* In case of error returns -1.
|
||||
*/
|
||||
int mgos_i2c_read_reg_w(struct mgos_i2c *conn, uint16_t addr, uint8_t reg);
|
||||
|
||||
/*
|
||||
* Helper for reading `n`-byte register value from a device. Returns true on
|
||||
* success, false on error. Data is written to `buf`, which should be large
|
||||
* enough.
|
||||
*/
|
||||
bool mgos_i2c_read_reg_n(struct mgos_i2c *conn, uint16_t addr, uint8_t reg,
|
||||
size_t n, uint8_t *buf);
|
||||
|
||||
/*
|
||||
* Helper for writing 1-byte register `reg` to a device at address `addr`.
|
||||
* Returns `true` in case of success, `false` otherwise.
|
||||
*/
|
||||
bool mgos_i2c_write_reg_b(struct mgos_i2c *conn, uint16_t addr, uint8_t reg,
|
||||
uint8_t value);
|
||||
|
||||
/*
|
||||
* Helper for writing 2-byte register `reg` to a device at address `addr`.
|
||||
* The value is big-endian: e.g. if `value` is `0x0102`, then `0x01, 0x02`
|
||||
* will be written.
|
||||
* Returns `true` in case of success, `false` otherwise.
|
||||
*/
|
||||
bool mgos_i2c_write_reg_w(struct mgos_i2c *conn, uint16_t addr, uint8_t reg,
|
||||
uint16_t value);
|
||||
|
||||
/*
|
||||
* Helper for writing `n`-byte register `reg` to a device at address `addr`.
|
||||
* Returns `true` in case of success, `false` otherwise.
|
||||
*/
|
||||
bool mgos_i2c_write_reg_n(struct mgos_i2c *conn, uint16_t addr, uint8_t reg,
|
||||
size_t n, const uint8_t *buf);
|
||||
|
||||
/* Close i2c connection and free resources. */
|
||||
void mgos_i2c_close(struct mgos_i2c *conn);
|
||||
|
||||
/* Return i2c bus handle that is set up via the sysconfig. */
|
||||
struct mgos_i2c *mgos_i2c_get_global(void);
|
||||
|
||||
// User contributed!
|
||||
bool mgos_i2c_open(int busnr);
|
||||
|
35
include/mgos_mock.h
Normal file
35
include/mgos_mock.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef __MGOS_MOCK_H
|
||||
#define __MGOS_MOCK_H
|
||||
|
||||
/* Some functions mocked from MGOS, so we can run unit tests standalone.
|
||||
*/
|
||||
|
||||
#include "mgos.h"
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
// mgos_log
|
||||
enum cs_log_level {
|
||||
LL_NONE = -1,
|
||||
LL_ERROR = 0,
|
||||
LL_WARN = 1,
|
||||
LL_INFO = 2,
|
||||
LL_DEBUG = 3,
|
||||
LL_VERBOSE_DEBUG = 4,
|
||||
|
||||
_LL_MIN = -2,
|
||||
_LL_MAX = 5,
|
||||
};
|
||||
|
||||
int log_print_prefix(enum cs_log_level l, const char *func, const char *file);
|
||||
|
||||
#define LOG(l, x) \
|
||||
do { \
|
||||
if (log_print_prefix(l, __func__, __FILE__)) printf x; \
|
||||
printf("\r\n"); \
|
||||
} while (0)
|
||||
|
||||
|
||||
float mg_time();
|
||||
|
||||
#endif // __MGOS_MOCK_H
|
20
src/main.c
Normal file
20
src/main.c
Normal file
@ -0,0 +1,20 @@
|
||||
#include "mgos.h"
|
||||
#include "mgos_i2c.h"
|
||||
|
||||
#define I2CBUSNR 7
|
||||
|
||||
int main() {
|
||||
struct mgos_i2c *i2c;
|
||||
|
||||
if (!mgos_i2c_open(I2CBUSNR)) {
|
||||
LOG(LL_ERROR, ("Cannot open I2C bus %u", I2CBUSNR));
|
||||
return -1;
|
||||
}
|
||||
i2c = mgos_i2c_get_global();
|
||||
if (!i2c) {
|
||||
LOG(LL_ERROR, ("Cannot open I2C bus"));
|
||||
return -2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
227
src/mgos_i2c.c
Normal file
227
src/mgos_i2c.c
Normal file
@ -0,0 +1,227 @@
|
||||
#include "mgos_i2c.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/i2c-dev.h>
|
||||
#include <i2c/smbus.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
|
||||
struct mgos_i2c {
|
||||
int fd;
|
||||
char *filename;
|
||||
};
|
||||
|
||||
static struct mgos_i2c *s_global_i2c_bus = NULL;
|
||||
|
||||
bool mgos_i2c_read(struct mgos_i2c *i2c, uint16_t addr, void *data, size_t len, bool stop) {
|
||||
size_t ret;
|
||||
|
||||
if (!i2c) {
|
||||
LOG(LL_ERROR, ("No I2C bus"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ioctl(i2c->fd,I2C_SLAVE,addr) < 0) {
|
||||
LOG(LL_ERROR, ("Cannot select slave 0x%04x on I2C bus", addr));
|
||||
return false;
|
||||
}
|
||||
ret = read(i2c->fd, data, len);
|
||||
return (ret == len);
|
||||
}
|
||||
|
||||
bool mgos_i2c_write(struct mgos_i2c *i2c, uint16_t addr, const void *data, size_t len, bool stop) {
|
||||
size_t ret;
|
||||
|
||||
if (!i2c) {
|
||||
LOG(LL_ERROR, ("No I2C bus"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ioctl(i2c->fd,I2C_SLAVE,addr) < 0) {
|
||||
LOG(LL_ERROR, ("Cannot select slave 0x%04x on I2C bus", addr));
|
||||
return false;
|
||||
}
|
||||
ret = write(i2c->fd, data, len);
|
||||
return (ret == len);
|
||||
}
|
||||
|
||||
void mgos_i2c_stop(struct mgos_i2c *i2c) {
|
||||
return;
|
||||
}
|
||||
|
||||
int mgos_i2c_get_freq(struct mgos_i2c *i2c) {
|
||||
return MGOS_I2C_FREQ_100KHZ;
|
||||
}
|
||||
|
||||
bool mgos_i2c_set_freq(struct mgos_i2c *i2c, int freq) {
|
||||
if (freq==MGOS_I2C_FREQ_100KHZ) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
int mgos_i2c_read_reg_b(struct mgos_i2c *i2c, uint16_t addr, uint8_t reg) {
|
||||
uint8_t data;
|
||||
|
||||
if (!i2c) {
|
||||
LOG(LL_ERROR, ("No I2C bus"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ioctl(i2c->fd,I2C_SLAVE,addr) < 0) {
|
||||
LOG(LL_ERROR, ("Cannot select slave 0x%04x on I2C bus", addr));
|
||||
return -1;
|
||||
}
|
||||
if (1 != write(i2c->fd, ®, 1)) {
|
||||
LOG(LL_ERROR, ("Cannot select register 0x%02x on device 0x%04x", reg, addr));
|
||||
return -1;
|
||||
}
|
||||
if (1 != read(i2c->fd, &data, 1)) {
|
||||
LOG(LL_ERROR, ("Cannot read register 0x%02x on device 0x%04x", reg, addr));
|
||||
return -1;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
int mgos_i2c_read_reg_w(struct mgos_i2c *i2c, uint16_t addr, uint8_t reg) {
|
||||
uint16_t data;
|
||||
|
||||
if (!i2c) {
|
||||
LOG(LL_ERROR, ("No I2C bus"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ioctl(i2c->fd,I2C_SLAVE,addr) < 0) {
|
||||
LOG(LL_ERROR, ("Cannot select slave 0x%04x on I2C bus", addr));
|
||||
return -1;
|
||||
}
|
||||
if (1 != write(i2c->fd, ®, 1)) {
|
||||
LOG(LL_ERROR, ("Cannot select register 0x%02x on device 0x%04x", reg, addr));
|
||||
return -1;
|
||||
}
|
||||
if (2 != read(i2c->fd, &data, 2)) {
|
||||
LOG(LL_ERROR, ("Cannot read register 0x%02x on device 0x%04x", reg, addr));
|
||||
return -1;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
bool mgos_i2c_read_reg_n(struct mgos_i2c *i2c, uint16_t addr, uint8_t reg, size_t n, uint8_t *buf) {
|
||||
if (!i2c) {
|
||||
LOG(LL_ERROR, ("No I2C bus"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ioctl(i2c->fd,I2C_SLAVE,addr) < 0) {
|
||||
LOG(LL_ERROR, ("Cannot select slave 0x%04x on I2C bus", addr));
|
||||
return false;
|
||||
}
|
||||
if (1 != write(i2c->fd, ®, 1)) {
|
||||
LOG(LL_ERROR, ("Cannot select register 0x%02x on device 0x%04x", reg, addr));
|
||||
return false;
|
||||
}
|
||||
if (n != read(i2c->fd, buf, n)) {
|
||||
LOG(LL_ERROR, ("Cannot read %lu bytes at register 0x%02x on device 0x%04x", n, reg, addr));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mgos_i2c_write_reg_b(struct mgos_i2c *i2c, uint16_t addr, uint8_t reg, uint8_t value) {
|
||||
uint8_t data[2];
|
||||
|
||||
if (!i2c) {
|
||||
LOG(LL_ERROR, ("No I2C bus"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ioctl(i2c->fd,I2C_SLAVE,addr) < 0) {
|
||||
LOG(LL_ERROR, ("Cannot select slave 0x%04x on I2C bus", addr));
|
||||
return false;
|
||||
}
|
||||
data[0]=reg;
|
||||
data[1]=value;
|
||||
if (2 != write(i2c->fd, data, 2)) {
|
||||
LOG(LL_ERROR, ("Cannot write to register 0x%02x on device 0x%04x", reg, addr));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mgos_i2c_write_reg_w(struct mgos_i2c *i2c, uint16_t addr, uint8_t reg, uint16_t value) {
|
||||
uint8_t data[3];
|
||||
|
||||
if (!i2c) {
|
||||
LOG(LL_ERROR, ("No I2C bus"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ioctl(i2c->fd,I2C_SLAVE,addr) < 0) {
|
||||
LOG(LL_ERROR, ("Cannot select slave 0x%04x on I2C bus", addr));
|
||||
return false;
|
||||
}
|
||||
data[0]=reg;
|
||||
data[1]=(uint8_t)(0xFF & (value >> 0));
|
||||
data[2]=(uint8_t)(0xFF & (value >> 8));
|
||||
|
||||
if (3 != write(i2c->fd, data, 3)) {
|
||||
LOG(LL_ERROR, ("Cannot write to register 0x%02x on device 0x%04x", reg, addr));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mgos_i2c_write_reg_n(struct mgos_i2c *i2c, uint16_t addr, uint8_t reg, size_t n, const uint8_t *buf) {
|
||||
if (!i2c) {
|
||||
LOG(LL_ERROR, ("No I2C bus"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ioctl(i2c->fd,I2C_SLAVE,addr) < 0) {
|
||||
LOG(LL_ERROR, ("Cannot select slave 0x%04x on I2C bus", addr));
|
||||
return false;
|
||||
}
|
||||
if (1 != write(i2c->fd, ®, 1)) {
|
||||
LOG(LL_ERROR, ("Cannot select register 0x%02x on device 0x%04x", reg, addr));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (n != write(i2c->fd, buf, n)) {
|
||||
LOG(LL_ERROR, ("Cannot write to register 0x%02x on device 0x%04x", reg, addr));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void mgos_i2c_close(struct mgos_i2c *i2c) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct mgos_i2c *mgos_i2c_get_global(void) {
|
||||
return s_global_i2c_bus;
|
||||
}
|
||||
|
||||
// User provided function to interface with Linux I2C driver
|
||||
bool mgos_i2c_open(int busnr) {
|
||||
int fd;
|
||||
char filename[20];
|
||||
struct mgos_i2c *i2c;
|
||||
|
||||
sprintf(filename,"/dev/i2c-%d",busnr);
|
||||
if ((fd = open(filename,O_RDWR)) < 0) {
|
||||
LOG(LL_ERROR, ("Could not open %s", filename));
|
||||
return false;
|
||||
}
|
||||
i2c = calloc(1, sizeof(struct mgos_i2c));
|
||||
if (!i2c) {
|
||||
LOG(LL_ERROR, ("Could not allocate mgos_i2c handle for %s", filename));
|
||||
return false;
|
||||
}
|
||||
i2c->fd=fd;
|
||||
i2c->filename=strdup(filename);
|
||||
s_global_i2c_bus=i2c;
|
||||
LOG(LL_INFO, ("Opened I2C bus on %s", filename));
|
||||
|
||||
return true;
|
||||
}
|
44
src/mgos_mock.c
Normal file
44
src/mgos_mock.c
Normal file
@ -0,0 +1,44 @@
|
||||
/* Some functions mocked from MGOS, so we can run unit tests standalone.
|
||||
*/
|
||||
|
||||
#include "mgos_mock.h"
|
||||
|
||||
int _mgos_timers = 0;
|
||||
|
||||
int log_print_prefix(enum cs_log_level l, const char *func, const char *file) {
|
||||
char ll_str[6];
|
||||
|
||||
switch(l) {
|
||||
case LL_ERROR:
|
||||
strncpy(ll_str, "ERROR", sizeof(ll_str));
|
||||
break;
|
||||
case LL_WARN:
|
||||
strncpy(ll_str, "WARN", sizeof(ll_str));
|
||||
break;
|
||||
case LL_INFO:
|
||||
strncpy(ll_str, "INFO", sizeof(ll_str));
|
||||
break;
|
||||
case LL_DEBUG:
|
||||
strncpy(ll_str, "DEBUG", sizeof(ll_str));
|
||||
break;
|
||||
case LL_VERBOSE_DEBUG:
|
||||
strncpy(ll_str, "VERB", sizeof(ll_str));
|
||||
break;
|
||||
default: // LL_NONE
|
||||
return 0;
|
||||
}
|
||||
printf ("%-5s %-20s %-40s| ", ll_str, file, func);
|
||||
return 1;
|
||||
}
|
||||
|
||||
float mg_time() {
|
||||
struct timeval tod;
|
||||
float time;
|
||||
|
||||
gettimeofday(&tod, NULL);
|
||||
|
||||
time = tod.tv_sec;
|
||||
time += tod.tv_usec/1000000;
|
||||
|
||||
return time;
|
||||
}
|
Reference in New Issue
Block a user