/* Tool to control ZX76-31R5-SP-S+ digital attenuators on LTHW Main unit */ /* (C) 2016 by sysmocom s.f.m.c. GmbH * All Rights Reserved * * Author: Philipp Maier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include "gpio.h" /* GPIO pin assignment */ #define GPIO_LE_1 13 #define GPIO_LE_2 7 #define GPIO_LE_3 5 #define GPIO_LE_4 11 #define GPIO_DATA 15 #define GPIO_CLK 17 /* Internal GPIO alias */ #define LE_1 0 #define LE_2 1 #define LE_3 2 #define LE_4 3 #define DATA 4 #define CLK 5 /* ZX76-31R5-SP-S+ properties */ #define DB_MAX 31.5 /* Generate a clock or latch enable pulse */ static inline void gpio_pulse(struct gpio_descr *gd, unsigned int gpio) { gpio_set(gd, gpio, 1); gpio_set(gd, gpio, 0); } /* Write control word to Attenuator */ void att_write(struct gpio_descr *gd, uint8_t cw, unsigned int le) { int i; unsigned int bit; /* Write control word (val) to Attenuator */ for (i = 5; i >= 0; i--) { bit = ((cw >> i) & 1); gpio_set(gd, DATA, bit); gpio_pulse(gd, CLK); } /* Generate latch enable pulse */ gpio_pulse(gd, le); } /* Initalize attenuators */ struct gpio_descr *att_init(void) { unsigned int gpios[6]; struct gpio_descr *gd; /* GPIO pin mapping */ gpios[LE_1] = GPIO_LE_1; gpios[LE_2] = GPIO_LE_2; gpios[LE_3] = GPIO_LE_3; gpios[LE_4] = GPIO_LE_4; gpios[DATA] = GPIO_DATA; gpios[CLK] = GPIO_CLK; /* Open GPIO */ gd = gpio_open(NULL, gpios, 6); if (!gd) { printf("Error: Unable to open GPIO\n"); exit(1); } /* Initalize GPIOs to low level */ gpio_set(gd, LE_1, 0); gpio_set(gd, LE_2, 0); gpio_set(gd, LE_3, 0); gpio_set(gd, LE_4, 0); gpio_set(gd, DATA, 0); gpio_set(gd, CLK, 0); return gd; } /* Set attenuator value */ void att_set(struct gpio_descr *gd, double val, unsigned int le) { uint8_t cw; if (val > DB_MAX || val < 0) { printf("Error: Invalid attenuation value!\n"); return; } printf("Setting attenuator #%d to value %.1lf...\n", le + 1, val); cw = (uint8_t) (val * 2); att_write(gd, cw, le); } /* Print online help */ void print_help(char *progname) { printf("Usage: %s -i ID -a ATT\n", progname); printf("Attenuation (ATT) in 0.5db steps, range 0-31.5\n"); printf("\n"); exit(0); } int main(int argc, char *argv[]) { struct gpio_descr *gd; int option; double getopt_att = -1; int getopt_id = -1; /* Parse options */ while ((option = getopt(argc, argv, "hi:a:")) != -1) { switch (option) { case 'h': print_help(basename(argv[0])); break; case 'a': getopt_att = atof(optarg); break; case 'i': getopt_id = atoi(optarg) - 1; break; } } /* Check options */ if (getopt_att < 0) { printf("Error: No attenuation value specified!\n"); exit(1); } if (getopt_id < 0) { printf("Error: No attenuator id specified!\n"); exit(1); } if (getopt_id > 3) { printf("Error: Invalid attenuator id specified!\n"); exit(1); } /* Set attenuation */ gd = att_init(); att_set(gd, getopt_att, getopt_id); gpio_close(gd); return 0; }