/* -------------------------------------------------------------------------------------------------- */ /* The LongMynd receiver: ftdi.c */ /* - an implementation of the Serit NIM controlling software for the MiniTiouner Hardware */ /* - implements all the ftdi i2c accessing routines apart from the usb stuff */ /* Copyright 2019 Heather Lomond */ /* -------------------------------------------------------------------------------------------------- */ /* This file is part of longmynd. Longmynd 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 3 of the License, or (at your option) any later version. Longmynd 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 longmynd. If not, see . */ /* -------------------------------------------------------------------------------------------------- */ /* ----------------- INCLUDES ----------------------------------------------------------------------- */ /* -------------------------------------------------------------------------------------------------- */ #include #include #include #include #include "ftdi.h" #include "ftdi_usb.h" #include "nim.h" #include "errors.h" /* -------------------------------------------------------------------------------------------------- */ /* ----------------- DEFINES ------------------------------------------------------------------------ */ /* -------------------------------------------------------------------------------------------------- */ #define FTDI_VID 0x0403 #define FTDI_PID 0x6010 #define FTDI_NUM_TRIES 10 #define FTDI_STOP_START_REPEATS 4 #define FTDI_RDWR_TIMEOUT 100 #define MSB_FALLING_EDGE_CLOCK_BYTE_IN 0x24 #define MSB_FALLING_EDGE_CLOCK_BYTE_OUT 0x11 #define MSB_RISING_EDGE_CLOCK_BIT_IN 0x22 #define MSB_FAILING_EDGE_CLOCK_BIT_IN 0x26 /* FTDI GPIO Pins LSB - AC0: NIM Reset - AC1: TS2SYNC - AC2: - AC3: - AC4: LNB Bias Enable - AC5: - AC6: - AC7: LNB Bias Voltage Select MSB */ #define FTDI_GPIO_PINID_NIM_RESET 0 #define FTDI_GPIO_PINID_TS2SYNC 1 #define FTDI_GPIO_PINID_LNB_BIAS_ENABLE 4 #define FTDI_GPIO_PINID_LNB_BIAS_VSEL 7 /* -------------------------------------------------------------------------------------------------- */ /* ----------------- GLOBALS ------------------------------------------------------------------------ */ /* -------------------------------------------------------------------------------------------------- */ static int num_bytes_to_send = 0; static uint8_t out_buffer[256]; /* Default GPIO value 0x6f = 0b01101111 = LNB Bias Off, LNB Voltage 12V, NIM not reset */ static uint8_t ftdi_gpio_value = 0x6f; /* Default GPIO direction 0xf1 = 0b11110001 = LNB pins, NIM Reset are outputs, TS2SYNC is input (0 for in and 1 for out) */ static uint8_t ftdi_gpio_direction = 0xf1; /* -------------------------------------------------------------------------------------------------- */ /* ----------------- ROUTINES ----------------------------------------------------------------------- */ /* -------------------------------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------------------------------- */ uint8_t ftdi_setup_ftdi_io(void){ /* -------------------------------------------------------------------------------------------------- */ /* sets up the IO stages of the FTDI and syncs the comms */ /* return: error code */ /* -------------------------------------------------------------------------------------------------- */ uint8_t err=ERROR_NONE; uint8_t *in_buffer; uint8_t old_in_buffer=0; int i; int clock_divisor = 0x0095; printf("Flow: FTDI setup io\n"); /* note we don't accumulate errors for this bit as we are trying to sync */ /* first we send out a byte to act as our sync */ num_bytes_to_send = 0; out_buffer[num_bytes_to_send++] = 0xAA; if (err==ERROR_NONE) ftdi_usb_i2c_write(out_buffer, num_bytes_to_send); num_bytes_to_send = 0; /* next we keep reading it until we get it back, and the reply before it */ for (i=0; i> 8) & 0xFF; if (err==ERROR_NONE) err=ftdi_usb_i2c_write(out_buffer, num_bytes_to_send); num_bytes_to_send = 0; usleep(30000); out_buffer[num_bytes_to_send++] = 0x85; if (err==ERROR_NONE) err=ftdi_usb_i2c_write(out_buffer, num_bytes_to_send); num_bytes_to_send = 0; /* need to wait a while for it to work */ usleep(30000); if (err!=ERROR_NONE) printf("ERROR: set mpsse mode\n"); return err; } /* -------------------------------------------------------------------------------------------------- */ uint8_t ftdi_i2c_set_start(void) { /* -------------------------------------------------------------------------------------------------- */ /* sets the i2c start condition on the i2c bus */ /* return: error code */ /* -------------------------------------------------------------------------------------------------- */ int count; for (count=0; count>8); err|=ftdi_i2c_send_byte_check_ack(reg&0xff); if (err==ERROR_NONE) break; } if (err==ERROR_NONE) { /* Read back the contents of that register */ for(i=0; i>8); err|=ftdi_i2c_send_byte_check_ack(reg&0xff); err|=ftdi_i2c_send_byte_check_ack(val); err|=ftdi_i2c_set_stop(); err|=ftdi_i2c_output(); if (err==ERROR_NONE) break; } timeout++; } while ((err!=ERROR_NONE) && (timeout!=FTDI_RDWR_TIMEOUT)); if (err!=ERROR_NONE) printf("ERROR: i2c write reg16 0x%.2x, 0x%.4x, 0x%.2x\n",addr,reg, val); return err; } /* -------------------------------------------------------------------------------------------------- */ uint8_t ftdi_i2c_read_reg8(uint8_t addr, uint8_t reg, uint8_t *val) { /* -------------------------------------------------------------------------------------------------- */ /* read an i2c 8 bit register from the nim */ /* addr: the i2c bus address to access */ /* reg: the i2c register to read */ /* *val: the return value for the register we have read */ /* return: error code */ /* -------------------------------------------------------------------------------------------------- */ uint8_t err; int i; int timeout=0; do { for (i=0; i */ /* -------------------------------------------------------------------------------------------------- */ { printf("Flow: FTDI GPIO Write: pin %d -> value %d\n", pin_id, (int)pin_value); if(pin_value) { ftdi_gpio_value |= (1 << pin_id); } else { ftdi_gpio_value &= ~(1 << pin_id); } num_bytes_to_send = 0; out_buffer[num_bytes_to_send++] = 0x82; /* aka. MPSSE_CMD_SET_DATA_BITS_HIGHBYTE */ out_buffer[num_bytes_to_send++] = ftdi_gpio_value; out_buffer[num_bytes_to_send++] = ftdi_gpio_direction; ftdi_usb_i2c_write(out_buffer, num_bytes_to_send); num_bytes_to_send = 0; return ERROR_NONE; } /* -------------------------------------------------------------------------------------------------- */ uint8_t ftdi_nim_reset(void) /* -------------------------------------------------------------------------------------------------- */ /* toggle the reset line on the nim */ /* -------------------------------------------------------------------------------------------------- */ { printf("Flow: FTDI nim reset\n"); ftdi_gpio_write(FTDI_GPIO_PINID_NIM_RESET, 0); usleep(10000); ftdi_gpio_write(FTDI_GPIO_PINID_NIM_RESET, 1); usleep(10000); return ERROR_NONE; } /* -------------------------------------------------------------------------------------------------- */ uint8_t ftdi_set_polarisation_supply(bool supply_enable, bool supply_horizontal) /* -------------------------------------------------------------------------------------------------- */ /* Controls RT5047A LNB Power Supply IC, fitted to an additional board. */ /* -------------------------------------------------------------------------------------------------- */ { if(supply_enable) { /* Set Voltage */ if(supply_horizontal) { ftdi_gpio_write(FTDI_GPIO_PINID_LNB_BIAS_VSEL, 1); } else { ftdi_gpio_write(FTDI_GPIO_PINID_LNB_BIAS_VSEL, 0); } /* Then enable output */ ftdi_gpio_write(FTDI_GPIO_PINID_LNB_BIAS_ENABLE, 1); } else { /* Disable output */ ftdi_gpio_write(FTDI_GPIO_PINID_LNB_BIAS_ENABLE, 0); } return ERROR_NONE; } /* -------------------------------------------------------------------------------------------------- */ uint8_t ftdi_init(uint8_t usb_bus, uint8_t usb_addr) { /* -------------------------------------------------------------------------------------------------- */ /* initialises the ftdi module on the minitiouner */ /* -------------------------------------------------------------------------------------------------- */ uint8_t err; printf("Flow: FTDI init\n"); err=ftdi_usb_init_i2c(usb_bus, usb_addr, FTDI_VID, FTDI_PID); if (err==ERROR_NONE) err=ftdi_usb_set_mpsse_mode_i2c(); if (err==ERROR_NONE) err=ftdi_usb_init_ts(usb_bus, usb_addr, FTDI_VID, FTDI_PID); if (err==ERROR_NONE) err=ftdi_usb_set_mpsse_mode_ts(); if (err==ERROR_NONE) err=ftdi_setup_ftdi_io(); if (err==ERROR_NONE) err=ftdi_nim_reset(); if (err!=ERROR_NONE) printf("ERROR: FTDI init\n"); return err; }