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

HAMKit | Facebook Comments