/*
PROGRAM NAME	UMDnames.dll

USED BY			BBC Academy Studio C SD installation

Version	Date		Programmer				Comments
======= ==========	==========				========
1.0		23-07-2017	Andy Woodhouse			Initial Release

TARGET SCREEN SIZE	1024 x 768 or larger
PANEL SIZE			800 x 600	(Automatic panel)

Overview
========
The primary function of this automatic panel is to control the names displayed in the UMD fields on the
Studio C Kaleido-X monitors. Several name sets can be selected, including the names held in database 2 
of the SDI router ini file, 8 sets of User Editable names (to support "Cam1: Tim" style in place of 
"Camera 1" etc), a diagnostic name where the text contains the UMD address, and a name set that describes
the function of each connection to the multiviewer. The active name set is copied into the first 48 slots
(number of multiviewer inputs) of the Studio C TSL Driver. 

This automatic monitors 3 slots in the "Tally" infodriver that control the name set to use. It also monitors
revertives from the SDI router that correspond to inputs of the multiviewer.  It is a design requirement
for the multiviewer layouts that TSL protocol address 1 is associated with the SDI destination that feeds
multiviewer input 1 etc.

Various values are read from the BNCS /config/instances.xml file
"StC MV01 Camera 1" is the id for the first multiviewer input. This tells us the SDI Router ID and the destination index.


The slot usage in the UMD driver is:

Slot No.     Mode  Function            Comments
===========  ====  ========            ========
1 -  256     R/W   Text                
501 -  756   R/W   Cue, Brightness     Driver keeps these slots, the Cue slots,and the Brightness slots aligned
1001 - 1256  R/W   Cue                 0=Off  1=left cue on  2=right cue on  3=both cue on
1501 - 1756	 R/W   Brightness          0=Off  1=1/7th  2=1/2 (half)  3=full


*/

#include <windows.h>
#include <stdio.h>
#include <bncs_string.h>
#include <bncs_config.h>
#include "UMDnames.h"

#define MAIN_PNL	1
#define MAIN_PNL_NAME "UMD_mimic.bncs_ui"
#define	MV_SDI_DEST01	"StC MV01 Camera 1"
#define MV_INPUTS	48
#define TALLY_INFODRV	"CTA Tally Infodriver"
#define TALLY_NAME_MODE		210		// Slot number that holds ID address or Name mode flag
#define TALLY_BRIGHTNESS	211		// Slot number for the brightness of the UMD (ignored by Kaleido)
#define TALLY_NAMESET		212		// Slot number for current name set
#define TSL_NAME_OFFSET		0
#define TSL_CUE_OFFSET		1000
#define TSL_BRIGHT_OFFSET	1500

#define NAMES_DRIVER	"StC_UMD_Names_DriverID"
#define TSL_DRIVER		"StC TSL Driver"

#define TIMER_SETUP	1
#define TIMER_SETUP_PERIOD	1000

#define LOG_HEADER	"UMDnamesAuto: "

#define BNCS_MIN_DEV 1
#define BNCS_MAX_DEV 999

//////////////////////////////////////////////////
// Make our class visible to the outside world. //
//////////////////////////////////////////////////
EXPORT_BNCS_SCRIPT(UMDnames)


///////////////////////////////////////////////////
// Constructor - equivalent to ApplCore STARTUP. //
///////////////////////////////////////////////////
UMDnames::UMDnames(bncs_client_callback * parent, const char * path) : bncs_script_helper(parent, path)
{
	bool tallyFound;
	bool sdiFound;
	bool tslFound;
	bool namesFound;

	// Initialise module wide variables
	tallyInfo = 0;			// Driver ID for tally infodriver
	umdNameMode = 0;		// Holds value reported by Tally Infodriver slot 210
	umdBrightness = 0;		// Holds brightness index reported by Tally Infodriver slot 211. Ignored by the multiviewer.
	umdNameSetID = 0;		// Holds the current name set ID reported by Tally Infodriver slot 212.
	sdiDevID = 0;			// Driver ID for SDI router
	sdiMV_First = 0;		// First SDI destination used for multiviewer input
	sdiMV_Last = 0;			// Number of SDI destinations to multiviewer
	tslDriver = 0;			// Driver ID for TSL driver.
	namesDriver = 0;		// Driver ID for User Names storage

	failIniData = false;	// Flag to show if data initialisation fails
	tallyRevertReg = false;	// Tally Infodriver Revertives not yet registered
	sdiRevertReg = false;	// SDI revertives not yet registered
	namesRevertReg = false;	// user names driver not registered for revertives

	// Clear SDI router mimic data
	for (int idx = 0; idx <= ROUTERSIZEMAX; idx++)	sdiDests[idx] = 0;
	// Clear revertive count testing data arrays
	for (int idx = 0; idx <= ROUTERSIZEMAX; idx++)	sdiRevertFlags[idx] = false;
	for (int idx = 0; idx < 3; idx++)	tallyRevertFlags[idx] = false;

	// Initialise the name arrays to blank, including location zero which is unused
	for (int idx = 0; idx <= ROUTERSIZEMAX; idx++)
	{
		sdiNames[idx] = "";
		mv_func[idx] = "";
		user_1[idx] = "";
		user_2[idx] = "";
		user_3[idx] = "";
		user_4[idx] = "";
		user_5[idx] = "";
		user_6[idx] = "";
		user_7[idx] = "";
		user_8[idx] = "";
	}

	// Clear the array if user name sets
	for (int idx = 0; idx <= USERNAMESETS; idx++) userNames[idx] = "";

	// Show the mimic panel.
	panelShow(MAIN_PNL, MAIN_PNL_NAME);

	// Look up the ID of the Tally Infodriver
	tallyFound = getDev(TALLY_INFODRV, &tallyInfo);			// Read the Driver ID for the tally infodriver
	if (!tallyFound || (tallyInfo < BNCS_MIN_DEV) || (tallyInfo > BNCS_MAX_DEV))		// Check value returned ok and value of returned number
	{
		debug(bncs_string(LOG_HEADER) + bncs_string("Failed to read Tally InfoDriver ID or returned ID = 0\n"));
		textPut("text", "-1", MAIN_PNL, "TallyIDval");			// Show Bad Tally Infodriver ID on User Interface
		tallyInfo = -1;
		textPut("colour.background=#c00000", MAIN_PNL, "TallyID");		// Highlight failed data type
		failIniData = true;
	}
	textPut("text", tallyInfo, MAIN_PNL, "TallyIDval");			// Show Tally Infodriver ID on User Interface 

	// Look up the SDI driver ID that routes video to the mltiviewer
	sdiFound = getDev(MV_SDI_DEST01, &sdiDevID, &sdiMV_First);	// Read the BNCS Device ID and offset for first SDI connection to Multiviewer
	if (!sdiFound || (sdiDevID < BNCS_MIN_DEV) || (sdiDevID > BNCS_MAX_DEV) || (sdiMV_First <= 0))	// Check returned data
	{
		debug(bncs_string(LOG_HEADER) + bncs_string("Failed to read SDI ID, returned ID = 0, or first destination = 0\n"));
		debug(bncs_string(LOG_HEADER) + bncs_string("SDI device ID returned = %1, first destination returned = %2\n").arg(sdiDevID).arg(sdiMV_First));
		sdiDevID = -1;
		textPut("colour.background=#c00000", MAIN_PNL, "SDI_ID");		// Highlight failed data type
		sdiMV_First = 0;
		sdiMV_Last = 0;
		failIniData = true;
	}
	else
	{
		sdiMV_Last = sdiMV_First + MV_INPUTS - 1;
	}
	textPut("text", sdiDevID, MAIN_PNL, "sdiIDval");			// Show SDI device number on user interface

	// Look up the TSL driver ID where we send our active names
	tslFound = getDev(TSL_DRIVER, &tslDriver);
	if (!tslFound || (tslDriver < BNCS_MIN_DEV) || (tslDriver > BNCS_MAX_DEV))
	{
		debug(bncs_string(LOG_HEADER) + bncs_string("Failed to read TSL Driver ID, or returned ID outside valid range.\n"));
		debug(bncs_string(LOG_HEADER) + bncs_string("TSL device ID returned = %1\n").arg(tslDriver));
		tslDriver = -1;
		textPut("colour.background=#c00000", MAIN_PNL, "TSL_ID");		// Highlight failed data type
		failIniData = true;
	}
	textPut("text", tslDriver, MAIN_PNL, "TSLval");

	// Look up the BNCS dev_xxx.ini file that holds the user names sets
	namesFound = getDev(NAMES_DRIVER, &namesDriver);
	if (!namesFound || (namesDriver < BNCS_MIN_DEV) || (namesDriver > BNCS_MAX_DEV))
	{
		debug(bncs_string(LOG_HEADER) + bncs_string("Failed to read Names Driver ID, or returned ID outside valid range.\n"));
		debug(bncs_string(LOG_HEADER) + bncs_string("Names device ID returned = %1\n").arg(namesDriver));
		namesDriver = -1;
		textPut("colour.background=#c00000", MAIN_PNL, "Names_ID");		// Highlight failed data type
		failIniData = true;
	}
	textPut("text", namesDriver, MAIN_PNL, "NamesVal");

	// If any of the ID look ups failed, we should just stop work and not load more data.
	if (failIniData)
	{
		return;
	}

	// Load the names into our local string arrays
	for (int idx = 1; idx <= ROUTERSIZEMAX; idx++)
	{
		// Load SDI names from datadase 2
		routerName(sdiDevID, 2, idx, sdiNames[idx]);
	}

	// Load the names from the user storage into local string arrays
	for (int idx = 1; idx <= ROUTERSIZEMAX; idx++)
	{
		routerName(namesDriver, 1, idx, user_1[idx]);
		routerName(namesDriver, 2, idx, user_2[idx]);
		routerName(namesDriver, 3, idx, user_3[idx]);
		routerName(namesDriver, 4, idx, user_4[idx]);
		routerName(namesDriver, 5, idx, user_5[idx]);
		routerName(namesDriver, 6, idx, user_6[idx]);
		routerName(namesDriver, 7, idx, user_7[idx]);
		routerName(namesDriver, 8, idx, user_8[idx]);
	}

	// Load the multiviewer functional names from namesDriver database 0
	// Source index 1 to 48 hold the data. 
	for (int idx = 1; idx <= MV_INPUTS; idx++)
	{
		routerName(namesDriver, 0, idx, mv_func[idx]);
	}

	// Load the names of the eight user name sets from database 9 of the namesDriver
	for (int idx = 1; idx <= USERNAMESETS; idx++)
	{
		routerName(namesDriver, 9, idx, userNames[idx]);
	}

	// Register for revertives
	infoRegister(tallyInfo, TALLY_NAME_MODE, TALLY_NAMESET);	// Tally infodriver
	tallyRevertReg = true;										// Note that tally registration is active
	routerRegister(sdiDevID, sdiMV_First, sdiMV_Last);			// SDI Router, multiviewer destinations
	sdiRevertReg = true;										// Note that SDI registration is active
	routerRegister(namesDriver, 1, 1);							// Needed for database updates in user names
	namesRevertReg = true;

	initalPoll = true;											// Note we are about to start the poll process

	// Poll Tally Infodriver and router
	infoPoll(tallyInfo, TALLY_NAME_MODE, TALLY_NAMESET);		// Poll tally data
	routerPoll(sdiDevID, sdiMV_First, sdiMV_Last);				// Poll SDI router

	// Start timer that checks if all required data is loaded
	timerStart(TIMER_SETUP, TIMER_SETUP_PERIOD);				// Allow 1 second for initial acquisition of tally data	
}


////////////////////////////////////////////////////
// Destructor - equivalent to ApplCore CLOSEDOWN. //
////////////////////////////////////////////////////
UMDnames::~UMDnames()
{
	if (tallyRevertReg)
	{
		infoUnregister(tallyInfo);
		tallyRevertReg = false;
	}

	if (sdiRevertReg)
	{
		routerUnregister(sdiDevID);
		sdiRevertReg = false;
	}

	if (namesRevertReg)
	{
		routerUnregister(namesDriver);
		namesRevertReg = false;
	}
}



////////////////////////////////////////////////////
// All button pushes and notifications come here. //
////////////////////////////////////////////////////
void UMDnames::buttonCallback(buttonNotify *b)
{
	// There are no user buttons, only labels, on
	// the mimic panel. Hence just ignore any calls
	// to this function, logging them for future
	// analysis as may be required.

	bncs_string errLog = bncs_string(LOG_HEADER) + bncs_string("buttonCallback from Panel %1 button id %2\n").arg(b->panel()).arg(b->id());
	debug(errLog);

}


///////////////////////////////
// All revertives come here. //
///////////////////////////////
int UMDnames::revertiveCallback(revertiveNotify *r)
{
	// This module is interested in revertives from the serial router destinations 
	// associated with the multiviewer inputs, and the mode control data held by the
	// tally infodriver. SDI destination changes require updates be sent to the TSL
	// driver infodriver slots 1 to 48. 
	// Revertive registration is also active for the device ID that holds the user 
	// defined names and nameset names, although no revertive should ever be received
	// for this driver (it is not run as a driver, only the database facilities in the
	// .INI file are used). The registration is needed so that database changes for the
	// device invoke databaseCallback(revertiveNotify r*)

	if (r->device() == tallyInfo)
	{
		// See if revertive is for a slot of interest to this module
		if ((r->index() >= TALLY_NAME_MODE) && (r->index() <= TALLY_NAMESET))
		{
			// One of the slots relevant to this module.
			// Is this the initial revertive status acquisition, or are we in active mode?
			if (initalPoll)
			{
				tallyRevertFlags[r->index() - TALLY_NAME_MODE] = true;
				switch (r->index())
				{
					case TALLY_NAME_MODE:
						umdNameMode = r->sInfo().toInt();
						break;

					case TALLY_BRIGHTNESS:
						// Not really needed as Kaleido will ignore the value
						umdBrightness = r->sInfo().toInt();	
						break;

					case TALLY_NAMESET:
						umdNameSetID = r->sInfo().toInt();
						break;
				}
			}
			else
			{
				// Operating in run mode - so we have a possible update.
				int newVal = r->sInfo().toInt();	// Read the value returned ready to comare with current vaue
				switch (r->index())
				{
					case TALLY_NAME_MODE:
						if (umdNameMode != newVal)
						{
							umdNameMode = newVal;	// Store the new value
							mimicShowModes();		// Update mimic and names pointer
							updateAllNames();		// Call routine to show names
						}
						break;

					case TALLY_BRIGHTNESS:
						if (umdBrightness != newVal)
						{
							umdBrightness = newVal;	// Save updated brightness
							updateAllBrightness();	// Call function to set new brightness to UMD chain
						}
						break;

					case TALLY_NAMESET:
						if (umdNameSetID != newVal)
						{
							umdNameSetID = newVal;	// Save new names mode
							mimicShowModes();		// Update mimic and names pointer
							updateAllNames();		// Call routine to show names
						}
						break;
				}
			}	// End of the else clause
		}	//	End of if ((r->index() >= TALLY_NAME_MODE) && (r->index() <= TALLY_NAMESET))

		return 0;
	}	//	End of if (r->device == tallyInfo)

	// Check for revertives from SDI router
	if (r->device() == sdiDevID)
	{
		// Check the revertive is relevant to our module
		if ((r->index() >= sdiMV_First) && (r->index() <= sdiMV_Last))
		{
			// Actions depend on initial poll or active mode
			if (initalPoll)
			{
				sdiRevertFlags[r->index()] = true;	// Note the destination that has replied
				sdiDests[r->index()] = r->info();	// Note the source ID feeding that destination
			}
			else
			{
				// Normal processing
				int destination = r->index();	// Note destination
				int newSource = r->info();		// Get new source

				if (sdiDests[destination] != newSource)
				{
					sdiDests[destination] = newSource;		// Note the new setting
					setName(destination - sdiMV_First + 1);	// Send updates to mimimcs and TSL driver
				}
			}
		}
	}

	return 0;
}



///////////////////////////////////////////////
// All database name changes come back here. //
///////////////////////////////////////////////
void UMDnames::databaseCallback(revertiveNotify *r)
{
	// This module has to recognise any changes that happen in either the SDI router database 2
	// or any databases in the namesDriver. Whilst CSI will take care of the INI file, this module 
	// must update it's internal arrays of the strings, and send any "Live" updated selections to
	// both the local mimic and the UMD driver.

	if ((r->device() == sdiDevID) && (r->database() == 2))
	{
		// A change has happened in the database this module uses for matrix name display
		sdiNames[r->index()] = r->sInfo();		// Save the updated source name into the string array
		
		// Need to scan for this source in use if matrix names are on display.
		if ((umdNameMode == 0) && (umdNameSetID == 0))		// Check for matrix names on display
		{
			// Matrix names are used in the display, so scan through the multiviewer 
			// destinations and find any that are showing the updated source name.
			int srcID = r->index();

			for (int idx = sdiMV_First; idx <= sdiMV_Last; idx++)
			{
				if (sdiDests[idx] == srcID)
				{
					setName(idx - sdiMV_First + 1);	// Update the display for this MV index (1..48)
				}
			}
		}			// End of if ((umdNameMode == 0) && (umdNameSetID == 0))
		return;
	}				// End of if ((r->device() == sdiDevID) && (r->database() == 2))


	// Check for changes to namesDriver databases
	if ((r->device() == namesDriver) && (r->database() >= 0) && (r->database() <= 9))
	{
		// A change has been reported to one of the databases used in the namesDriver.
		// Need to update the memory copy of the string, and check if this is currently
		// active on a UMD display. If active the text must be updated. The processing of
		// database 0 and database 9 differ from the processing of databases 1 to 8.

		// Most probable change is to databases 1 to 8, so check for these first.
		if ((r->database() > 0) && (r->database() < 9))
		{
			// One of the user names databases has been modified.
			bncs_string *updatedSet;

			switch (r->database())
			{
				// Point updatedset at the start of the relevant array
				case 1: updatedSet = user_1; break;
				case 2: updatedSet = user_2; break;
				case 3: updatedSet = user_3; break;
				case 4: updatedSet = user_4; break;
				case 5: updatedSet = user_5; break;
				case 6: updatedSet = user_6; break;
				case 7: updatedSet = user_7; break;
				case 8: updatedSet = user_8; break;
			}
			updatedSet[r->index()] = r->sInfo();	// Update string in memory

			// Now check if the updated database is the active display set
			if ((umdNameMode == 0) && (umdNameSetID == r->database()))
			{
				// Modified database is in use. But is modified name on display?
				// Scan multiviewer destinations to see if updated source is routed
				int srcID = r->index();

				for (int idx = sdiMV_First; idx <= sdiMV_Last; idx++)
				{
					if (sdiDests[idx] == srcID)
					{
						setName(idx - sdiMV_First + 1);	// Update the display for this MV index (1..48)
					}
				}
			}
			return;
		}	// End of if ((r->database() > 0) && (r->database() < 9))

		// Database 9 (the names of the User name sets) is next most probable to change.
		if (r->database() == 9)
		{
			// Update the list of name sets
			if ((r->index() >= 1) && (r->index() <= 8))
			{
				userNames[r->index()] = r->sInfo();	// Save updated name
				if (r->index() == umdNameSetID)		// If this set is in use for UMDs
				{
					mimicShowModes();				// Show updated nameset name on the mimic
				}
			}
			return;
		}

		// Database 0 (multiviewer input functions) is least probable to change on a dynamic edit.
		if (r->database() == 0)
		{
			// Name of one of the multiviewer input functions has changed
			mv_func[r->index()] = r->sInfo();		// Save updated name

			if (umdNameSetID == 9)		// Check if function mode is the active one.
			{
				setName(r->index());	// Only one name needs updating
			}
			return;
		}
	
	}	// End of if ((r->device() == namesDriver) && (r->database() >= 0) && (r->database() <= 9))
}


////////////////////////////////////////////////////////////////////////////////
// All parent notifications come here. When this script is just one component //
// of another dialog then our host might want to tell us things.              //
////////////////////////////////////////////////////////////////////////////////
bncs_string UMDnames::parentCallback(parentNotify *p)
{
	if (p->command() == "return")
	{
		if (p->value() == "all")
		{	
			// Persisting values for bncs_vis_ed
			bncs_stringlist sl;
			sl << bncs_string("");
			return sl.toString('\n');
		}
	}

	// ***** CONNECTIONS EVENTS HELPER LIST *****
	else if( p->command() == "_events" )
	{	
		// Helper-list of everything in this component generated by hostNotify's
		bncs_stringlist sl;
		sl << "";		
		return sl.toString('\n');
	}

	// ***** CONNECTIONS COMMANDS HELPER LIST *****
	else if( p->command() == "_commands" )
	{	
		// Helper-list of any commands/parameters you might want to set at run-time
		bncs_stringlist sl;
		sl << "";
		return sl.toString( '\n' );
	}

	return "";
}


/////////////////////////////
// Timer events come here. //
/////////////////////////////
void UMDnames::timerCallback(int id)
{
	switch (id)
	{
		case TIMER_SETUP:
			// Inititial polling for values is allowed 1 second to complete. When this timer
			// ticks we check that the number of returned tally found flags is valid. If not valid
			// the polls are re-issed and the timer restarted, otherwise the  timer is stopped and
			// the initialPoll flag is cleared and operation of data output begins.
			tallyRevertCount = 0;
			sdiRevertCount = 0;
			for (int idx = 0; idx < 3; idx++)
			{
				// Count number of revertives from tally infodriver
				if (tallyRevertFlags[idx]) tallyRevertCount++;
			}
			for (int idx = sdiMV_First; idx <= sdiMV_Last; idx++)
			{
				// Count number of revertives from SDI driver
				if (sdiRevertFlags[idx])	sdiRevertCount++;
			}
			
			// If tallyRevertCount==3 and sdiRevertCount==48 all revertives received
			if ((tallyRevertCount == 3) && (sdiRevertCount == MV_INPUTS))
			{
				timerStop(TIMER_SETUP);
				initalPoll = false;
				mimicShowModes();	// Set up mimic info data and set pointer to relevant name set
				for (int index = 1; index <= MV_INPUTS; index++)
				{
					setName(index);
					setBright(index);
				}
			}
			else
			{
				// Re-issue the poll requests
				infoPoll(tallyInfo, TALLY_NAME_MODE, TALLY_NAMESET);		// Poll tally data
				routerPoll(sdiDevID, sdiMV_First, sdiMV_Last);				// Poll SDI router
			}
			break;

		default:	// Unhandled timer event
			timerStop(id);
			break;
	}
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////// Callbacks above - Methods below ///////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// function void UMDnames::mimicShowModes(void) is called when there is a requirement to update the nameset
// information shown at the top right of the mimic panel. The function also sets up the active nameset pointer
// "CurrentName".
void UMDnames::mimicShowModes(void)
{
	bncs_string nameMode;
	
	// Update the Name Mode ID mimic displays
	textPut("text", umdNameMode, MAIN_PNL, "NameModeID");
	switch (umdNameMode)
	{
		case 0:		nameMode = "Show Names";		break;
		case 1:		nameMode = "Show UMD Address";	break;
		default:	nameMode = "UNKNOWN";			break;
	}
	textPut("text", nameMode, MAIN_PNL, "NameModeName");

	// Update Names Set mimics
	textPut("text", umdNameSetID, MAIN_PNL, "NameSetId");	// Numeric mimic
	switch (umdNameSetID)
	{
		case 0:		nameMode = "SDI Matrix Names";	CurrentName = sdiNames; break;
		case 1:		nameMode = userNames[1];		CurrentName = user_1; break;
		case 2:		nameMode = userNames[2];		CurrentName = user_2; break;
		case 3:		nameMode = userNames[3];		CurrentName = user_3; break;
		case 4:		nameMode = userNames[4];		CurrentName = user_4; break;
		case 5:		nameMode = userNames[5];		CurrentName = user_5; break;
		case 6:		nameMode = userNames[6];		CurrentName = user_6; break;
		case 7:		nameMode = userNames[7];		CurrentName = user_7; break;
		case 8:		nameMode = userNames[8];		CurrentName = user_8; break;
		case 9:		nameMode = "MV Assignment";		CurrentName = mv_func; break;
		default:	nameMode = "UNKNOWN";			break;
	}
	textPut("text", nameMode, MAIN_PNL, "NameSetName");
}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// function void UMDnames::setName(const int mvIndex) is called to send the name for multiviwer input mvIndex
// to both the local mimic and the TSL UMD driver.
void UMDnames::setName(const int mvIndex)
{
	// The actions depend on the values stored in variables "umdNameMode" and "umdNameSetID". If umdNameMode
	// has the value 0, the standard set of names selected by umdNameSetID are used. If umdNameMode has the
	// value 1, a string containing the TSL UMD address is sent instead

	if (umdNameMode == 0)
	{
		
		if ((umdNameSetID >= 0) && (umdNameSetID <=8))
		{
			// Send a standard name based on currently routed SDI source
			bncs_string adr = CurrentName[sdiDests[sdiMV_First + mvIndex - 1]];
			textPut("text", adr, MAIN_PNL, bncs_string("Name_%1").arg(mvIndex, '0', 2U));
			infoWrite(tslDriver, adr, mvIndex);
			return;
		}

		// Pointer CurrentName (set in function mimicShowModes) is used to access the name
		if (umdNameSetID == 9)
		{
			// Send the multiviewer function allocation for this destination
			bncs_string adr = CurrentName[mvIndex];	
			textPut("text", adr, MAIN_PNL, bncs_string("Name_%1").arg(mvIndex, '0', 2U));
			infoWrite(tslDriver, adr, mvIndex);
			return;
		}
	}

	if (umdNameMode == 1)
	{
		// Send a string of the form "Address=012"
		bncs_string adr = bncs_string("Address=%1").arg(mvIndex, '0', 3U);			// Form the name
		textPut("text", adr, MAIN_PNL, bncs_string("Name_%1").arg(mvIndex,'0',2U));	// Send to the mimic display
		infoWrite(tslDriver, adr, mvIndex);
		return;
	}

}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// function void UMDnames::setBright(const int mvIndex) is called to send the UMD brightness value in global
// variable umdBrightness to the UMD whose index is provided as a parameter. No updates are needed for the 
// local mimic panel.
void UMDnames::setBright(const int mvIndex)
{
	if ((mvIndex >= 1) && (mvIndex <= MV_INPUTS))
	{
		infoWrite(tslDriver, umdBrightness, TSL_BRIGHT_OFFSET + mvIndex);
	}
}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// function void UMDnames::updateAllNames(void) is called to send all 48 names for multiviewer display
// to the local mimic panel and the UMD on the multiviewer.
void UMDnames::updateAllNames(void)
{
	for (int index = 1; index <= MV_INPUTS; index++)
	{
		setName(index);
	}
}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// function void UMDnames::updateAllBrightness(void) is called to send updated brightness to each multiviewer
// umd address. The Kaleido ignores this value, but just in case a future Kaleido-X software release adds more
// capability the function is here.
void UMDnames::updateAllBrightness(void)
{
	for (int index = 1; index <= MV_INPUTS; index++)
	{
		setBright(index);
	}
}