From a7fc9b96516fc2b3ef3820de6c2a1710829a1f5f Mon Sep 17 00:00:00 2001 From: volpol Date: Sat, 18 Aug 2018 11:41:31 +0200 Subject: [PATCH 1/1] Initial import --- Makefile | 15 +++ c_gpio.c | 282 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ c_gpio.h | 51 ++++++++++ hx711.c | 194 ++++++++++++++++++++++++++++++++++++++ hx711.h | 74 +++++++++++++++ log.h | 22 +++++ main.c | 200 +++++++++++++++++++++++++++++++++++++++ mgmt.c | 75 +++++++++++++++ mgmt.h | 14 +++ net.c | 155 ++++++++++++++++++++++++++++++ net.h | 16 ++++ pump.c | 86 +++++++++++++++++ pump.h | 10 ++ 13 files changed, 1194 insertions(+) create mode 100644 Makefile create mode 100644 c_gpio.c create mode 100644 c_gpio.h create mode 100644 hx711.c create mode 100644 hx711.h create mode 100644 log.h create mode 100644 main.c create mode 100644 mgmt.c create mode 100644 mgmt.h create mode 100644 net.c create mode 100644 net.h create mode 100644 pump.c create mode 100644 pump.h diff --git a/Makefile b/Makefile new file mode 100644 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 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 +#include +#include +#include +#include +#include +#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< +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 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 index 0000000..cea20c6 --- /dev/null +++ b/hx711.c @@ -0,0 +1,194 @@ +#include +#include +#include "hx711.h" + +#include +#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 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 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 index 0000000..a126547 --- /dev/null +++ b/main.c @@ -0,0 +1,200 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#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 index 0000000..9ea903c --- /dev/null +++ b/mgmt.c @@ -0,0 +1,75 @@ +#include +#include + +#ifdef HAVE_HX711 +#include +#include + +#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 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 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 +#include + +#include +#include +#include +#include +#include +#include + +#include + +#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 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 index 0000000..2472383 --- /dev/null +++ b/pump.c @@ -0,0 +1,86 @@ +/* + * util.c + * + * Created on: Aug 4, 2010 + * Author: volpol + */ + +#include +#include +#include +#include +#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 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 */ -- 2.30.2