Wiki VMAC PiHat v2 Repeater Logic

HAMKit Wiki Repository
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages
Filter by Categories
 HAMKit Wiki
News and Information
RasDuinoHat
Raspberry Pi
Standard Page
VDAS
VMAC PiHat v1
VMAC PiHat v2

    VMAC PiHat V2 was originally designed as a ATV repeater controller and whilst it has seen other applications, the general overview as a controller is shown below.

    Typical application:

     

    Repeater example code will be developed in Python, but most of which is already available in the Wiki sections.

    The below is a very work in progress version of what I am using on GB3JT and testing various functions – however, it may help others so will keep it updated.  You can see the result at:  https://batc.org.uk/live/gb3jt

    # HAMKit VMAC PiHat v2.4 - ATV Repeater - Dave Williams
    # Hardware: PiHat v2.4, Pi3, EasyCap Video Capture
    # Initialise all GPIO inputs, outputs, I2C, SPI and UART
    # Reset, DTMF Decoder, Squelch Detect, Video Detect, Matrix, OSD, PTT
    # 23rd August 2018.  GB3JT TEST
    # Thanks also to Paul Theunissen, PA5PT, for OSD code template
    # GB3JT stream can be found at https://batc.org.uk/live/gb3jt
    #!/usr/bin/python
    
    #DRAFT!!! VERY WIP ==========================
    
    #========================== | Imports / Libraries | ==========================
    
    import RPi.GPIO as GPIO #GPIO
    import smbus #I2C
    import spidev #SPI
    #import serial #UART
    
    import time #Time
    import datetime #RTC
    from ctypes import *
    
    #========================== | Definitions | ==========================
    
    #====== GPIO
    GPIO.setmode(GPIO.BCM)
    GPIO.setwarnings(False)
    #GPIO.cleanup()
    
    #Define GPIO Outputs
    GPIO_OSD_RST = 25 # OSD Reset / Enable
    GPIO_PTT = 27 # Red LED = PTT & FET
    GPIO_Status = 22 # Blue LED = Status
    GPIO_User = 17 # Amber LED = User (also defined as RTS)
    
    #Setup Outputs
    GPIO.setup(GPIO_OSD_RST,GPIO.OUT)
    GPIO.setup(GPIO_PTT,GPIO.OUT)
    GPIO.setup(GPIO_Status,GPIO.OUT)
    GPIO.setup(GPIO_User,GPIO.OUT)
    
    #Define GPIO Inputs
    GPIO_Button = 4 # PCB User Button
    GPIO_D0 = 26 # DTMF D0 8870 Data Bit 0
    GPIO_D1 = 19 # DTMF D1 8870 Data Bit 1
    GPIO_D2 = 13 # DTMF D2 8870 Data Bit 2
    GPIO_D3 = 6 # DTMF D3 8870 Data Bit 3
    GPIO_DINT = 5 # DTMF DINT 8870 StD Latch Output
    GPIO_SQ1 = 12 # PCB I/O 1 User Input SQ1
    GPIO_SQ2 = 16 # PCB I/O 1 User Input SQ2
    GPIO_SQ3 = 20 # PCB I/O 1 User Input SQ3
    GPIO_SQ4 = 21 # PCB I/O 1 User Input SQ4
    GPIO_VD_1 = 18 # VideoDetect from Video Input RCA AV1
    GPIO_VD_2 = 23 # VideoDetect from Video Input RCA AV2
    GPIO_VD_3 = 24 # VideoDetect from Video Input RCA AV3
    
    #Setup Inputs with pull-ups enabled
    GPIO.setup(GPIO_Button, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.setup(GPIO_D0, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.setup(GPIO_D1, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.setup(GPIO_D2, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.setup(GPIO_D3, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.setup(GPIO_DINT, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.setup(GPIO_SQ1, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.setup(GPIO_SQ2, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.setup(GPIO_SQ3, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.setup(GPIO_SQ4, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.setup(GPIO_VD_1, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.setup(GPIO_VD_2, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.setup(GPIO_VD_3, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    
    
    #====== I2C Bus (FMS6501 / EEPROM)
    DEVICE_BUS = 1 # 0 = /dev/i2c-0 (port I2C0), 1 = /dev/i2c-1 (port I2C1)
    i2cbus = smbus.SMBus(DEVICE_BUS)
    
    DEVICE_ADD_Matrix = 0x43 #0x43 or 0x03 FMS6501 Matrix
    DEVICE_ADD_EEPROM = 0x50 #0x50 EEPROM
    
    
    #====== SPI bus (MAX7456)
    #spi = spidev.SpiDev() 
    
    
    #====== UART
    #"/dev/ttyAMA0"  # Raspberry Pi 2
    #"/dev/ttyS0"    # Raspberry Pi 3
    ##UARTSerial = serial.Serial(
    ##  port='/dev/ttyS0',
    ##  baudrate = 9600,
    ##  parity=serial.PARITY_NONE,
    ##  stopbits=serial.STOPBITS_ONE,
    ##  bytesize=serial.EIGHTBITS,
    ##  timeout=1
    ##)
    
    # sp = serial.Serial ("/dev/tty01")   
    # sp.baudrate = 9600                   
    # data = sp.read(10)      # 10 characters            
    # sp.write(data)          # echo all 10 characters back
    # sp.close()  
    
    
    #====== Define Program Variables
    DValueStore = 0
    PiHatAVin = {1:'V', 2:'V', 3:'V', 4:'A', 5:'A', 6:'A', 7:'A', 8:'A', 9:'V'}
    PiHatAVout = {1:'V', 2:'V', 3:'A', 4:'A'}
    dateString = '%H %M %S'
    
    #====== Define User Variables
    UserCallsign = "GB3JT"
    UserFreqTX = "1318 MHz"
    UserFreqRX = "1249 MHz"
    UserCTCSS = ""
    UserQRA = "JO00HV"
    UserNGR = "TQ825120"
    UserPostcode = "TN34 2AF"
    UserOverChar = "K"
    UserTX247 = True
    
    #Define DTMF Symbols
    DTMFLookup = ["1","2","3","4","5","6","7","8","9","0","*","#","A","B","C","D"]
    
    #Define Morse Symbols
    MorseLookup = {
        'A': '.-',
        'B': '-...',
        'C': '-.-.',
        'D': '-..',
        'E': '.',
        'F': '..-.',
        'G': '--.',
        'H': '....',
        'I': '..',
        'J': '.---',
        'K': '-.-',
        'L': '.-..',
        'M': '--',
        'N': '-.',
        'O': '---',
        'P': '.--.',
        'Q': '--.-',
        'R': '.-.',
        'S': '...',
        'T': '-',
        'U': '..-',
        'V': '...-',
        'W': '.--',
        'X': '-..-',
        'Y': '-.--',
        'Z': '--..',
    
        '1': '.----',
        '2': '..---',
        '3': '...--',
        '4': '....-',
        '5': '.....',
        '6': '-....',
        '7': '--...',
        '8': '---..',
        '9': '----.',
        '0': '-----',
    
        '!': '-.-.--',
        '"': '.-..-.',
        '$': '...-..-',
        '&': '.-...',
        '(': '-.--.',
        ')': '-.--.-',
        ',': '--..--',
        '.': '.-.-.-',
        '/': '-..-.',
        '-': '-....-',
        ':': '---...',
        ';': '-.-.-.',
        '?': '..--..',
        '@': '.--.-.',
        '\'': '.----.',
        '_': '..--.-',
        '+': '.-.-.',
        '=': '-...-'
    
    }
    
    #========================== | Initialise | ==========================
    
    #====== GPIO 
    GPIO.output(GPIO_OSD_RST,GPIO.HIGH) #Enable OSD Reset High
    
    #====== Serial UART 
    #UARTSerial.write("VMAC PiHat")
    
    #Initiate LEDs
    GPIO.output(GPIO_Status,GPIO.HIGH)
    GPIO.output(GPIO_User,GPIO.HIGH)
    GPIO.output(GPIO_PTT,GPIO.HIGH)
    time.sleep(1)
    GPIO.output(GPIO_Status,GPIO.LOW)
    GPIO.output(GPIO_User,GPIO.LOW)
    if UserTX247 == False:
        GPIO.output(GPIO_PTT,GPIO.LOW)
        
    time.sleep(1)
    
    #Read 8870 StD Latch Output
    DINT = GPIO.input(GPIO_DINT)
    
    #========================== | Routines | ==========================
    
    def PowerDownAllPorts():
        print ("PowerDownAllPorts")
        i2cbus.write_byte_data(DEVICE_ADD_Matrix, 0x01, 0x0) #Mute
        time.sleep(.01)
        i2cbus.write_byte_data(DEVICE_ADD_Matrix, 0x02, 0x0) #Mute
        time.sleep(.01)    
        i2cbus.write_byte_data(DEVICE_ADD_Matrix, 0x03, 0x0) #Mute
        time.sleep(.01)
        i2cbus.write_byte_data(DEVICE_ADD_Matrix, 0x04, 0x0) #Mute
        time.sleep(.01)
        i2cbus.write_byte_data(DEVICE_ADD_Matrix, 0x05, 0x0) #Mute
        time.sleep(.01)
        i2cbus.write_byte_data(DEVICE_ADD_Matrix, 0x06, 0x0) #Mute
        time.sleep(.01)
        i2cbus.write_byte_data(DEVICE_ADD_Matrix, 0x07, 0x0) #Mute
        time.sleep(.01)
        i2cbus.write_byte_data(DEVICE_ADD_Matrix, 0x08, 0x0) #Mute
        time.sleep(.01)	
        i2cbus.write_byte_data(DEVICE_ADD_Matrix, 0x09, 0x0) #Mute
        time.sleep(.01)                  
    
    def ReadDTMF():
        #Check for High Pulse from the 8870 StD Latch Output
        if DINT == True:
            
            #Only Check GPIO if 8870 Data Bits have changed 
            D0 = GPIO.input(GPIO_D0)
            D1 = GPIO.input(GPIO_D1)
            D2 = GPIO.input(GPIO_D2)
            D3 = GPIO.input(GPIO_D3)
            DValue = D0+(D1*2)+(D2*4)+(D3*8)
            
            #Only Display if DTMF Value has changed
            if DValueStore != DValue:
                DValueStore = DValue
            
                #Print Output
                print ("DTMF Value: %02d \tSymbol: " % (DValue) + DTMFLookup[DValue - 1])
                
                
    #========================== | Main | ==========================
    
    #Disable and Powerdown All Matrix Outputs
    PowerDownAllPorts()
    
    # Setup Matrix Video Switching
    #i2cbus.write_byte_data(DEVICE_ADD_Matrix, 0x1d, 0xff) #clamp
    #i2cbus.write_byte_data(DEVICE_ADD_Matrix, 0x1e, 0xff) #clamp
    #i2cbus.write_byte_data(DEVICE_ADD_Matrix, 0x07, 0x82) #Input 1 to OSD In
    i2cbus.write_byte_data(DEVICE_ADD_Matrix, 0x01, 0x86) #Input OSD to Output 1
    
    #OSD MAX7456
    class max7456():
        
        # Create SPI bus (MAX7456)
        spi = spidev.SpiDev() 
    
        # MAX7456 opcodes
        DMAH     = 0x05
        DMAL     = 0x06
        DMDI     = 0x07
        DMM_reg  = 0x04
        HOS_reg  = 0x02
        HOS_reg  = 0x02
        OSDM     = 0x0C
        RB0      = 0x10
        STATUS   = 0xA0
        VM0_reg  = 0x00
        VM1_reg  = 0x01
        VOS_reg  = 0x03
    
        # PAL - VM0_reg commands
        ENABLE_display      = 0x48
        ENABLE_display_vert = 0x4c
        MAX7456_reset       = 0x42
        DISABLE_display     = 0x40
    
        # Read command
        READ = 0x80
        MAX_screen_rows = 16
    
        # White levels
        WHITE_level_80  = 0x03
        WHITE_level_90  = 0x02
        WHITE_level_100 = 0x01
        WHITE_level_120 = 0x00
    
        chars = {' ':0, '1':1, '2':2, '3':3, '4':4, '5':5, '6':6, '7':7, '8':8, '9':9,
            '0':10, 'A':11, 'B':12, 'C':13, 'D':14, 'E':15, 'F':16, 'G':17, 'H':18, 'I':19,
            'J':20, 'K':21, 'L':22, 'M':23, 'N':24, 'O':25, 'P':26, 'Q':27, 'R':28, 'S':29,
            'T':30, 'U':31, 'V':32, 'W':33, 'X':34, 'Y':35, 'Z':36, 'a':37, 'b':38, 'c':39,
            'd':40, 'e':41, 'f':42, 'g':43, 'h':44, 'i':45, 'j':46, 'k':47, 'l':48, 'm':49,
            'n':50, 'o':51, 'p':52, 'q':53, 'r':54, 's':55, 't':56, 'u':57, 'v':58, 'x':59,
            'y':60, 'z':61, '(':62, ')':63, '.':64, '?':65, ';':66, ':':67, ',':68, '\'':69,
            '/':70, '"':71, '-':72, '<':73, '>':74, '@':75, '\xa9':76
        }
    
        def __init__(self):
            # Open a SPI port - max7456 connected on SPI0
            self.spi.open(0, 0)
            self.spi.max_speed_hz = 1000000
            self.spi.bits_per_word = 8
            self.spi.cshigh = False
            self.spi.lsbfirst = False
            self.spi.mode = 0
      
            # On init, reset max7456
            self.reset()
    
            # Set all rows at the same white level
            for x in range (0, self.MAX_screen_rows):
              self.spi.xfer2([(self.RB0 + x), self.WHITE_level_90])
    
            # Enable max7456
            self.spi.xfer2([self.VM0_reg, self.ENABLE_display]);
    
        def printStr(self, X, Y, string, enable = True):
            disp = []
            for char in string:
                     disp.append(self.chars[char])
    
            print (string)
    
            if enable == False:
                self.spi.xfer([self.VM0_reg, self.Disable_display])
            
            # Enable 8 bit mode:
            dmm = self.spi.xfer2([self.DMM_reg + self.READ, 0x00])
            dmm = self.setBit(dmm[1], 6)
            self.spi.xfer2([self.DMM_reg, dmm])
    
            start = X * 30 + Y
            
            # Clear position
            self.spi.xfer2([self.DMAH, 0x00])
            self.spi.xfer2([self.DMAL, 0x00])
    
            for char in disp:
                # Write char
                dmah = self.spi.xfer2([self.DMAH + self.READ, 0x00])
                dmah = self.clearBit(dmah[1], 1)
                self.spi.xfer2([self.DMAH, dmah])
    
                dmah_pos = ((start >> 8) & 0x01)
                dmal = (start & 0xff)
                dmah = dmah | dmah_pos
                start = start + 1
    
                # Select MSB
                self.spi.xfer2([self.DMAH, dmah])
                self.spi.xfer2([self.DMAL, dmal])
            
                self.spi.xfer2([self.DMDI, (char)])
    
        def reset(self):
            self.spi.xfer2([self.VM0_reg, self.MAX7456_reset])
            time.sleep(0.1)
            while True:
                r = self.spi.xfer([self.STATUS, 0x00])
                stable = self.testBit(r[1], 1)
                if stable == 0:
                    print ("Reset MAX7456 Ok...")
                    break 
                break
    
        def testBit(self, value, offset):
            mask = 1 << value
            return(value & mask)
     
        def setBit(self, value, offset):
            mask = 1 << offset
            return(value + mask)
    
        def clearBit(self, int_type, offset):
            mask = ~(1 << offset)
            return(int_type & mask)
        
    try:
        max7456 = max7456()
        
        #Display OSD Text
        max7456.printStr(2,10, "Hastings ATV", enable = True)
        #max7456.printStr(5,5, "OSD Test ABCDEFGHIJ", enable = True)
        #max7456.printStr(9,1, "1234567890123456789012345678", enable = True)
        max7456.printStr(13,3, "GB3JT VMAC PiHat Testing", enable = True)
        
    except KeyboardInterrupt:
        spi.close()
        
        
    i2cbus.write_byte_data(DEVICE_ADD_Matrix, 0x07, 0x85) #Input 3 to OSD In
    
    #========================== | LOOP | ==========================#
    
    #Loop
    while True:
        
        VideoDetect_1 = GPIO.input(GPIO_VD_1)
        VideoDetect_2 = GPIO.input(GPIO_VD_2)
        VideoDetect_3 = GPIO.input(GPIO_VD_3)
        
           
        if VideoDetect_1 == True:
            print ("VideoDetect_1 23cm FM Analogue")
            i2cbus.write_byte_data(DEVICE_ADD_Matrix, 0x07, 0x81) #Input 1 to OSD In
            i2cbus.write_byte_data(DEVICE_ADD_Matrix, 0x06, 0x87) #Input 4 to TX A 
            max7456.printStr(14,28, "1", enable = True)
            time.sleep(5)
            i2cbus.write_byte_data(DEVICE_ADD_Matrix, 0x06, 0x00) #Mute
        
        elif VideoDetect_2 == True:
            print ("VideoDetect_2 6cm FM Analogue")
            i2cbus.write_byte_data(DEVICE_ADD_Matrix, 0x07, 0x83) #Input 2 to OSD In
            i2cbus.write_byte_data(DEVICE_ADD_Matrix, 0x06, 0x88) #Input 5 to TX A 
            max7456.printStr(14,28, "2", enable = True)
            time.sleep(5)
            i2cbus.write_byte_data(DEVICE_ADD_Matrix, 0x06, 0x00) #Mute        
        
        elif VideoDetect_3 == False:
            print ("VideoDetect_3 23cm Digital")
            i2cbus.write_byte_data(DEVICE_ADD_Matrix, 0x07, 0x85) #Input 3 to OSD In
            i2cbus.write_byte_data(DEVICE_ADD_Matrix, 0x06, 0x89) #Input 6 to TX A 
            max7456.printStr(14,28, "3", enable = True)
            time.sleep(5)
            i2cbus.write_byte_data(DEVICE_ADD_Matrix, 0x06, 0x00) #Mute        
    
        else:
            i2cbus.write_byte_data(DEVICE_ADD_Matrix, 0x07, 0x85) #Input 2 to OSD In
            i2cbus.write_byte_data(DEVICE_ADD_Matrix, 0x06, 0x00) #Mute
            max7456.printStr(14,28, "0", enable = True)        
    
        
        #Heatbeat User LED
        GPIO.output(GPIO_User,GPIO.HIGH)
        time.sleep(.2)
        GPIO.output(GPIO_User,GPIO.LOW)
        time.sleep(1)
        max7456.printStr(14,1, datetime.datetime.now().strftime(dateString), enable = True)     
    
    
    

    Please feel free to share our product love through the below