aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qmc5883.c361
-rw-r--r--src/qmc5883.h12
2 files changed, 373 insertions, 0 deletions
diff --git a/src/qmc5883.c b/src/qmc5883.c
new file mode 100644
index 0000000..7bcab37
--- /dev/null
+++ b/src/qmc5883.c
@@ -0,0 +1,361 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h> //#usleep
+#include <errno.h>
+#include <ctype.h> //# isdigit()
+
+
+#include "qmc5883.h"
+#include "deftypes.h"
+
+
+extern void bus_err(int ern);
+extern void print_help(void);
+extern uchar *xchg_data (uchar *buf, uint8 wrlen, uint8 waitlen, uint8 rdlen);
+
+unsigned char buf[32];
+
+
+void qmc5883_print_all(const uchar *opts)
+{
+ printf(
+ "00: Temperature data [°C] (reg: 0x00)\n"
+ "01: Configuration [hex] (reg: 0x01)\n"
+ "02: Tos (Overtemp) [°C] (reg: 0x03)\n"
+ "03: Thys (Hysteresis) [°C] (reg: 0x04)\n"
+ "\n");
+}
+
+void qmc5883_read_all(const uchar *opts) {}
+// void hmc5883_read_one(const uchar *opts) {}
+// void hmc5883_conf_set(const uchar *opts){}
+
+
+
+
+static float calc_field(char direction, float gain){ // Calculate temperature
+ uint16 raw = 0; //# Signed by default
+
+ // if(direction == 'x'){
+ // buf[0] = 0x03; //# Measurement in the REG[0]
+ // } else if (direction == 'y'){
+ // buf[0] = 0x07;
+ // } else if(direction == 'z'){
+ // buf[0] = 0x05;
+ // }
+
+ // buf[0] = 0x3d;
+ // buf[0] = 0x00;
+ // xchg_data(buf,1,0,3);
+
+// buf[0] = 0x3c;
+// for(int i=0; i<15; i++){
+// buf[i] = 0xFF;
+// }
+// xchg_data(buf,14,0,14);
+
+ // buf[0] = 0x01;
+ // xchg_data(buf,1,0,1);
+
+
+ buf[0] = 0x0A;
+ buf[1] = 0b10000000; //soft reset to all
+ xchg_data(buf,2,0,1);
+
+ buf[0] = 0x09;
+ buf[1] = 0x15;
+ buf[2] = 0x0A;
+ buf[3] = 0b00000000;
+ buf[4] = 0x1b;
+ buf[5] = 0x01;
+ xchg_data(buf,6,2,1);
+
+
+ buf[0] = 0x00;
+ xchg_data(buf,1,0,14);
+
+ // buf[0] = 0x3c;
+ // buf[1] = 0x01;
+ // buf[3] = 0xA0;
+ // xchg_data(buf,3,0,1);
+
+ // buf[0] = 0x3c;
+ // buf[1] = 0x02;
+ // buf[2] = 0x00;
+ // xchg_data(buf,3,0,1);
+
+ raw = buf[0] + buf[1]*256 ; //# /x*256 == x << 8/ (>> 5): Temp is 11bit data register
+
+// return(raw * 1.0);
+
+ if((raw & 0x8000) == 0x8000){ //# check if the msb(bit11) is 1 (1024 = 0x400), 2'complement negative number
+ raw = ~raw + 1; //# 2'complement data
+ //raw = raw & 0xFFFF; //# Only the lowest 11bit needed
+ return( -1 * raw * (1.0/3000.0));
+ } else {
+ return(raw *(1.0/3000.0)); //# 11bit -> 0.125°C or 9bit -> 0.5°C
+ }
+
+}
+
+
+static float read_tos(void){ // Over-Temperature Shutdown register
+ uint16 rawtemp = 0; //# Int16 default signed
+ buf[0] = 0x03; //# Tos = REG[2]
+ xchg_data(buf,1,0,2);
+
+ rawtemp = buf[0]*256 + buf[1]; // x*256 == x << 8
+ rawtemp = (rawtemp) >> 7; //# 9bit data
+
+ if((rawtemp & 0x100) == 0x100){ //# check MSB if it's a 2'complement number
+ rawtemp = ~rawtemp + 1 ; //# 2'complement, 2^9 = 512;
+ rawtemp = rawtemp & 0x1FF; //# lowest 9 bit
+ return (-1 * rawtemp * 0.5);
+ } else {
+ return (rawtemp * 0.5); //# 9bit -> 0.5 celsius
+ }
+}
+
+
+
+
+static uchar read_conf(void){ //Configuration register
+ buf[0] = 0x01;
+ xchg_data(buf,1,0,1);
+ return buf[0];
+}
+
+
+// void lm75_read_all(const uchar *opts){ // Print out whole device's data
+// // if(opts != NULL)
+// // {
+// // printf("00:%f\n", calc_temp(strtof(opts, NULL)));
+// // } else {
+// fprintf(stdout, "00:%f\n", calc_temp(0.0));
+// // }
+// fprintf(stdout, "01:0x%x\n", read_conf());
+// fprintf(stdout, "02:%f\n", read_thys());
+// fprintf(stdout, "03:%f\n", read_tos());
+
+// }
+
+
+void qmc5883_read_one(const uchar *opts){ // Prints the selected register's data
+ uint16 id,i;
+ uchar temp[256];
+
+ if(opts != NULL){ //# Search the comma: ...<01,-11.24>
+ for(i = 0; i < strlen((char*)opts); i++){
+
+ if (*(opts+i) == ','){
+ break;
+
+ } else {
+ if( !isdigit(*(opts+i)) ){ //# Check the register string
+ fprintf(stderr, "The Register address must be an integer!\n");
+ print_help();
+ qmc5883_print_all(NULL);
+ exit (EXIT_FAILURE);
+ }
+ temp[i] = *(opts+i); //# copy register string
+ temp[i+1] = '\0';
+ }
+ }
+
+ id = atoi((char*)temp); //# Convert register to number
+ strncpy((char*)temp, (char*)opts+i+1, 255); //# Copy remain to temp
+
+ switch (id) //# Which register is selected?
+ {
+ case 0x00:
+ // for(uint32 i=0; i<0xFFFFFFFF; i++){
+ fprintf(stdout, "%f\n", calc_field(*temp, 0.73)); //# with the offset
+ // usleep(100*1000);
+ // }
+ break;
+ case 0x01:
+ fprintf(stdout, "0x%x\n", read_conf());
+ break;
+ case 0x02:
+
+ break;
+ case 0x03:
+ fprintf(stdout, "%f\n", read_tos());
+ break;
+ default:
+ print_help();
+ }
+ }
+}
+
+
+
+void qmc5883_conf_set(const uchar *opts){ // Prints the selected register's data
+ uint16 i;
+ uchar temp[256];
+
+ if(opts != NULL){
+ for(i = 0; i < strlen((char*)opts); i++){
+ if (*(opts+i) == ','){ //# .... conf_set 0x49 thys,-10.5
+ break;
+ }
+ temp[i] = *(opts+i);
+ temp[i+1] = '\0';
+ }
+
+
+ if(!strcmp("tos", (char*)temp)){ //# Set the Tos register value
+ float inp;
+ uint16 temp;
+ buf[0] = 0x03;
+ inp = atof( (char*)(opts+i+1));
+
+ if(inp < 0){
+ temp = 0 - inp/0.5;
+ temp = ~temp +1; //# 2'complement
+ buf[1] = (temp >> 1) & 0xFF; //# (x << 7) and (x >> 8) ==> (x >> 1)
+ buf[2] = ((temp << 7) | 0x7F) & 0xFF; //# |d8,d7,d6,d5|d4,d3,d2,d1|d0,xx,xx,xx|xx,xx,xx,xx|
+ } else {
+ temp = inp/0.5;
+ buf[1] = (temp >> 1) & 0xFF; //# (x << 7) and (x >> 8) ==> (x >> 1)
+ buf[2] = (temp << 7) & 0xFF;;
+ }
+ xchg_data(buf,3,0,2);
+
+
+ }else if(!strcmp("thys", (char*)temp)){ //# Set the Thys reg
+ float inp;
+ uint16 temp;
+ buf[0] = 0x02;
+ inp = atof( (char*)(opts+i+1));
+
+ if(inp < 0){
+ temp = 0 - inp/0.5;
+ temp = ~temp +1; //# 2'complement
+ buf[1] = (temp >> 1) & 0xFF; //# (x << 7) and (x >> 8) ==> (x >> 1)
+ buf[2] = ((temp << 7) | 0x7F) & 0xFF; //# |d8,d7,d6,d5|d4,d3,d2,d1|d0,xx,xx,xx|xx,xx,xx,xx|
+ } else {
+ temp = inp/0.5;
+ buf[1] = (temp >> 1) & 0xFF; //# (x << 7) and (x >> 8) ==> (x >> 1)
+ buf[2] = (temp << 7) & 0xFF;;
+ }
+ xchg_data(buf,3,0,2);
+
+
+ }else if(!strcmp("conf", (char*)temp)){ //# Set whole conf register
+
+ buf[0] = 0x01;
+ buf[1] = strtol((char*)(opts+i+1),NULL,0);
+ xchg_data(buf,2,0,1);
+
+
+ }else if(!strcmp("sleep", (char*)temp)){ //# Send the sleep command
+
+ buf[0] = 0x01;
+ xchg_data(buf,1,0,1);
+ if (!strcmp("on",(char*)opts+i+1))
+ {
+ buf[1] = buf[0] | 0x01;
+ }
+ else if(!strcmp("off",(char*)opts+i+1))
+ {
+ // buf[1] = ~buf[0]; //# XOR = NEG->OR->NEG
+ // buf[1] = buf[1] | 0b00000001; //# Invert->add->invert
+ // buf[1] = ~buf[1];
+ buf[1] = buf[0] ^ 0b00000001; //# XOR to clear the bit
+ }
+ else
+ {
+ qmc5883_print_all(NULL);
+ exit(EXIT_FAILURE);
+ }
+ buf[0] = 0x01;
+ xchg_data(buf,2,0,1);
+
+
+ }else if(!strcmp("mode", (char*)temp)){ //# Comparator/Interrupt mode
+
+ buf[0] = 0x01;
+ xchg_data(buf,1,0,1);
+ if (!strcmp("comp",(char*)opts+i+1))
+ {
+ buf[1] = buf[0] ^ 0b00000010; //# XOR to clear
+ }
+ else if(!strcmp("int",(char*)opts+i+1))
+ {
+ buf[1] = buf[0] | 0b00000010;
+ }
+ else
+ {
+ qmc5883_print_all(NULL);
+ exit(EXIT_FAILURE);
+ }
+ buf[0] = 0x01;
+ xchg_data(buf,2,0,1);
+
+
+ }else if(!strcmp("tos_pol", (char*)temp)){ //# Tos polarity
+
+ buf[0] = 0x01;
+ xchg_data(buf,1,0,1);
+ if (!strcmp("Al",(char*)opts+i+1))
+ {
+ buf[1] = buf[0] ^ 0b00000100; //# XOR to clear the bit
+ }
+ else if(!strcmp("Ah",(char*)opts+i+1))
+ {
+ buf[1] = buf[0] | 0b00000100;
+ }
+ else
+ {
+ qmc5883_print_all(NULL);
+ exit(EXIT_FAILURE);
+ }
+ buf[0] = 0x01;
+ xchg_data(buf,2,0,1);
+
+
+ }else if(!strcmp("fault_q", (char*)temp)){ //# Tos Fault Queue
+
+ buf[0] = 0x01;
+ xchg_data(buf,1,0,1);
+ if (!strcmp("1",(char*)opts+i+1))
+ {
+ buf[1] = buf[0] | 0b00011000; //# Add and clear whole section
+ buf[1] = buf[1] ^ 0b00011000;
+ }
+ else if(!strcmp("2",(char*)opts+i+1))
+ {
+ buf[1] = buf[0] | 0b00011000; //# Clear first
+ buf[1] = buf[1] ^ 0b00011000; //# Clear first
+ buf[1] = buf[1] | 0b00001000; //# Set
+ }
+ else if(!strcmp("4",(char*)opts+i+1))
+ {
+ buf[1] = buf[0] | 0b00011000; //# Clear first
+ buf[1] = buf[1] ^ 0b00011000; //# Clear first
+ buf[1] = buf[1] | 0b00010000; //# Set
+ }
+ else
+ {
+ qmc5883_print_all(NULL);
+ exit(EXIT_FAILURE);
+ }
+ buf[0] = 0x01;
+ xchg_data(buf,2,0,1);
+
+
+ } else {
+ // for(i = 0; i < strlen((char*)opts); i++ ){
+ // if( !isxdigit(*(opts+i)) || *(opts+i) !='x' || opts[i] != ','){ //# Check the register string
+ // printf("The Register address, and value must be a hex, or an integer!\n");
+ print_help();
+ qmc5883_print_all(NULL);
+ exit (EXIT_FAILURE);
+ // }
+ // }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/qmc5883.h b/src/qmc5883.h
new file mode 100644
index 0000000..9d82b96
--- /dev/null
+++ b/src/qmc5883.h
@@ -0,0 +1,12 @@
+
+#ifndef _HMC5883_INCLUDED
+#define _HMC5883_INCLUDED
+
+#include "deftypes.h"
+
+void qmc5883_print_all(const uchar *opts);
+void qmc5883_read_all(const uchar *opts);
+void qmc5883_read_one(const uchar *opts);
+void qmc5883_conf_set(const uchar *opts);
+
+#endif \ No newline at end of file