/* Raspberry Pi Sense HAT
UXLIBS: -lpthread -lm -lc
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#include "../../basext.h"
/***************************
Extension Module Functions
***************************/
typedef struct _ModuleObject {
void *HandleArray;
}ModuleObject,*pModuleObject;
besVERSION_NEGOTIATE
return (int)INTERFACE_VERSION;
besEND
besSUB_START
pModuleObject p;
besMODULEPOINTER = besALLOC(sizeof(ModuleObject));
if( besMODULEPOINTER == NULL )return 0;
p = (pModuleObject)besMODULEPOINTER;
return 0;
besEND
besSUB_FINISH
pModuleObject p;
p = (pModuleObject)besMODULEPOINTER;
if( p == NULL )return 0;
return 0;
besEND
/***************
GPIO Functions
***************/
static unsigned char LEDArray[192];
// I2C file handles
static int file_led = -1; // LED array
static int file_hum = -1; // humidity/temp sensor
static int file_pres = -1; // pressure sensor
static int file_acc = -1; // accelerometer/gyro
static int file_mag = -1; // magnetometer
static int i2cRead(int iHandle, unsigned char ucAddr, unsigned char *buf, int iLen);
static int i2cWrite(int iHandle, unsigned char ucAddr, unsigned char *buf, int iLen);
// humidity/temp calibration values
static int H0_rH_x2, H1_rH_x2, T0_degC_x8;
static int T1_degC_x8, H0_T0_OUT;
static int H1_T0_OUT, T0_OUT, T1_OUT;
static int i2cRead(int iHandle, unsigned char ucAddr, unsigned char *buf, int iLen)
{
int rc;
rc = write(iHandle, &ucAddr, 1);
if (rc == 1)
{
rc = read(iHandle, buf, iLen);
}
return rc;
} /* i2cRead() */
static int i2cWrite(int iHandle, unsigned char ucAddr, unsigned char *buf, int iLen)
{
unsigned char ucTemp[512];
int rc;
if (iLen > 511 || iLen < 1 || buf == NULL)
return -1; // invalid write
ucTemp[0] = ucAddr; // send the register number first
memcpy(&ucTemp
[1], buf
, iLen
); // followed by the data rc = write(iHandle, ucTemp, iLen+1);
return rc-1;
} /* i2cWrite() */
besFUNCTION(shInit)
int iChannel;
besARGUMENTS("i")
&iChannel
besARGEND
unsigned char ucTemp[32];
char filename[32];
sprintf(filename
, "/dev/i2c-%d", iChannel
); if ((file_led = open(filename, O_RDWR)) < 0)
{
// fprintf(stderr, "Failed to open the i2c bus; need to run as sudo?\n");
besRETURN_LONG(-1);
}
/* TODO
if (ioctl(file_led, I2C_SLAVE, 0x46) < 0)
{
fprintf(stderr, "Failed to acquire bus for LED matrix\n");
goto badexit;
}
*/
file_acc = open(filename, O_RDWR);
if (ioctl(file_acc, I2C_SLAVE, 0x6a) < 0)
{
fprintf(stderr
, "Failed to acquire bus for accelerometer\n"); goto badexit;
}
file_mag = open(filename, O_RDWR);
if (ioctl(file_mag, I2C_SLAVE, 0x1c) < 0)
{
fprintf(stderr
, "Failed to acquire bus for magnetometer\n"); goto badexit;
}
/* TODO
// Fill the LED with black
memset(LEDArray, 0, sizeof(LEDArray));
i2cWrite(file_led, 0, LEDArray, sizeof(LEDArray));
*/
file_hum = open(filename, O_RDWR);
if (ioctl(file_hum, I2C_SLAVE, 0x5f) < 0)
{
fprintf(stderr
, "Failed to acquire bus for Humidity sensor\n"); goto badexit;
}
file_pres = open(filename, O_RDWR);
if (ioctl(file_pres, I2C_SLAVE, 0x5C) < 0)
{
fprintf(stderr
, "Failed to aquire bus for Pressure sensor\n"); goto badexit;
}
// Prepare humidity sensor
i2cRead(file_hum, 0x10, ucTemp, 1); // AV_CONF
ucTemp[0] &= 0xc0;
ucTemp[0] |= 0x1b; // avgt=16, avgh=32
i2cWrite(file_hum, 0x10, ucTemp, 1);
i2cRead(file_hum, 0x20+0x80, ucTemp, 3); // get CTRL_REG 1-3
ucTemp[0] &= 0x78; // keep reserved bits
ucTemp[0] |= 0x81; // turn on + 1Hz sample rate
ucTemp[1] &= 0x7c; // turn off heater + boot + one shot
i2cWrite(file_hum, 0x20+0x80, ucTemp, 3); // turn on + set sample rate
// Get the H/T calibration values
i2cRead(file_hum, 0x30+0x80, ucTemp, 16);
H0_rH_x2 = ucTemp[0];
H1_rH_x2 = ucTemp[1];
T0_degC_x8 = ucTemp[2];
T1_degC_x8 = ucTemp[3];
T0_degC_x8 |= ((ucTemp[5] & 0x3) << 8); // 2 msb bits
T1_degC_x8 |= ((ucTemp[5] & 0xc) << 6);
H0_T0_OUT = ucTemp[6] | (ucTemp[7] << 8);
H1_T0_OUT = ucTemp[10] | (ucTemp[11] << 8);
T0_OUT = ucTemp[12] | (ucTemp[13] << 8);
T1_OUT = ucTemp[14] | (ucTemp[15] << 8);
if (H0_T0_OUT > 32767) H0_T0_OUT -= 65536; // signed
if (H1_T0_OUT > 32767) H1_T0_OUT -= 65536;
if (T0_OUT > 32767) T0_OUT -= 65536;
if (T1_OUT > 32767) T1_OUT -= 65536;
// prepare pressure sensor
ucTemp[0] = 0x90; // turn on and set 1Hz update
i2cWrite(file_pres, 0x20, ucTemp, 1);
// Init magnetometer
ucTemp[0] = 0x48; // output data rate/power mode
ucTemp[1] = 0x00; // default scale
ucTemp[2] = 0x00; // continuous conversion
ucTemp[3] = 0x08; // high performance mode
i2cWrite(file_mag, 0x20+0x80, ucTemp, 4);
// Init accelerometer/gyroscope
ucTemp[0] = 0x60; // 119hz accel
i2cWrite(file_acc, 0x20, ucTemp, 1);
ucTemp[0] = 0x38; // enable gyro on all axes
i2cWrite(file_acc, 0x1e, ucTemp, 1);
ucTemp[0] = 0x28; // data rate + full scale + bw selection
// bits: ODR_G2 | ODR_G1 | ODR_G0 | FS_G1 | FS_G0 | 0 | BW_G1 | BW_G0
// 0x28 = 14.9hz, 500dps
i2cWrite(file_acc, 0x10, ucTemp, 1); // gyro ctrl_reg1
besRETURN_LONG(1);
// problems opening the I2C handles/addresses
badexit:
/* TODO
if (file_led != -1)
{
close(file_led);
file_led = -1;
}
*/
if (file_hum != -1)
{
close(file_hum);
file_hum = -1;
}
if (file_pres != -1)
{
close(file_pres);
file_pres = -1;
}
if (file_acc != -1)
{
close(file_acc);
file_acc = -1;
}
if (file_mag != -1)
{
close(file_mag);
file_mag = -1;
}
besRETURN_LONG(0);
besEND
besFUNCTION(shGetAccel)
int *Ax, *Ay, *Az;
besARGUMENTS("iii")
&Ax, &Ay, &Az
besARGEND
unsigned char ucTemp[8];
int rc;
rc = i2cRead(file_acc, 0x28+0x80, ucTemp, 6);
if (rc == 6)
{
int x, y, z;
x = ucTemp[0] + (ucTemp[1] << 8);
y = ucTemp[2] + (ucTemp[3] << 8);
z = ucTemp[4] + (ucTemp[5] << 8);
// fix the signed values
if (x > 32767) x -= 65536;
if (y > 32767) y -= 65536;
if (z > 32767) z -= 65536;
*Ax = x; *Ay = y; *Az = z;
besRETURN_LONG(1);
}
besRETURN_LONG(0);
besEND
besFUNCTION(shGetGyro)
int *Gx, *Gy, *Gz;
besARGUMENTS("iii")
&Gx, &Gy, &Gz
besARGEND
unsigned char ucTemp[8];
int rc;
rc = i2cRead(file_acc, 0x18+0x80, ucTemp, 6);
if (rc == 6)
{
*Gx = ucTemp[0] + (ucTemp[1] << 8);
*Gy = ucTemp[2] + (ucTemp[3] << 8);
*Gz = ucTemp[4] + (ucTemp[5] << 8);
besRETURN_LONG(1);
}
besRETURN_LONG(0);
besEND
besFUNCTION(shGetMagneto)
int *Mx, *My, *Mz;
besARGUMENTS("iii")
&Mx, &My, &Mz
besARGEND
unsigned char ucTemp[8];
int rc;
rc = i2cRead(file_mag, 0x28+0x80, ucTemp, 6);
if (rc == 6)
{
int x, y, z;
x = ucTemp[0] + (ucTemp[1] << 8);
y = ucTemp[2] + (ucTemp[3] << 8);
z = ucTemp[4] + (ucTemp[5] << 8);
// fix signed values
if (x > 32767) x -= 65536;
if (y > 32767) y -= 65536;
if (z > 32767) z -= 65536;
*Mx = z; *My = y; *Mz = z;
besRETURN_LONG(1);
}
besRETURN_LONG(0);
besEND
besFUNCTION(shGetTempHumid)
int *Temp, *Humid;
besARGUMENTS("ii")
&Temp, &Humid
besARGEND
unsigned char ucTemp[4];
int rc;
int H_T_out, T_out, T0_degC, T1_degC;
int H0_rh, H1_rh;
int tmp;
rc = i2cRead(file_hum, 0x28+0x80, ucTemp, 4);
if (rc == 4)
{
H_T_out = ucTemp[0] + (ucTemp[1] << 8);
T_out = ucTemp[2] + (ucTemp[3] << 8);
if (H_T_out > 32767) H_T_out -=65536;
if (T_out > 32767) T_out -= 65536;
T0_degC = T0_degC_x8 / 8;
T1_degC = T1_degC_x8 / 8;
H0_rh = H0_rH_x2 / 2;
H1_rh = H1_rH_x2 / 2;
tmp = (H_T_out - H0_T0_OUT) * (H1_rh - H0_rh)*10;
*Humid = tmp / (H1_T0_OUT - H0_T0_OUT) + H0_rh*10;
tmp = (T_out - T0_OUT) * (T1_degC - T0_degC)*10;
*Temp = tmp / (T1_OUT - T0_OUT) + T0_degC*10;
besRETURN_LONG(1);
}
besRETURN_LONG(0); // not ready
besEND
besFUNCTION(shShutdown)
/* TODO Blank the LED array
memset(LEDArray, 0, sizeof(LEDArray));
i2cWrite(file_led, 0, LEDArray, 192);
*/
// Close all I2C file handles
// TODO if (file_led != -1) close(file_led);
if (file_hum != -1) close(file_hum);
if (file_pres != -1) close(file_pres);
if (file_acc != -1) close(file_acc);
if (file_mag != -1) close(file_mag);
file_led = file_hum = file_pres = file_acc = file_mag = -1;
besEND
besFUNCTION(shReadJoystick)
unsigned char ucBuf[2];
int rc;
if (file_led != -1)
{
rc = i2cRead(file_led, 0xf2, ucBuf, 1);
if (rc == 1)
besRETURN_STRING(ucBuf[0]);
}
besRETURN_LONG(0);
besEND