Initial import
authorvolpol <volpol@packet-gain.de>
Sat, 18 Aug 2018 09:41:31 +0000 (11:41 +0200)
committervolpol <volpol@packet-gain.de>
Sat, 18 Aug 2018 09:41:31 +0000 (11:41 +0200)
13 files changed:
Makefile [new file with mode: 0644]
c_gpio.c [new file with mode: 0644]
c_gpio.h [new file with mode: 0644]
hx711.c [new file with mode: 0644]
hx711.h [new file with mode: 0644]
log.h [new file with mode: 0644]
main.c [new file with mode: 0644]
mgmt.c [new file with mode: 0644]
mgmt.h [new file with mode: 0644]
net.c [new file with mode: 0644]
net.h [new file with mode: 0644]
pump.c [new file with mode: 0644]
pump.h [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..a536f79
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,15 @@
+.PHONY: all clean
+
+CFLAGS=-Wall -std=gnu99 -m32
+LDFLAGS=-m32
+#CFLAGS+=-DDEBUG
+CFLAGS += -DHAVE_HX711
+
+
+all: bbd
+
+clean:
+       rm -f *.o bbd
+
+bbd: hx711.o c_gpio.o pump.o net.o main.o mgmt.o
+       $(CC) $(LDFLAGS) -o $@ -pthread $^
diff --git a/c_gpio.c b/c_gpio.c
new file mode 100644 (file)
index 0000000..3d3b00e
--- /dev/null
+++ b/c_gpio.c
@@ -0,0 +1,282 @@
+/*
+Copyright (c) 2012-2015 Ben Croston
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <string.h>
+#include "c_gpio.h"
+
+#define BCM2708_PERI_BASE_DEFAULT   0x20000000
+#define BCM2709_PERI_BASE_DEFAULT   0x3f000000
+#define GPIO_BASE_OFFSET            0x200000
+#define FSEL_OFFSET                 0   // 0x0000
+#define SET_OFFSET                  7   // 0x001c / 4
+#define CLR_OFFSET                  10  // 0x0028 / 4
+#define PINLEVEL_OFFSET             13  // 0x0034 / 4
+#define EVENT_DETECT_OFFSET         16  // 0x0040 / 4
+#define RISING_ED_OFFSET            19  // 0x004c / 4
+#define FALLING_ED_OFFSET           22  // 0x0058 / 4
+#define HIGH_DETECT_OFFSET          25  // 0x0064 / 4
+#define LOW_DETECT_OFFSET           28  // 0x0070 / 4
+#define PULLUPDN_OFFSET             37  // 0x0094 / 4
+#define PULLUPDNCLK_OFFSET          38  // 0x0098 / 4
+
+#define PAGE_SIZE  (4*1024)
+#define BLOCK_SIZE (4*1024)
+
+static volatile uint32_t *gpio_map;
+
+void short_wait(void)
+{
+    int i;
+
+    for (i=0; i<150; i++) {    // wait 150 cycles
+        asm volatile("nop");
+    }
+}
+
+int setup(void)
+{
+    int mem_fd;
+    uint8_t *gpio_mem;
+    uint32_t peri_base;
+    uint32_t gpio_base;
+    unsigned char buf[4];
+    FILE *fp;
+    char buffer[1024];
+    char hardware[1024];
+    int found = 0;
+
+    // try /dev/gpiomem first - this does not require root privs
+    if ((mem_fd = open("/dev/gpiomem", O_RDWR|O_SYNC)) > 0)
+    {
+        gpio_map = (uint32_t *)mmap(NULL, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, 0);
+        if ((uint32_t)gpio_map < 0) {
+            return SETUP_MMAP_FAIL;
+        } else {
+            return SETUP_OK;
+        }
+    }
+
+    // revert to /dev/mem method - requires root
+
+    // determine peri_base
+    if ((fp = fopen("/proc/device-tree/soc/ranges", "rb")) != NULL) {
+        // get peri base from device tree
+        fseek(fp, 4, SEEK_SET);
+        if (fread(buf, 1, sizeof buf, fp) == sizeof buf) {
+            peri_base = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0;
+        }
+        fclose(fp);
+    } else {
+        // guess peri base based on /proc/cpuinfo hardware field
+        if ((fp = fopen("/proc/cpuinfo", "r")) == NULL)
+            return SETUP_CPUINFO_FAIL;
+
+        while(!feof(fp) && !found) {
+            fgets(buffer, sizeof(buffer), fp);
+            sscanf(buffer, "Hardware   : %s", hardware);
+            if (strcmp(hardware, "BCM2708") == 0 || strcmp(hardware, "BCM2835") == 0) {
+                // pi 1 hardware
+                peri_base = BCM2708_PERI_BASE_DEFAULT;
+                found = 1;
+            } else if (strcmp(hardware, "BCM2709") == 0 || strcmp(hardware, "BCM2836") == 0) {
+                // pi 2 hardware
+                peri_base = BCM2709_PERI_BASE_DEFAULT;
+                found = 1;
+            }
+        }
+        fclose(fp);
+        if (!found)
+            return SETUP_NOT_RPI_FAIL;
+    }
+
+    gpio_base = peri_base + GPIO_BASE_OFFSET;
+
+    // mmap the GPIO memory registers
+    if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0)
+        return SETUP_DEVMEM_FAIL;
+
+    if ((gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL)
+        return SETUP_MALLOC_FAIL;
+
+    if ((uint32_t)gpio_mem % PAGE_SIZE)
+        gpio_mem += PAGE_SIZE - ((uint32_t)gpio_mem % PAGE_SIZE);
+
+    gpio_map = (uint32_t *)mmap( (void *)gpio_mem, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, mem_fd, gpio_base);
+
+    if ((uint32_t)gpio_map < 0)
+        return SETUP_MMAP_FAIL;
+
+    return SETUP_OK;
+}
+
+void clear_event_detect(int gpio)
+{
+    int offset = EVENT_DETECT_OFFSET + (gpio/32);
+    int shift = (gpio%32);
+
+    *(gpio_map+offset) |= (1 << shift);
+    short_wait();
+    *(gpio_map+offset) = 0;
+}
+
+int eventdetected(int gpio)
+{
+    int offset, value, bit;
+
+    offset = EVENT_DETECT_OFFSET + (gpio/32);
+    bit = (1 << (gpio%32));
+    value = *(gpio_map+offset) & bit;
+    if (value)
+        clear_event_detect(gpio);
+    return value;
+}
+
+void set_rising_event(int gpio, int enable)
+{
+    int offset = RISING_ED_OFFSET + (gpio/32);
+    int shift = (gpio%32);
+
+    if (enable)
+        *(gpio_map+offset) |= 1 << shift;
+    else
+        *(gpio_map+offset) &= ~(1 << shift);
+    clear_event_detect(gpio);
+}
+
+void set_falling_event(int gpio, int enable)
+{
+    int offset = FALLING_ED_OFFSET + (gpio/32);
+    int shift = (gpio%32);
+
+    if (enable) {
+        *(gpio_map+offset) |= (1 << shift);
+        *(gpio_map+offset) = (1 << shift);
+    } else {
+        *(gpio_map+offset) &= ~(1 << shift);
+    }
+    clear_event_detect(gpio);
+}
+
+void set_high_event(int gpio, int enable)
+{
+    int offset = HIGH_DETECT_OFFSET + (gpio/32);
+    int shift = (gpio%32);
+
+    if (enable)
+        *(gpio_map+offset) |= (1 << shift);
+    else
+        *(gpio_map+offset) &= ~(1 << shift);
+    clear_event_detect(gpio);
+}
+
+void set_low_event(int gpio, int enable)
+{
+    int offset = LOW_DETECT_OFFSET + (gpio/32);
+    int shift = (gpio%32);
+
+    if (enable)
+        *(gpio_map+offset) |= 1 << shift;
+    else
+        *(gpio_map+offset) &= ~(1 << shift);
+    clear_event_detect(gpio);
+}
+
+void set_pullupdn(int gpio, int pud)
+{
+    int clk_offset = PULLUPDNCLK_OFFSET + (gpio/32);
+    int shift = (gpio%32);
+
+    if (pud == PUD_DOWN)
+        *(gpio_map+PULLUPDN_OFFSET) = (*(gpio_map+PULLUPDN_OFFSET) & ~3) | PUD_DOWN;
+    else if (pud == PUD_UP)
+        *(gpio_map+PULLUPDN_OFFSET) = (*(gpio_map+PULLUPDN_OFFSET) & ~3) | PUD_UP;
+    else  // pud == PUD_OFF
+        *(gpio_map+PULLUPDN_OFFSET) &= ~3;
+
+    short_wait();
+    *(gpio_map+clk_offset) = 1 << shift;
+    short_wait();
+    *(gpio_map+PULLUPDN_OFFSET) &= ~3;
+    *(gpio_map+clk_offset) = 0;
+}
+
+void setup_gpio(int gpio, int direction, int pud)
+{
+    if ((uint32_t)gpio_map <= 0) return;
+
+    int offset = FSEL_OFFSET + (gpio/10);
+    int shift = (gpio%10)*3;
+
+    set_pullupdn(gpio, pud);
+    if (direction == OUTPUT)
+        *(gpio_map+offset) = (*(gpio_map+offset) & ~(7<<shift)) | (1<<shift);
+    else  // direction == INPUT
+        *(gpio_map+offset) = (*(gpio_map+offset) & ~(7<<shift));
+}
+
+// Contribution by Eric Ptak <trouch@trouch.com>
+int gpio_function(int gpio)
+{
+    int offset = FSEL_OFFSET + (gpio/10);
+    int shift = (gpio%10)*3;
+    int value = *(gpio_map+offset);
+    value >>= shift;
+    value &= 7;
+    return value; // 0=input, 1=output, 4=alt0
+}
+
+void output_gpio(int gpio, int value)
+{
+    int offset, shift;
+    if ((uint32_t)gpio_map <= 0) return;
+
+    if (value) // value == HIGH
+        offset = SET_OFFSET + (gpio/32);
+    else       // value == LOW
+       offset = CLR_OFFSET + (gpio/32);
+
+    shift = (gpio%32);
+
+    *(gpio_map+offset) = 1 << shift;
+}
+
+int input_gpio(int gpio)
+{
+   int offset, value, mask;
+   if ((uint32_t)gpio_map <= 0) return 0;
+
+   offset = PINLEVEL_OFFSET + (gpio/32);
+   mask = (1 << gpio%32);
+   value = *(gpio_map+offset) & mask;
+   return value;
+}
+
+void cleanup(void)
+{
+    if ((uint32_t)gpio_map <= 0) return;
+    munmap((void *)gpio_map, BLOCK_SIZE);
+}
diff --git a/c_gpio.h b/c_gpio.h
new file mode 100644 (file)
index 0000000..06cb4ea
--- /dev/null
+++ b/c_gpio.h
@@ -0,0 +1,51 @@
+/*
+Copyright (c) 2012-2015 Ben Croston
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+int setup(void);
+void setup_gpio(int gpio, int direction, int pud);
+int gpio_function(int gpio);
+void output_gpio(int gpio, int value);
+int input_gpio(int gpio);
+void set_rising_event(int gpio, int enable);
+void set_falling_event(int gpio, int enable);
+void set_high_event(int gpio, int enable);
+void set_low_event(int gpio, int enable);
+int eventdetected(int gpio);
+void cleanup(void);
+
+#define SETUP_OK           0
+#define SETUP_DEVMEM_FAIL  1
+#define SETUP_MALLOC_FAIL  2
+#define SETUP_MMAP_FAIL    3
+#define SETUP_CPUINFO_FAIL 4
+#define SETUP_NOT_RPI_FAIL 5
+
+#define INPUT  1 // is really 0 for control register!
+#define OUTPUT 0 // is really 1 for control register!
+#define ALT0   4
+
+#define HIGH 1
+#define LOW  0
+
+#define PUD_OFF  0
+#define PUD_DOWN 1
+#define PUD_UP   2
diff --git a/hx711.c b/hx711.c
new file mode 100644 (file)
index 0000000..cea20c6
--- /dev/null
+++ b/hx711.c
@@ -0,0 +1,194 @@
+#include <stdbool.h>
+#include <stdint.h>
+#include "hx711.h"
+
+#include <unistd.h>
+#include "c_gpio.h"
+
+
+void HX711_init(uint8_t gain)
+{
+    PD_SCK_SET_OUTPUT;
+    DOUT_SET_INPUT;
+
+    HX711_set_gain(gain);
+
+}
+
+bool HX711_isReady(void)
+{
+    return DOUT_READ == LOW;
+}
+
+void HX711_set_gain(uint8_t gain)
+{
+       switch (gain)
+       {
+               case 128:               // channel A, gain factor 128
+                       GAIN = 1;
+                       break;
+               case 64:                // channel A, gain factor 64
+                       GAIN = 3;
+                       break;
+               case 32:                // channel B, gain factor 32
+                       GAIN = 2;
+                       break;
+       }
+
+       PD_SCK_SET_LOW;
+       HX711_read();
+}
+
+int32_t HX711_read(void)
+{
+    // Will hold the 24-bit value
+    int32_t Count = 0;
+
+    // wait for the chip to become ready
+    while (!HX711_isReady());
+
+    for (uint8_t i=0; i<24; i++)
+    {
+        PD_SCK_SET_HIGH;
+        Count = Count << 1;
+        PD_SCK_SET_LOW;
+
+        if(DOUT_READ)
+        {
+            Count++;
+        }
+    }
+
+    // Set the gain for next time
+    for (uint8_t i = 0; i < GAIN; i++)
+    {
+        PD_SCK_SET_HIGH;
+        PD_SCK_SET_LOW;
+    }
+
+    // XOR the count
+    Count ^= 0x800000;
+
+    return(Count);
+}
+
+int32_t HX711_read_(void)
+{
+       // wait for the chip to become ready
+    while (!HX711_isReady());
+
+    uint32_t value = 0;
+    uint8_t data[3] = { 0 };
+    uint8_t filler = 0x00;
+
+       // pulse the clock pin 24 times to read the data
+    data[2] = shiftIn();
+    data[1] = shiftIn();
+    data[0] = shiftIn();
+
+       // set the channel and the gain factor for the next reading using the clock pin
+       for (uint8_t i = 0; i < GAIN; i++)
+       {
+               PD_SCK_SET_HIGH;
+               PD_SCK_SET_LOW;
+       }
+
+    // Datasheet indicates the value is returned as a two's complement value
+    // Flip all the bits
+    data[2] = ~data[2];
+    data[1] = ~data[1];
+    data[0] = ~data[0];
+
+    // Replicate the most significant bit to pad out a 32-bit signed integer
+    if ( data[2] & 0x80 )
+    {
+        filler = 0xFF;
+    } else if ((0x7F == data[2]) && (0xFF == data[1]) && (0xFF == data[0]))
+    {
+        filler = 0xFF;
+    } else
+    {
+        filler = 0x00;
+    }
+
+    // Construct a 32-bit signed integer
+    value = ( (uint32_t)(filler) << 24
+            | (uint32_t)(data[2]) << 16
+            | (uint32_t)(data[1]) << 8
+            | (uint32_t)(data[0]) );
+
+    // ... and add 1
+    return (int32_t)(++value);
+}
+
+int32_t HX711_read_average(uint8_t times)
+{
+       int32_t sum = 0;
+       for (uint8_t i = 0; i < times; i++)
+       {
+               sum += HX711_read();
+               // TODO: See if yield will work | yield();
+       }
+       return sum / times;
+}
+
+double HX711_get_value(uint8_t times)
+{
+       return HX711_read_average(times) - OFFSET;
+}
+
+float HX711_get_units(uint8_t times)
+{
+       return HX711_get_value(times) / SCALE;
+}
+
+void HX711_tare(uint8_t times)
+{
+       double sum = HX711_read_average(times);
+       HX711_set_offset(sum);
+}
+
+void HX711_set_scale(float scale)
+{
+       SCALE = scale;
+}
+
+float HX711_get_scale()
+{
+       return SCALE;
+}
+
+void HX711_set_offset(int32_t offset)
+{
+    OFFSET = offset;
+}
+
+int32_t HX711_get_offset()
+{
+       return OFFSET;
+}
+
+void HX711_power_down()
+{
+       PD_SCK_SET_LOW;
+       PD_SCK_SET_HIGH;
+       usleep(100);
+}
+
+void HX711_power_up()
+{
+       PD_SCK_SET_LOW;
+}
+
+uint8_t shiftIn(void)
+{
+    uint8_t value = 0;
+
+    for (uint8_t i = 0; i < 8; ++i)
+    {
+        PD_SCK_SET_HIGH;
+        value |= DOUT_READ << (7 - i);
+        PD_SCK_SET_LOW;
+    }
+    return value;
+}
diff --git a/hx711.h b/hx711.h
new file mode 100644 (file)
index 0000000..e702fb7
--- /dev/null
+++ b/hx711.h
@@ -0,0 +1,74 @@
+#ifndef HX711_h
+#define HX711_h
+
+    #define PD_SCK_PIN          6
+
+    #define PD_SCK_SET_OUTPUT   setup_gpio (PD_SCK_PIN, OUTPUT, PUD_OFF)
+    #define PD_SCK_SET_INPUT   setup_gpio (PD_SCK_PIN, INPUT, PUD_OFF)
+
+    #define PD_SCK_SET_HIGH     output_gpio(PD_SCK_PIN, HIGH)
+    #define PD_SCK_SET_LOW      output_gpio(PD_SCK_PIN, LOW)
+
+    #define DOUT_PIN            5
+    #define DOUT_READ           input_gpio(DOUT_PIN)
+
+    #define DOUT_SET_INPUT      setup_gpio (DOUT_PIN, INPUT, PUD_OFF)
+
+
+    uint8_t GAIN;                              // amplification factor
+    int32_t OFFSET;                    // used for tare weight
+    float SCALE;                           // used to return weight in grams, kg, ounces, whatever
+
+       // define clock and data pin, channel, and gain factor
+       // channel selection is made by passing the appropriate gain: 128 or 64 for channel A, 32 for channel B
+       // gain: 128 or 64 for channel A; channel B works with 32 gain factor only
+       void HX711_init(uint8_t gain);
+
+       // check if HX711 is ready
+       // from the datasheet: When output data is not ready for retrieval, digital output pin DOUT is high. Serial clock
+       // input PD_SCK should be low. When DOUT goes to low, it indicates data is ready for retrieval.
+       bool HX711_is_ready();
+
+       // set the gain factor; takes effect only after a call to read()
+       // channel A can be set for a 128 or 64 gain; channel B has a fixed 32 gain
+       // depending on the parameter, the channel is also set to either A or B
+       void HX711_set_gain(uint8_t gain);
+
+       // waits for the chip to be ready and returns a reading
+       int32_t HX711_read();
+
+       // returns an average reading; times = how many times to read
+       int32_t HX711_read_average(uint8_t times);
+
+       // returns (read_average() - OFFSET), that is the current value without the tare weight; times = how many readings to do
+       double HX711_get_value(uint8_t times);
+
+       // returns get_value() divided by SCALE, that is the raw value divided by a value obtained via calibration
+       // times = how many readings to do
+       float HX711_get_units(uint8_t times);
+
+       // set the OFFSET value for tare weight; times = how many times to read the tare value
+       void HX711_tare(uint8_t times);
+
+       // set the SCALE value; this value is used to convert the raw data to "human readable" data (measure units)
+       void HX711_set_scale(float scale);
+
+       // get the current SCALE
+       float HX711_get_scale();
+
+       // set OFFSET, the value that's subtracted from the actual reading (tare weight)
+       void HX711_set_offset(int32_t offset);
+
+       // get the current OFFSET
+       int32_t HX711_get_offset();
+
+       // puts the chip into power down mode
+       void HX711_power_down();
+
+       // wakes up the chip after power down mode
+       void HX711_power_up();
+
+    // Sends/receives data. Modified from Arduino source
+       uint8_t shiftIn(void);
+
+#endif /* HX711_h */
diff --git a/log.h b/log.h
new file mode 100644 (file)
index 0000000..9b27875
--- /dev/null
+++ b/log.h
@@ -0,0 +1,22 @@
+/*
+ * log.h
+ *
+ *  Created on: Jul 5, 2012
+ *      Author: volpol
+ */
+
+#ifndef LOG_H_
+#define LOG_H_
+
+#ifdef DEBUG
+       #define EPRINT(fmt, ...) do { fprintf( stderr, "%s:%s:%d:"fmt, __FILE__, __FUNCTION__, __LINE__ , ##__VA_ARGS__ ); } while (0)
+       #define DPRINT(...) EPRINT(__VA_ARGS__)
+       #define WHOAMI DPRINT("\n");
+#else
+       #define EPRINT(fmt, ...) do { fprintf( stderr, fmt, ##__VA_ARGS__ ); } while (0)
+       #define DPRINT(...)
+       #define WHOAMI 
+#endif
+
+
+#endif /* LOG_H_ */
diff --git a/main.c b/main.c
new file mode 100644 (file)
index 0000000..a126547
--- /dev/null
+++ b/main.c
@@ -0,0 +1,200 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <time.h>
+
+#include <errno.h>
+#include <poll.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <pthread.h>
+
+#include "c_gpio.h"
+#include "pump.h"
+#include "mgmt.h"
+#include "hx711.h"
+#include "net.h"
+#include "log.h"
+
+static volatile int force_quit;
+
+static void handle_signal(int sig){
+    fprintf (stderr, "SIGNAL: %d\n", sig);
+    switch (sig){
+    case SIGTERM:
+    case SIGINT:
+        force_quit = 1;
+        break;
+    }
+}
+
+//0 - ready, >0 - busy, -1 - err/unknown
+static volatile int mix_state;
+
+static void mix(const char *recipe){
+    int idx;
+    int vol;
+    const char *s;
+    char *n;
+    int sr;
+
+    s = recipe;
+
+    while (!force_quit && s && *s){
+        fprintf (stderr, "#%s#\n", s);
+        idx = strtoul(s, &n, 10);
+        s = n + 1;
+
+        fprintf (stderr, "#%s#\n", s);
+        vol = strtoul(s, &n, 10);
+        s = n + 1;
+
+        fprintf (stderr, "START PUMP: %d VOL %d\n", idx, vol);
+
+        if (0 != pump_add(idx)) break; //or continue?
+        mgmt_start(vol);
+        pump_on(idx);
+        while (!(sr = mgmt_stop()) && !force_quit) usleep(100);
+        pump_off(idx);
+        pump_del(idx);
+        fprintf (stderr, "STOP reason: %d/%d\n", sr, force_quit);
+        if (sr > MGMT_NORMAL_STOP) {
+            mix_state = -1;
+            break;
+        }
+    }
+    HX711_power_down();
+}
+
+static int receive(int fd, int timeout){
+struct pollfd pe;
+int res;
+pe.fd = fd;
+uint8_t buf[1024];
+int bread, total;
+
+total = 0;
+*buf = 0;
+do {
+    pe.events = POLLIN;
+    pe.revents = 0;
+    if( (0 < (res = poll (&pe, 1, timeout))) && pe.revents == POLLIN){
+        errno = 0;
+        bread = read(fd, buf + total, sizeof buf - total);
+        if (bread < 0)
+            switch (errno){
+                case EAGAIN:
+                //case EWOULDBLOCK:
+                case EINTR:
+                    break;
+
+                default:
+                    res = -1;
+                    break;
+        } else
+        if (0 == bread && 0 == errno) { res = -1; }
+        else {
+            total += bread;
+            if ('\n' == buf[total -  1]){
+                buf[total -  1] = 0;
+                fprintf (stderr, "%s\n", buf);
+                if (0 == strncmp((char *)buf, "MIX:", 4)) mix((char *)buf + 4);
+                if (0 == strncmp((char *)buf, "QUIT", 4)) res = -1;
+                *buf = 0;
+            }
+        }
+    }
+    timeout = 50;
+} while ((1 == res) && (pe.revents == POLLIN) && !force_quit);
+return res;
+}
+
+static pthread_t dealer;
+
+static void *deal( void *p ){
+    struct pollfd pas;
+    int err;
+
+    pas.fd = mix_state;
+    pas.events = POLLIN;
+    pas.revents = 0;
+
+    write (pas.fd, "READY\n", 6);
+
+    do {
+        err = receive (pas.fd, 1000);
+    } while (err >= 0 && !force_quit);
+
+    net_close( pas.fd );
+    //don't touch mix_state if it set to error by receive / mix
+    if (mix_state > 0)
+        mix_state  = 0;
+    return p;
+}
+
+int bbd(void){
+    int err = -1;
+    int ss, as;
+
+    ss = net_open_server( 0xbbd, "*" );
+       if ( ss < 0 )
+       {
+               EPRINT( "net_open_server failed!\n" );
+               goto DONE;
+       }
+    mgmt_init();
+    while (!force_quit){
+        if ((as = net_accept( ss )) > 0){
+            switch (mix_state){
+                case 0:
+                    pthread_join( dealer, NULL);
+                    dealer = 0;
+                    mix_state = as;
+                    err = pthread_create( &dealer, NULL, deal, NULL);
+                    if (0 != err)
+                        EPRINT( "pthread_create failed!\n" );
+                    else
+                        DPRINT ("PID: %lX\n", dealer);
+                    break;
+                case -1:
+                    write (as, "ERROR\n", 6);
+                    net_close (as);
+                    break;
+                default:
+                    write (as, "BUSY\n", 5);
+                    net_close (as);
+                    break;
+            }
+        }
+    }
+    pthread_join( dealer, NULL);
+    dealer = 0;
+    close(ss);
+DONE:
+    return err;
+}
+
+int main(void){
+    int err;
+
+    //install signal handlers
+    signal(SIGTERM, handle_signal);
+    signal(SIGINT,  handle_signal);
+
+    //initialize gpio susbsystem
+    if (SETUP_OK == (err = setup())){
+        err = bbd();
+        cleanup();
+    } else {
+        fprintf (stderr, "setup: %d\n", err);
+        if (SETUP_NOT_RPI_FAIL == err){
+            //limited on PC/non-PI but still
+            err = bbd();
+        }
+    }
+    fprintf (stderr, "bbd: %d\n", err);
+    return err;
+}
diff --git a/mgmt.c b/mgmt.c
new file mode 100644 (file)
index 0000000..9ea903c
--- /dev/null
+++ b/mgmt.c
@@ -0,0 +1,75 @@
+#include <time.h>
+#include <stdio.h>
+
+#ifdef HAVE_HX711
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "log.h"
+#include "mgmt.h"
+#include "hx711.h"
+
+#define MAX(x,y) (((x)>(y)) ? (x) : (y))
+#define MIN(x,y) (((x)<(y)) ? (x) : (y))
+static int stop_time;
+static double stop_weight;
+static double start_weight;
+
+static double curweight(void){
+    double w1, w2;
+
+    do {
+        w1 = HX711_get_units(3);
+        w2 = HX711_get_units(3);
+    } while (MAX(w1,w2) - MIN(w1,w2) > 0.5);
+
+    DPRINT ("w: %3.2f\n", w2);
+    return w2;
+}
+
+void mgmt_init(void){
+    HX711_init(128);
+    HX711_set_scale(412);
+    HX711_tare(30);
+    HX711_power_down();
+}
+
+int mgmt_start(int ml){
+    HX711_power_up();
+    HX711_tare(3);
+    stop_time = time(NULL) + 10;
+    start_weight = curweight();
+    stop_weight = start_weight + ml;
+    return 0;
+}
+
+int mgmt_stop(void){
+    int res = MGMT_CONTINUE;
+    double cw = curweight();
+    if (cw >= stop_weight) res = MGMT_NORMAL_STOP; else
+    if (time(NULL) >= stop_time && MAX(cw, start_weight) - MIN(cw, start_weight) < 5) res = MGMT_ABORT;
+    return res;
+}
+
+#else
+
+#define Q 1
+
+static int stop_cond;
+
+void mgmt_init(void){
+
+}
+
+int mgmt_start(int ml){
+    stop_cond = time(NULL) + ml * Q;
+    return 0;
+}
+
+int mgmt_stop(void){
+    return time(NULL) >= stop_cond;
+}
+
+#endif
+
+
diff --git a/mgmt.h b/mgmt.h
new file mode 100644 (file)
index 0000000..d4b6961
--- /dev/null
+++ b/mgmt.h
@@ -0,0 +1,14 @@
+#ifndef MGMT_H
+#define MGMT_H 1
+
+#define MGMT_CONTINUE 0
+#define MGMT_NORMAL_STOP 1
+#define MGMT_ABORT 2
+
+void mgmt_init(void);
+int mgmt_start(int ml);
+int mgmt_stop(void);
+
+#endif /* MGMT_H */
+
+
diff --git a/net.c b/net.c
new file mode 100644 (file)
index 0000000..701905b
--- /dev/null
+++ b/net.c
@@ -0,0 +1,155 @@
+/*
+ * net.c
+ *
+ *  Created on: Mar 8, 2013
+ *      Author: volpol
+ *  Modifed:
+ *             2013-05-31      support bind address, statics no more [uw]
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <poll.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include <unistd.h>
+
+#include "log.h"
+
+
+int net_open_client( const char *host, unsigned short port, const char *bind_addr )
+{
+       int sock = -1;
+       struct sockaddr_in server;
+       struct hostent *he = NULL;
+
+       //WHOAMI;
+       DPRINT( "%s:%d [%s]\n", host, port, bind_addr ? bind_addr : "*" );
+       if ( 0 > ( sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ) ) )
+               return perror( "socket()" ), -1;
+       server.sin_port = htons( port );
+       server.sin_family = AF_INET;
+       if ( NULL == ( he = gethostbyname( host ) ) )
+       {
+               herror( "gethostbyname()" );
+               goto ERROUT;
+       }
+       if ( NULL != bind_addr )
+       {
+               struct sockaddr_in lob;
+               lob.sin_family = AF_INET;
+               if ( 0 != strcmp( bind_addr, "*" ) )
+               {
+                       if ( 0 == strcmp( bind_addr, "localhost" ) )
+                               bind_addr = "127.0.0.1";
+                       lob.sin_family = AF_INET;
+                       if ( 0 == inet_aton( bind_addr, (struct in_addr *)&lob.sin_addr.s_addr ) )
+                       {
+                               fprintf( stderr, "inet_aton() failed\n" );
+                               goto ERROUT;
+                       }
+               }
+               else
+                       lob.sin_addr.s_addr = INADDR_ANY;
+               if ( 0 > bind( sock, (const struct sockaddr*)&lob, sizeof lob ) )
+               {
+                       perror( "bind()" );
+                       goto ERROUT;
+               }
+       }
+       server.sin_addr.s_addr = *((in_addr_t*)he->h_addr_list[0]);
+       if ( 0 != connect( sock, (struct sockaddr *)&server, sizeof server ) )
+       {
+               perror( "connect()" );
+               goto ERROUT;
+       }
+       return sock;
+ERROUT:
+       close( sock );
+       return -1;
+}
+
+int net_accept( int sock )
+{
+       WHOAMI;
+       int conn = -1;
+    struct pollfd pe;
+    int res;
+
+    pe.fd = sock;
+    pe.events = POLLIN;
+    pe.revents = 0;
+    if( (0 < (res = poll (&pe, 1, 100))) && pe.revents == POLLIN){
+        if ( 0 > ( conn = accept( sock, NULL, NULL ) ) )
+            perror( "accept()" );
+        else
+        {
+            DPRINT( "accepted conn: %d\n", conn );
+        }
+    } else {
+        return -1;
+    }
+       return conn;
+}
+
+void net_close( int conn )
+{
+       WHOAMI;
+       if ( 0 <= conn )
+       {
+               DPRINT( "shutting down conn: %d\n", conn );
+               shutdown( conn, SHUT_RDWR );
+               close( conn );
+       }
+}
+
+int net_open_server( unsigned short port, const char *bind_addr  )
+{
+       int sock;
+       int reuse = 1;
+       struct sockaddr_in lob;
+
+       //WHOAMI;
+       DPRINT( "%d [%s]\n", port, bind_addr ? bind_addr : "*" );
+       if ( 0 > ( sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ) ) )
+               return perror( "socket()" ), -1;
+       if ( 0 != setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof reuse ) )
+       {
+               perror( "setsockopt()" );
+               goto ERROUT;
+       }
+       lob.sin_family = AF_INET;
+       lob.sin_port = htons( port );
+       if ( NULL != bind_addr && 0 != strcmp( bind_addr, "*" ) )
+       {
+               if ( 0 == strcmp( bind_addr, "localhost" ) )
+                       bind_addr = "127.0.0.1";
+               lob.sin_family = AF_INET;
+               if ( 0 == inet_aton( bind_addr, (struct in_addr *)&lob.sin_addr.s_addr ) )
+               {
+                       fprintf( stderr, "inet_aton() failed\n" );
+                       goto ERROUT;
+               }
+       }
+       else
+               lob.sin_addr.s_addr = INADDR_ANY;
+       if ( 0 > bind( sock, (const struct sockaddr*)&lob, sizeof lob ) )
+       {
+               perror( "bind()" );
+               goto ERROUT;
+       }
+       if ( 0 > listen( sock, 0 ) )
+       {
+               perror( "listen()" );
+               goto ERROUT;
+       }
+       return sock;
+ERROUT:
+       close( sock );
+       return -1;
+}
diff --git a/net.h b/net.h
new file mode 100644 (file)
index 0000000..c299bf9
--- /dev/null
+++ b/net.h
@@ -0,0 +1,16 @@
+/*
+ * net.h
+ *
+ *  Created on: Mar 8, 2013
+ *      Author: volpol
+ */
+
+#ifndef NET_H_
+#define NET_H_
+
+int net_accept( int sock );
+int net_open_server( unsigned short port, const char *bind_addr );
+int net_open_client( const char *host, unsigned short port, const char *bind_addr );
+void net_close( int conn );
+
+#endif /* NET_H_ */
diff --git a/pump.c b/pump.c
new file mode 100644 (file)
index 0000000..2472383
--- /dev/null
+++ b/pump.c
@@ -0,0 +1,86 @@
+/*
+ * util.c
+ *
+ *  Created on: Aug 4, 2010
+ *      Author: volpol
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "log.h"
+
+#include "pump.h"
+#include "c_gpio.h"
+
+
+DPRINT ("pump_idx %d", num);
+DPRINT ("pump_gpio %d", gpio);
+#define NUM_PUMPS 12
+static int P2G[NUM_PUMPS] = {
+    17,
+    2,
+    0,
+
+    0,
+    0,
+    0,
+
+    0,
+    0,
+    0,
+
+    0,
+    0,
+    0
+};
+
+int pump_add(int num){
+    int res = -1;
+    DPRINT ("pump_idx %d", num);
+    if (num > 0 && num <= NUM_PUMPS){
+        int gpio = P2G[num];
+        DPRINT ("pump_gpio %d", gpio);
+        setup_gpio(gpio, OUTPUT, PUD_UP);
+        pump_off(num);
+        res = 0;
+    }
+    return res;
+}
+
+int pump_del(int num){
+    int res = -1;
+    DPRINT ("pump_idx %d", num);
+    if (num > 0 && num <= NUM_PUMPS){
+        int gpio = P2G[num];
+        DPRINT ("pump_gpio %d", gpio);
+        setup_gpio(gpio, INPUT, PUD_OFF);
+        res = 0;
+    }
+    return res;
+}
+
+void pump_on(int num){
+    DPRINT ("pump_idx %d", num);
+    if (num > 0 && num <= NUM_PUMPS){
+        int gpio = P2G[num];
+        DPRINT ("pump_gpio %d", gpio);
+        output_gpio(gpio, LOW);
+    }
+}
+
+void pump_off(int num){
+    DPRINT ("pump_idx %d", num);
+    if (num > 0 && num <= NUM_PUMPS){
+        int gpio = P2G[num];
+        DPRINT ("pump_gpio %d", gpio);
+        output_gpio(gpio, HIGH);
+    }
+}
+
+void pump_toggle(int num){
+        pump_on(num);
+        usleep(500000);
+        pump_off(num);
+}
diff --git a/pump.h b/pump.h
new file mode 100644 (file)
index 0000000..88d5906
--- /dev/null
+++ b/pump.h
@@ -0,0 +1,10 @@
+#ifndef PUMP_H
+#define PUMP_H 1
+
+int pump_add(int num);
+int pump_del(int num);
+void pump_toggle(int num);
+void pump_on(int num);
+void pump_off(int num);
+
+#endif /* PUMP_H */