From: volpol Date: Sat, 18 Aug 2018 09:41:31 +0000 (+0200) Subject: Initial import X-Git-Url: https://git.packet-gain.de/?a=commitdiff_plain;h=a7fc9b96516fc2b3ef3820de6c2a1710829a1f5f;p=bbd.git Initial import --- a7fc9b96516fc2b3ef3820de6c2a1710829a1f5f 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 */