Generic functions

-- General modules
require("Core")
 
-- Third-party libraries
-- https://github.com/silentbicycle/lua-memcached
local client = require("memcached")
local cache = client.connect()
 
function getCountryCode(number)
  -- Number should have not less than 3 digits
  if number >= 100
  then
    local value = tostring(number)
    return string.sub(value, 1, 3)
  end
  return nil
end
 
function getCountryAndRegionCode(number)
  -- Number should have not less than 4 digits
  if number >= 1000
  then
    local value = tostring(number)
    return string.sub(value, 1, 4)
  end
  return nil
end
 
function validateGeographicRegionCode(number, code)
  local value1 = tostring(code)
  local value2 = tostring(number)
  local length1 = string.len(value1)
  local length2 = string.len(value2)
  return
    (length1 <= length2) and
    (value1 == string.sub(value2, 1, length1))
end
 
function validateRegularRepeater(parameters)
  return
    -- Link has a repeater kind
    (parameters.kind == LINK_TYPE_REPEATER) and
    -- It is not DV4mini
    (parameters.name ~= "DG1HT DV4mini") and
    -- And not Homebrew Repeater in DMO mode
    ((parameters.name ~= "Homebrew Repeater") or
     (parameters.values[VALUE_HOMEBREW_CONNECTION_MODE] ~= CONNECTION_MODE_HOTSPOT))
end

Global TalkGroup routing

This function is used to route calls to other BrandMeisters

function makeGlobalRouteForGroup(kind, destination)
  if
    (destination ~= 9) and
    (kind ~= LINK_TYPE_NETWORK) and
    (validateGeographicRegionCode(destination, "8") or
     validateGeographicRegionCode(destination, "9") or
     getCountryCode(destination))
  then
    local contexts = getContextTable()
    for _, parameters in pairs(contexts) do
      if parameters.name == "FastForward"
      then
        newRoute(parameters.object, 0, 0)
      end
    end
  end
end

National TalkGroup routing

function makeAutomaticRouteForNationalGroup(kind, number, destination, slot)
  if destination >= 100
  then
    local country = getCountryCode(destination)
    local contexts = getContextTable()
    for _, parameters in pairs(contexts) do
      if
         -- Do not route call back
         ((kind ~= parameters.kind) or
          (number ~= parameters.number)) and
         -- Remote should be a repeater
         validateRegularRepeater(parameters) and
         -- Remote ID length is great than country code
         (parameters.number >= 100) and
         -- Destination ID and Remote ID should have same country code as prefix
         (getCountryCode(parameters.number) == country)
      then
        newRoute(parameters.object, slot, 0)
      end
    end
  end
end

Regional TalkGroup routing

function makeAutomaticRouteForRegionalGroup(kind, number, destination, slot)
  if destination >= 1000
  then
    local region = getCountryAndRegionCode(destination)
    local contexts = getContextTable()
    for _, parameters in pairs(contexts) do
      if
         -- Do not route call back
         ((kind ~= parameters.kind) or
          (number ~= parameters.number)) and
         -- Remote should be a repeater
         validateRegularRepeater(parameters) and
         -- Remote ID length is great than region code
         (parameters.number >= 1000) and
         -- Destination ID and Remote ID should have same region code as prefix
         (getCountryAndRegionCode(parameters.number) == region)
      then
        newRoute(parameters.object, slot, 0)
      end
    end
  end
end

OnDemand/Dynamic TalkGroup routing

A OnDemand TalkGroup is connected by pressing the PTT in the future also possable via RRS

function makeOnDemandRouteForGroup(kind, number, slot, destination, interval)
  -- Keep Group 9 as local
  if destination ~= 9
  then
    -- Subscribe repeater to group
    if kind == LINK_TYPE_REPEATER
    then
      cache:set(number .. "-" .. destination, tostring(slot), interval)
    end
    -- Route to subscribed group
    local contexts = getContextTable()
    for _, parameters in pairs(contexts) do
      if
         -- Do not route call back
         ((kind ~= parameters.kind) or
          (number ~= parameters.number)) and
         -- Remote should be a repeater
         (parameters.kind == LINK_TYPE_REPEATER)
      then
        local slot = cache:get(parameters.number .. "-" .. destination)
        if
           -- Subscription should be available
           (slot ~= nil)
        then
          newRoute(parameters.object, tonumber(slot), 0)
        end
      end
    end
  end
end

Dongle Reflector/TalkGroup routing

The function is used for mapping reflectors to TalkGroups

local state = 0;
 
function makeRouteForDV4mini(kind, name, number, destination, map)
  -- 1) Forward new Group calls to LoopBack
  if name ~= "LoopBack"
  then
    for reflector, group in pairs(map) do
      if destination == group
      then
        state = reflector
        newRoute(LINK_TYPE_APPLICATION, LOOPBACK, 0, 9)
        return REGISTRY_CONTINUE_APPENDING
      end
    end
  end
  -- 2) Forward calls from LoopBack to DV4mini connected to reflector
  if (destination == 9) and
     (name == "LoopBack")
  then
    local contexts = getContextTable()
    for _, parameters in pairs(contexts) do
      if (parameters.name == "DG1HT DV4mini") and
         (parameters.values[VALUE_REFLECTOR] == state)
      then
        newRoute(parameters.object, 0, 0)
      end
    end
    return REGISTRY_STOP_APPENDING
  end
  -- 3) Forward DV4mini calls of reflector to LoopBack
  if (destination == 9) and
     (name == "DG1HT DV4mini")
  then
    -- 3.1) Get current reflector of DV4mini
    local reflector = nil
    local contexts = getContextTable()
    for _, parameters in pairs(contexts) do
      if (parameters.number == number) and
         (parameters.name == "DG1HT DV4mini")
      then
        reflector = parameters.values[VALUE_REFLECTOR];
        break
      end
    end
    -- 3.2) Get group number from map
    local group = map[reflector]
    if group == nil
    then
      -- Group was not found, should be processed by TorsenHelper
      report("Mapped group not found for reflector DCS" .. reflector)
      return REGISTRY_CONTINUE_APPENDING
    end
    -- 3.3) Route call to other DVmini
    for _, parameters in pairs(contexts) do
      if (parameters.number ~= number) and
         (parameters.name == "DG1HT DV4mini") and
         (parameters.values[VALUE_REFLECTOR] == reflector)
      then
        newRoute(parameters.object, 0, 0)
      end
    end
    -- 3.4) Route call to LoopBack
    newRoute(LINK_TYPE_APPLICATION, LOOPBACK, 0, group)
    -- 3.5) Publish user event with reference to the reflector
    report("Processing call for mapped reflector DCS" .. reflector)
    publishEvent("reflector = " .. reflector)
    return REGISTRY_STOP_APPENDING
  end
  return REGISTRY_CONTINUE_APPENDING
end