package ptzcamera;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;

import anywheresoftware.b4a.BA;

@BA.ShortName("ViscaOverIP")
@BA.Events(values= {
		"log(msg as string)",
		"camerapower(success as boolean, id as int, value as boolean)",
		"whitebalancemode(success as boolean, id as int, value as string)",
		"rgain(success as boolean, id as int, value as int)",
		"bgain(success as boolean, id as int, value as int)",
		"aemode(success as boolean, id as int, value as string)",
		"shutterposition(success as boolean, id as int, value as int)",
		"irisposition(success as boolean, id as int, value as int)",
		"gainposition(success as boolean, id as int, value as int)",
		"brightposition(success as boolean, id as int, value as int)",
		"expcompposition(success as boolean, id as int, value as int)",
		"focusmode(success as boolean, id as int, value as string)",
		"focusposition(success as boolean, id as int, value as int)",
		"zoomposition(success as boolean, id as int, value as int)",
		"pantiltposition(success as boolean, id as int, panvalue as int, tiltvalue as int)",
		"preset(success as boolean, id as int, value as int)",
		"trackingstatus(success as boolean, id as int, value as boolean)",
		"trackingmode(success as boolean, id as int, value as string)",
		"trackingbodysize(success as boolean, id as int, value as string)",
		"osdmenu(success as boolean, id as int, value as boolean)",
		"tally(success as boolean, id as int, value as boolean)",
		"wdrmode(success as boolean, id as int, value as boolean)",
		"blcmode(success as boolean, id as int, value as boolean)",
		"livefreeze(success as boolean, id as int, value as boolean)",
		"presetfreeze(success as boolean, id as int, value as boolean)",
		"firmwareversion(success as boolean, id as int, value as string)",
		"usbpluggedstatus(success as boolean, id as int, value as boolean)",
		"uvcstatus(success as boolean, id as int, value as boolean)"
		
})
public class ViscaOverIP {
	private BA ba;
	private String event;
	private Object Me = this;
	
	private DatagramSocket myport;
	
	// event
	private boolean need_log_event = false;
	private boolean need_camerapower_event = false;
	private boolean need_whitebalancemode_event = false;
	private boolean need_rgain_event = false;
	private boolean need_bgain_event = false;
	private boolean need_aemode_event = false;
	private boolean need_shutterposition_event = false;
	private boolean need_irisposition_event = false;
	private boolean need_gainposition_event = false;
	private boolean need_brightposition_event = false;
	private boolean need_expcompposition_event = false;
	private boolean need_focusmode_event = false;
	private boolean need_focusposition_event = false;
	private boolean need_zoomposition_event = false;
	private boolean need_pantiltposition_event = false;
	private boolean need_preset_event = false;
	private boolean need_trackingstatus_event = false;
	private boolean need_trackingmode_event = false;
	private boolean need_trackingbodysize_event = false;
	private boolean need_osdmenu_event = false;
	private boolean need_tally_event = false;
	private boolean need_wdrmode_event = false;
	private boolean need_blcmode_event = false;
	private boolean need_livefreeze_event = false;
	private boolean need_presetfreeze_event = false;
	private boolean need_firmwareversion_event = false;
	private boolean need_usbpluggedstatus_event = false;
	private boolean need_uvcstatus_event = false;
	
	// timeout in miliseconds
	private final int read_timeout = 10;
	
	// sequence number
	private Integer sequence_number = 0;
	
	private final int udp_port = 52381;
	
	private final Map<Integer, InetSocketAddress> map = new HashMap<Integer, InetSocketAddress>();
	
	/**
	 * Initialize Visca PTZ Controller
	 * @param eventname eventname
	 */
	public void Initialize(BA bax, String eventname) {
		this.ba = bax;
		this.event = eventname;
		if (ba!=null) {
			if (event!=null) {
				if (event.isEmpty()==false) {
					need_log_event = ba.subExists(event+"_log");
					need_camerapower_event = ba.subExists(event+"_camerapower");
					need_whitebalancemode_event = ba.subExists(event+"_whitebalancemode");
					need_rgain_event = ba.subExists(event+"_rgain");
					need_bgain_event = ba.subExists(event+"_bgain");
					need_aemode_event = ba.subExists(event+"_aemode");
					need_shutterposition_event = ba.subExists(event+"_shutterposition");
					need_irisposition_event = ba.subExists(event+"_irisposition");
					need_gainposition_event = ba.subExists(event+"_gainposition");
					need_brightposition_event = ba.subExists(event+"_brightposition");
					need_expcompposition_event = ba.subExists(event+"_expcompposition");
					need_focusmode_event = ba.subExists(event+"_focusmode");
					need_focusposition_event = ba.subExists(event+"_focusposition");
					need_zoomposition_event = ba.subExists(event+"_zoomposition");
					need_pantiltposition_event = ba.subExists(event+"_pantiltposition");
					need_preset_event = ba.subExists(event+"_preset");
					need_trackingstatus_event = ba.subExists(event+"_trackingstatus");
					need_trackingmode_event = ba.subExists(event+"_trackingmode");
					need_trackingbodysize_event = ba.subExists(event+"_trackingbodysize");
					need_osdmenu_event = ba.subExists(event+"_osdmenu");
					need_tally_event = ba.subExists(event+"_tally");
					need_wdrmode_event = ba.subExists(event+"_wdrmode");
					need_blcmode_event = ba.subExists(event+"_blcmode");
					need_livefreeze_event = ba.subExists(event+"_livefreeze");
					need_presetfreeze_event = ba.subExists(event+"_presetfreeze");
					need_firmwareversion_event = ba.subExists(event+"_firmwareversion");
					need_usbpluggedstatus_event = ba.subExists(event+"_usbpluggedstatus");
					need_uvcstatus_event = ba.subExists(event+"_uvcstatus");
				}
			}
		}
	}
	
	/**
	 * Open UDP Port to communicate 
	 * Will open at port 52381
	 * @return true if can be opened
	 */
	public boolean OpenPort() {
		try {
			myport = new DatagramSocket(udp_port);
			myport.setSoTimeout(read_timeout);
			return true;
		} catch (SocketException e) {
			raise_log("Unable to create UDP Socket at 52381, Exception="+e.getMessage());
		}
		return false;
	}
	
	
	
	/**
	 * Close SerialPort
	 */
	public void ClosePort() {
		if (myport!=null) {
			myport.close();
			
			myport = null;
		}
		
	}
	
	/**
	 * Register ID and IP address for IP Camera
	 * @param ID value 1 - 7
	 * @param ipaddress valid IP address
	 * @param UdpPort valid UDP Port
	 * @return true if success
	 */
	public boolean Register_Device(int ID, String ipaddress, int UdpPort) {
		try {
			InetAddress ip = InetAddress.getByName(ipaddress);
			InetSocketAddress sa = new InetSocketAddress(ip, UdpPort);
			InetSocketAddress prev = map.put(ID, sa);
			if (prev!=null) {
				raise_log("ID="+ID+" replacing "+SocketAddressToString(prev)+" with "+SocketAddressToString(sa));
			} else {
				raise_log("Register ID="+ID+" to "+SocketAddressToString(sa));
			}
			return true;
		} catch (UnknownHostException | IllegalArgumentException e) {
			raise_log("Register_Device failed, exception="+e.getMessage());
			return false;
		}
		
	}
	
	private String SocketAddressToString(InetSocketAddress sa) {
		if (sa!=null) {
			return sa.getHostString()+":"+sa.getPort();
		}
		return "";
	}

	
	/**
	 * Check if serialport is opened
	 * @return true if opened
	 */
	public boolean IsOpened() {
		if (myport!=null) {
			return myport.isClosed()==false;
		}
		return false;
	}
	
	/**
	 * Make Camera to ON or OFF
	 * @param ID value 1 - 7
	 * @param toON 
	 * <br/><b>true</b> = Set Camera to ON
	 * <br/><b>false</b> = Set Camera to OFF 
	 * @return true if success
	 */
	public boolean CameraPower(int ID, boolean toON) {
		return SendData(false,MakeID(ID), 1, 4, 0, (toON ? 2 : 3), 0xFF);
	}
	
	/**
	 * Stop Zooming
	 * @param ID value 1 -7
	 * @return true if success
	 */
	public boolean Zoom_Stop(int ID) {
		return SendData(false,MakeID(ID), 1, 4, 7, 0, 0xFF);
	}
	
	/**
	 * Zoom Tele
	 * @param ID value 1 - 7
	 * @param speed 0 (low) - 7 (high)
	 * @return true if success
	 */
	public boolean Zoom_Tele(int ID, int speed) {
		if (speed<0) speed = 0;
		if (speed>7) speed = 7;
		return SendData(false,MakeID(ID), 1, 4, 7, (0x20+speed), 0xFF);
	}
	
	/**
	 * Zoom Wide
	 * @param ID value 1 - 7
	 * @param speed 0 (low) - 7 (high)
	 * @return true if success
	 */
	public boolean Zoom_Wide(int ID, int speed) {
		if (speed<0) speed = 0;
		if (speed>7) speed = 7;
		return SendData(false,MakeID(ID), 1, 4, 7, (0x30+speed), 0xFF);
	}
	
	/**
	 * Zoom directly to specific position
	 * @param ID value 1 - 7
	 * @param position 
	 * <br/><b>0x0000 - 0x6F20</b> for PTC310
	 * <br/><b>0x0110 - 0x5490</b> for PTC330
	 * @return true if success
	 */
	public boolean Zoom_Direct(int ID, int position) {
		int p = (position & 0xF000) >> 24;
		int q = (position & 0x0F00) >> 16;
		int r = (position & 0x00F0) >> 8 ;
		int s = (position & 0x000F);
		return SendData(false,MakeID(ID), 1, 4, 0x47, p, q, r, s, 0xFF);
	}
	
	/**
	 * Stop Focusing. Call after Focus_Far or Focus_Near
	 * @param ID value 1 - 7
	 * @return true if success
	 */
	public boolean Focus_Stop(int ID) {
		return SendData(false,MakeID(ID), 1, 4, 8, 0, 0xFF);
	}
	
	/**
	 * Focus to Far. call Focus_Stop if enough
	 * @param ID value 1 - 7
	 * @return true if success
	 */
	public boolean Focus_Far(int ID) {
		return SendData(false,MakeID(ID), 1, 4, 8, 2, 0xFF);
	}
	
	/**
	 * Focus to Near. Call Focus_Stop if enough
	 * @param ID value 1 - 7
	 * @return true if success
	 */
	public boolean Focus_Near(int ID) {
		return SendData(false,MakeID(ID), 1, 4 ,8, 3, 0xFF);
	}
	
	/**
	 * Auto Focus
	 * @param ID value  1 - 7
	 * @return true if success
	 */
	public boolean Focus_Auto(int ID) {
		return SendData(false,MakeID(ID), 1, 4, 0x38, 2, 0xFF);
	}
	
	/**
	 * Manual Focus
	 * @param ID value 1 - 7
	 * @return true if success
	 */
	public boolean Focus_Manual(int ID) {
		return SendData(false,MakeID(ID), 1, 4, 0x38, 3, 0xFF);
	}
	
	/**
	 * One Push Focus
	 * @param ID value 1 - 7
	 * @return true if success
	 */
	public boolean Focus_OnePush(int ID) {
		return SendData(false,MakeID(ID), 1, 4, 0x18, 1, 0xFF);
	}
	
	/**
	 * Focus Directly to specific position
	 * @param ID value 1 - 7
	 * @param position 
	 * <br/><b>0x0000 - 0x6F20</b> for PTC310
	 * <br/><b>0x0110 - 0x5490</b> for PTC330
	 * @return true if success
	 */
	public boolean Focus_Direct(int ID, int position) {
		
		return SendData(false,MakeID(ID), 1, 4, 0x47, GetByteFromInt(position,3), GetByteFromInt(position,2), GetByteFromInt(position,1), GetByteFromInt(position,0), 0xFF);
	}
	
	/**
	 * Change White Balance Mode
	 * @param ID value 1 - 7
	 * @param mode value 0 - 5, default to 0
	 * <br/><b>0</b> = Auto
	 * <br/><b>1</b> = Indoor
	 * <br/><b>2</b> = Outdoor
	 * <br/><b>3</b> = One push mode
	 * <br/><b>4</b> = Auto Trace Whitebalance
	 * <br/><b>5</b> = Manual
	 * @return true if success
	 */
	public boolean WhiteBalance_Mode(int ID, int mode) {
		if (mode<0) mode = 0;
		if (mode>5) mode = 0;
		return SendData(false,MakeID(ID), 1, 4, 0x35, mode, 0xFF);
	}
	
	/**
	 * Trigger OnePush at WhiteBalance
	 * @param ID value 1 - 7
	 * @return true if success
	 */
	public boolean WhiteBalance_OnePush_Trigger(int ID) {
		return SendData(false,MakeID(ID), 1, 4, 0x10, 5, 0xFF);
	}
	
	/**
	 * Increase / Decrease Red Gain
	 * @param ID value 1 - 7
	 * @param toUp true = up, false = down
	 * @return true if success
	 */
	public boolean RedGain(int ID, boolean toUp) {
		return SendData(false,MakeID(ID), 1, 4, 3, (toUp ? 2 : 3), 0xFF);
	}
	
	/**
	 * Increase / Decrease Blue Gain
	 * @param ID value 1 - 7
	 * @param toUp true =up, false = down
	 * @return true if success
	 */
	public boolean BlueGain(int ID, boolean toUp) {
		return SendData(false,MakeID(ID), 1, 4, 4, (toUp ? 2 : 3), 0xFF);
	}
	
	/**
	 * Change Auto Exposure Mode
	 * @param ID value 1 - 7
	 * @param mode 0 - 4
	 * <br/><b>0</b> = Full Auto, default to 0
	 * <br/><b>1</b> = Manual
	 * <br/><b>2</b> = Shutter Priority
	 * <br/><b>3</b> = Iris Priority
	 * <br/><b>4</b> = Bright
	 * @return true if success
	 */
	public boolean AutoExposure_Mode(int ID, int mode) {
		int code = 0;
		switch(mode) {
			case 1 :
				code = 0x3;
				break;
			case 2 : 
				code = 0xA;
				break;
			case 3 : 
				code = 0xB;
				break;
			case 4 : 
				code = 0xD;
			default : 
				code = 0;
				break;
		}
		return SendData(false,MakeID(ID), 1, 4, 0x39, code, 0xFF);
	}
	
	/**
	 * Increase / Decrease Shutter
	 * @param ID value 1 - 7
	 * @param toUp true = up, false = down
	 * @return true if success
	 */
	public boolean Shutter(int ID, boolean toUp) {
		return SendData(false,MakeID(ID), 1, 4, 0xA, (toUp ? 2 : 3), 0xFF);
	}
	
	/**
	 * Increase / Decrease Iris
	 * @param ID value 1 - 7
	 * @param toUp true = up, false = down
	 * @return true if success
	 */
	public boolean Iris(int ID, boolean toUp) {
		return SendData(false,MakeID(ID), 1, 4, 0xB, (toUp ? 2 : 3), 0xFF);
	}
	
	/**
	 * Increase / Decrease Gain
	 * @param ID value 1 - 7
	 * @param toUp true = up, false = down
	 * @return true if success
	 */
	public boolean Gain(int ID, boolean toUp) {
		return SendData(false,MakeID(ID), 1, 4, 0xC, (toUp ? 2 : 3), 0xFF);
	}
	
	/**
	 * Increase / Decrease Brightness
	 * @param ID value 1 - 7
	 * @param toUp true = up, false = down
	 * @return true if success
	 */
	public boolean Brightness(int ID, boolean toUp) {
		return SendData(false,MakeID(ID), 1, 4, 0xD, (toUp ? 2 : 3), 0xFF);
	}
	
	/**
	 * Increase / Decrease ExpComp
	 * @param ID value 1 - 7
	 * @param toUp true = up, false = down
	 * @return true if success
	 */
	public boolean ExpComp(int ID, boolean toUp) {
		return SendData(false,MakeID(ID), 1, 4, 0xE, (toUp ? 2 : 3), 0xFF);
	}
	
	/**
	 * Turn ON / OFF BackLight
	 * @param ID value 1 - 7
	 * @param toON true = ON, false = OFF
	 * @return true if success
	 */
	public boolean BackLight(int ID, boolean toON) {
		return SendData(false,MakeID(ID), 1, 4, 0x33, (toON ? 2 : 3), 0xFF);
	}
	
	/**
	 * Delete Preset Position
	 * @param ID value 1 - 7
	 * @param position 0 - 0xFF
	 * @return true if success
	 */
	public boolean Preset_Reset(int ID, int position) {
		if (position<0) position = 0;
		if (position>0xFF) position = 0xFF;
		return SendData(false,MakeID(ID), 1, 4, 0x3F, 0, position, 0xFF);
	}
	
	/**
	 * Save Preset Position
	 * @param ID value 1 - 7
	 * @param position 0 - 0xFF
	 * @return true if success
	 */
	public boolean Preset_Set(int ID, int position) {
		if (position<0) position = 0;
		if (position>0xFF) position = 0xFF;
		return SendData(false,MakeID(ID), 1, 4, 0x3F, 1, position, 0xFF);
	}
	
	/**
	 * Call saved Preset Position
	 * @param ID value 1 - 7
	 * @param position 0 - 0xFF
	 * @return true if success
	 */
	public boolean Preset_Call(int ID, int position) {
		if (position<0) position = 0;
		if (position>0xFF) position = 0xFF;
		return SendData(false,MakeID(ID), 1, 4, 0x3F, 2, position, 0xFF);
	}
	
	/**
	 * Toggle Show / Hide Menu
	 * @param ID value 1 - 7
	 * @return true if success
	 */
	public boolean Menu_ShowHide(int ID) {
		return SendData(false,MakeID(ID), 1, 6, 6, 0x10, 0xFF);
	}
	
	/**
	 * Enter to sub-menu at Menu Screen
	 * @param ID value 1 - 7
	 * @return true if success
	 */
	public boolean Menu_Enter(int ID) {
		return SendData(false,MakeID(ID), 1, 0x7E, 1, 2, 0, 1, 0xFF);
	}
	
	/**
	 * Move Camera Pan and Tilt
	 * Can move Pan, Tilt, or combination of them
	 * To stop, give PanMode = 3 and TiltMode = 3
	 * @param ID value 1 - 7
	 * @param PanMode value 1 - 3, default to 3
	 * <br/><b>1</b> = Left
	 * <br/><b>2</b> = Right
	 * <br/><b>3</b> = Stop Pan
	 * @param TiltMode value 1 - 3, default to 3
	 * <br/><b>1</b> = Up
	 * <br/><b>2</b> = Down
	 * <br/><b>3</b> = Stop Tilt
	 * @param PanSpeed value 0x1 (low) - 0x18 (high)
	 * @param TiltSpeed value 0x1 (low) - 0x18 (high)
	 * @return true if success
	 */
	public boolean PanTilt(int ID, int PanMode, int TiltMode, int PanSpeed, int TiltSpeed) {
		if (PanMode<1) PanMode = 3;
		if (PanMode>3) PanMode = 3;
		if (TiltMode<1) TiltMode = 3;
		if (TiltMode>3) TiltMode = 3;
		if (PanSpeed<1) PanSpeed = 1;
		if (PanSpeed>0x18) PanSpeed = 0x18;
		if (TiltSpeed<1) TiltSpeed = 01;
		if (TiltSpeed>0x18) TiltSpeed = 0x18;
		return SendData(false,MakeID(ID), 1, 6, 1, PanSpeed, TiltSpeed, PanMode, TiltMode, 0xFF);
	}
	
	/**
	 * Turn ON / OFF WDR
	 * @param ID value 1 - 7 
	 * @param toON true = ON, false = OFF
	 * @return true if success
	 */
	public boolean WideDynamicRange(int ID, boolean toON) {
		return SendData(false,MakeID(ID), 1, 4, 0x3D, (toON ? 2 : 3), 0xFF);
	}
	
	/**
	 * Turn ON / OFF Tally Lamp
	 * @param ID value 1 - 7
	 * @param toON true = ON, false = OFF
	 * @return true if success
	 */
	public boolean Tally_Lamp(int ID, boolean toON) {
		return SendData(false,MakeID(ID), 1, 0x7E, 1, 0xA, 0, (toON ? 2 : 3), 0xFF);
	}
	
	/**
	 * Freeze Picture immediately
	 * @param toON true = ON, false = OFF
	 * @return true if success
	 */
	public boolean FreezePicture(int ID, boolean toON) {
		return SendData(false,MakeID(ID), 1, 4, 0x62, (toON ? 2 : 3), 0xFF);
	}
	
	
	/**
	 * Freeze Picture when doing preset move
	 * @param toON true = ON, false = OFF
	 * @return true if success
	 */
	public boolean FreezePicture_WhenPresetMove(int ID, boolean toON) {
		return SendData(false,MakeID(ID), 1, 4, 0x62, (toON ? 0x22 : 0x23), 0xFF);
	}
	
	/**
	 * Turn ON / OFF Auto Track 
	 * @param ID value 1 - 7
	 * @param toON true = ON, false = OFF
	 * @return true if success
	 */
	public boolean AutoTracking(int ID, boolean toON) {
		return SendData(false,MakeID(ID), 1, 4, 0x7D, (toON ? 2 : 3), 0xFF);
	}
	
	/**
	 * Set Memory Special
	 * @param ID value 1  - 7
	 * @param preset
	 * <br/><b>0x0 - 0xFF</b> = Normal Preset
	 * <br/><b>0x5F</b> = Trun(?) on OSD Menu 
	 * <br/><b>0xA0</b> = Full Body
	 * <br/><b>0xA1</b> = Upper Body
	 * <br/><b>0xA2</b> = Tracking Point
	 * <br/><b>0xA3</b> = Switch
	 * <br/><b>0xA4</b> = Presenter Mode (firmware v25 or higher)
	 * <br/><b>0xA5</b> = Zone Mode (firmware v25 or higher)
	 * <br/><b>0xA6</b> = Hybrid Mode (firmware v25 or higher)
	 * @return true if success
	 */
	public boolean Memory_Special(int ID, int preset) {
		return SendData(false,MakeID(ID), 1, 4, 0x3F, 1, preset, 0xFF);
	}
	
	/**
	 * Move to absolute position 
	 * @param ID value 1 - 7
	 * @param PanPosition gak ada keterangan, apakah sama dengan Zoom Position ?
	 * @param TiltPosition gak ada keterangan, apakah sama dengan Zoom Positon ?
	 * @param PanSpeed 0x1 - 0x18
	 * @param TiltSpeed 0x1 - 0x18
	 * @return true if success
	 */
	public boolean MoveToAbsolutePosition(int ID, int PanPosition, int TiltPosition, int PanSpeed, int TiltSpeed) {
		if (PanSpeed < 1) PanSpeed = 1;
		if (PanSpeed > 0x18) PanSpeed = 0x18;
		if (TiltSpeed < 1) TiltSpeed = 1;
		if (TiltSpeed > 0x18) TiltSpeed = 0x18;
		return SendData(false,MakeID(ID), 1, 6, 2, PanSpeed, TiltSpeed, GetByteFromInt(PanPosition,3), GetByteFromInt(PanPosition,2), GetByteFromInt(PanPosition,1), GetByteFromInt(PanPosition,0), GetByteFromInt(TiltPosition,3), GetByteFromInt(TiltPosition,2), GetByteFromInt(TiltPosition,1), GetByteFromInt(TiltPosition,0), 0xFF);
	}
	
	/**
	 * Turn ON / OFF Auto Zoom
	 * @param ID value 1 - 7
	 * @param toON true = ON, false = OFF
	 * @return true if success
	 */
	public boolean AutoZoom(int ID, boolean toON) {
		return SendData(false,MakeID(ID), 1, 4, 0xA0, (toON ? 2 : 3), 0xFF);
	}
	
	/**
	 * Turn ON / OFF Effective Tracking Area
	 * @param ID value 1 - 7
	 * @param toON true = ON, false = OFF
	 * @return true if success
	 */
	public boolean EffectiveTrackingArea(int ID, boolean toON) {
		return SendData(false,MakeID(ID), 1, 4, 0xA1, (toON ? 2 : 3), 0xFF);
	}
	
	/**
	 * Turn ON / OFF RTMP
	 * @param ID value 1 -7
	 * @param toON true = ON, false = OFF
	 * @return true if success
	 */
	public boolean RTMP(int ID, boolean toON) {
		return SendData(false,MakeID(ID), 1, 4, 0xA2, (toON ? 2 : 3), 0xFF);
	}
	
	/**
	 * Change Video Mode
	 * @param ID value 1 - 7
	 * @param mode
	 * <br/><b>0</b> = IP+Stream
	 * <br/><b>1</b> = USB Only
	 * <br/><b>2</b> = NDI only
	 * <br/><b>3</b> = Streaming Only
	 * @return true if success
	 */
	public boolean VideoMode(int ID, int mode) {
		if (mode<0) mode = 0;
		if (mode>3) mode = 3;
		return SendData(false,MakeID(ID), 1, 4, 0xA3, mode, 0xFF);
	}
	
	/**
	 * Reboot Camera
	 * @param ID
	 * @return true if success
	 */
	public boolean Reboot(int ID) {
		return SendData(false,MakeID(ID), 1, 4, 0xA4, 0xFF);
	}
	
	/**
	 * Turn ON / OFF Preset Affects PTZ and Focus
	 * @param ID value 1 - 7
	 * @param toON true = ON, false = OFF
	 * @return true if success
	 */
	public boolean PresetAffectsPTZandFocus(int ID, boolean toON) {
		return SendData(false,MakeID(ID), 1, 4, 0xA5, (toON ? 2 : 3), 0xFF);
	}
	
	/**
	 * Turn ON / OFF Relative Zoom Ratio
	 * @param ID value 1 - 7
	 * @param toON true = ON, false = OFF
	 * @return true if success
	 */
	public boolean RelativeZoomRatio(int ID, boolean toON) {
		return SendData(false,MakeID(ID), 1, 4, 0xA6, (toON ? 2 : 3), 0xFF);
	}
	
	/**
	 * Turn ON / OFF Auto Tilt
	 * @param ID value 1 - 7
	 * @param toON true = ON, false = OFF
	 * @return true if success
	 */
	public boolean AutoTilt(int ID, boolean toON) {
		return SendData(false,MakeID(ID), 1, 4, 0xA7, (toON ? 2 : 3), 0xFF);
	}
	
	/**
	 * Auto Zoom or Tilt Preset
	 * @param ID value 1 - 7
	 * @param preset 00 - 0xFF
	 * @return true if success
	 */
	public boolean AutoZoomTiltPreset(int ID, int preset) {
		if (preset<0) preset = 0;
		if (preset > 0xFF) preset = 0xFF;
		return SendData(false,MakeID(ID),1, 4, 0xA8, preset, 0xFF);
	}
	
	/**
	 * Get Camera Power
	 * will raise event camerapower
	 * @param ID value 1 - 7
	 */
	public void Get_CameraPower(int ID) {
		if (SendData(true,MakeID(ID),9,4,0,0xFF)) {
			byte[] result = ReadData(4);
			if (ValidCommandRead(result,ID,4)) {
				if (result[2]==2) {
					raise_camerapower(true, ID, true);
					return;
				} else if (result[2]==3) {
					raise_camerapower(true, ID, false);
					return;
				}
			}
		}
		raise_camerapower(false, ID, false);
	}
	
	/**
	 * Get White Balance Mode
	 * will raise event whitebalancemode
	 * @param ID value 1 - 7
	 */
	public void Get_WhiteBalanceMode(int ID) {
		if (SendData(true,MakeID(ID), 9, 4, 0x35, 0xFF)) {
			byte[] result = ReadData(4);
			if (ValidCommandRead(result, ID,4)) {
				int code = ByteToInt(result[2]);
				switch(code) {
					case 0 :
						raise_whitebalancemode(true, ID, "Auto");
						return;
					case 1 :
						raise_whitebalancemode(true, ID, "Indoor");
						return;
					case 2 :
						raise_whitebalancemode(true, ID, "Outdoor");
						return;
					case 3 : 
						raise_whitebalancemode(true, ID, "One Push WB");
						return;
					case 4 :
						raise_whitebalancemode(true, ID, "ATW");
						return;
					case 5 : 
						raise_whitebalancemode(true, ID, "Manual");
						return;
				}
			}
		}
		raise_whitebalancemode(false, ID, "");
	}
	
	/**
	 * Get R-Gain
	 * will raise event rgain
	 * @param ID value 1 - 7
	 */
	public void Get_RGain(int ID) {
		if (SendData(true,MakeID(ID), 9, 4, 0x43, 0xFF)) {
			byte[] result = ReadData(7);
			if (ValidCommandRead(result,ID,7)) {
				raise_rgain(true, ID, WordToInt(result[4], result[5]));
				return;
			}
		}
		raise_rgain(false, ID, 0);
	}
	
	/**
	 * Get B-Gain
	 * will raise event bgain
	 * @param ID value 1 - 7
	 */
	public void Get_BGain(int ID) {
		if (SendData(true,MakeID(ID), 9,4, 0x44,0xFF)) {
			byte[] result = ReadData(7);
			if (ValidCommandRead(result, ID, 7)) {
				raise_bgain(true, ID, WordToInt(result[4], result[5]));
				return;
			}
		}
		raise_bgain(false, ID, 0);
	}
	
	/**
	 * Get Auto Exposure Mode
	 * will raise event aemode
	 * @param ID value 1 - 7
	 */
	public void Get_AutoExposureMode(int ID) {
		if (SendData(true,MakeID(ID), 9, 4, 0x39, 0xFF)) {
			byte[] result = ReadData(4);
			if (ValidCommandRead(result, ID, 4)) {
				int code = ByteToInt(result[2]);
				switch(code) {
				case 0 : 
					raise_aemode(true, ID, "Full Auto");
					return;
				case 3 :
					raise_aemode(true, ID, "Manual");
					return;
				case 0xA : 
					raise_aemode(true, ID, "Shutter Priority");
					return;
				case 0xB : 
					raise_aemode(true, ID, "Iris Priority");
					return;
				case 0xD :
					raise_aemode(true, ID, "Bright");
					return;
				}
			}
		}
		raise_aemode(false, ID, "");
	}
	
	/**
	 * Get Shutter position
	 * will raise event shutterposition
	 * @param ID value 1 - 7
	 */
	public void Get_ShutterPosition(int ID) {
		if (SendData(true,MakeID(ID), 9, 4, 0x4A, 0xFF)) {
			byte[] result = ReadData(7);
			if (ValidCommandRead(result, ID, 7)) {
				raise_shutterposition(true, ID, WordToInt(result[4], result[5]));
				return;
			}
		}
		raise_shutterposition(false, ID, 0);
	}
	
	/**
	 * Get Iris position
	 * will raise event irisposition
	 * @param ID value 1 - 7
	 */
	public void Get_IrisPosition(int ID) {
		if (SendData(true,MakeID(ID), 9, 4, 0x4B, 0xFF)) {
			byte[] result = ReadData(7);
			if (ValidCommandRead(result, ID, 7)) {
				raise_irisposition(true, ID, WordToInt(result[4], result[5]));
				return;
			}
		}
		raise_irisposition(false, ID, 0);
	}
	
	/**
	 * Get Gain position
	 * will raise event gainposition
	 * @param ID value 1 - 7
	 */
	public void Get_GainPosition(int ID) {
		if (SendData(true,MakeID(ID), 9, 4, 0x4C, 0xFF)) {
			byte[] result = ReadData(7);
			if (ValidCommandRead(result, ID, 7)) {
				raise_gainposition(true, ID, WordToInt(result[4], result[5]));
				return;
			}
		}
		raise_gainposition(false, ID, 0);
	}
	
	/**
	 * Get Bright position
	 * will raise event brightposition
	 * @param ID value 1 - 7
	 */
	public void Get_BrightPosition(int ID) {
		if (SendData(true,MakeID(ID), 9, 4, 0x4D, 0xFF)) {
			byte[] result = ReadData(7);
			if (ValidCommandRead(result, ID, 7)) {
				raise_brightposition(true, ID, WordToInt(result[4], result[5]));
				return;
			}
		}
		raise_brightposition(false, ID, 0);
	}
	
	/**
	 * Get Exposure Compensation position
	 * will raise event expcompposition
	 * @param ID value 1 - 7
	 */
	public void Get_ExpCompPosition(int ID) {
		if (SendData(true,MakeID(ID), 9, 4, 0x4E, 0xFF)) {
			byte[] result = ReadData(7);
			if (ValidCommandRead(result, ID, 7)) {
				raise_expcompposition(true, ID, WordToInt(result[4], result[5]));
				return;
			}
		}
		raise_expcompposition(false, ID, 0);
	}
	
	/**
	 * Get Focus Mode
	 * will raise event focusmode
	 * @param ID value 1- 7
	 */
	public void Get_FocusMode(int ID) {
		if (SendData(true,MakeID(ID), 9, 4, 0x38, 0xFF)) {
			byte[] result = ReadData(4);
			if (ValidCommandRead(result, ID, 4)) {
				if (result[2]==2) {
					raise_focusmode(true, ID, "Auto");
					return;
				} else if (result[2]==3) {
					raise_focusmode(true, ID, "Manual");
					return;
				}
			}
		}
		raise_focusmode(false, ID, "");
	}
	
	/**
	 * Get Focus Position
	 * will raise event focusposition
	 * @param ID value 1 - 7
	 */
	public void Get_FocusPosition(int ID) {
		if (SendData(true,MakeID(ID), 9, 4, 0x48, 0xFF)) {
			byte[] result = ReadData(7);
			if (ValidCommandRead(result, ID, 7)) {
				raise_focusposition(true, ID, ToInt(result[2], result[3], result[4], result[5]) );
				return;
			}
		}
		raise_focusposition(false, ID, 0);
	}
	
	/**
	 * Get Zoom Position
	 * will raise event zoomposition
	 * @param ID value 1 - 7
	 */
	public void Get_ZoomPosition(int ID) {
		if (SendData(true,MakeID(ID), 9, 4, 0x47, 0xFF)) {
			byte[] result = ReadData(7);
			if (ValidCommandRead(result, ID, 7)) {
				raise_zoomposition(true, ID, ToInt(result[2], result[3], result[4], result[5]) );
				return;
			}
		}
		raise_zoomposition(false, ID, 0);
	}
	
	/**
	 * Get Pan and Tilt Position
	 * will raise event pantiltposition
	 * @param ID value 1 - 7
	 */
	public void Get_PanTiltPosition(int ID) {
		if (SendData(true,MakeID(ID), 9, 6, 0x12, 0xFF)) {
			byte[] result = ReadData(11);
			if (ValidCommandRead(result, ID, 11)) {
				raise_pantiltposition(true, ID, ToInt(result[2], result[3], result[4], result[5]), ToInt(result[6], result[7], result[8], result[9]) );
				return;
			}
		}
		raise_pantiltposition(false, ID, 0,0);
	}
	
	/**
	 * Get current preset
	 * will raise event preset
	 * @param ID value 1 - 7
	 */
	public void Get_Preset(int ID) {
		if (SendData(true,MakeID(ID), 9,4, 0x3F, 0xFF)) {
			byte[] result = ReadData(4);
			if (ValidCommandRead(result, ID, 4)) {
				raise_preset(true, ID, ByteToInt(result[2]));
				return;
			}
		}
		raise_preset(false, ID, 0);
	}
	
	/**
	 * Get Tracking Status
	 * will raise event trackingstatus
	 * @param ID value 1 - 7
	 */
	public void Get_TrackingStatus(int ID) {
		if (SendData(true,MakeID(ID), 9,0x36, 0x69, 2, 0xFF)) {
			byte[] result = ReadData(4);
			if (ValidCommandRead(result, ID, 4)) {
				raise_trackingstatus(true, ID, ByteToInt(result[2])==1);
				return;
				
			}
		}
		raise_trackingstatus(false, ID, false);
	}
	
	/**
	 * Get Tracking Mode
	 * will raise event trackingmode
	 * @param ID value 1 - 7
	 */
	public void Get_TrackingMode(int ID) {
		if (SendData(true,MakeID(ID), 9,0x36, 0x69, 1, 0xFF)) {
			byte[] result = ReadData(4);
			if (ValidCommandRead(result, ID, 4)) {
				int code = ByteToInt(result[2]);
				switch(code) {
				case 1:
					raise_trackingmode(true, ID, "Presenter");
					return;
				case 2 :
					raise_trackingmode(true, ID, "Zone");
					return;
				case 3 : 
					raise_trackingmode(true, ID, "Hybrid");
					return;
				}
			}
		}
		raise_trackingmode(false, ID, "");
	}
	
	/**
	 * Get Tracking Body Size
	 * will raise event trackingbodysize
	 * @param ID value 1 - 7
	 */
	public void Get_TrackingBodySize(int ID) {
		if (SendData(true,MakeID(ID), 9,0x36, 0x69, 3, 0xFF)) {
			byte[] result = ReadData(4);
			if (ValidCommandRead(result, ID, 4)) {
				int code = ByteToInt(result[2]);
				switch(code) {
				case 1:
					raise_trackingbodysize(true, ID, "Full Body");
					return;
				case 2 :
					raise_trackingbodysize(true, ID, "Upper Body");
					return;
				}
			}
		}
		raise_trackingbodysize(false, ID, "");
	}
	
	/**
	 * Get if Menu OSD Displayed
	 * will raise event osdmenu
	 * @param ID value 1 - 7
	 */
	public void Get_OSDMenu(int ID) {
		if (SendData(true,MakeID(ID), 9, 0x7E, 4, 0x76, 1, 0xFF)) {
			byte[] result = ReadData(4);
			if (ValidCommandRead(result, ID, 4)) {
				raise_osdmenu(true, ID, result[2]==2);
				return;
			}
		}
		raise_osdmenu(false, ID, false);
	}
	
	/**
	 * Get if Tally is ON or OFF
	 * will raise event tally
	 * @param ID value 1 - 7
	 */
	public void Get_Tally(int ID) {
		if (SendData(true,MakeID(ID), 9, 0x7E, 1, 0xA, 0xFF)) {
			byte[] result = ReadData(4);
			if (ValidCommandRead(result, ID, 4)) {
				raise_tally(true, ID, result[2]==2);
				return;
			}
		}
		raise_tally(false, ID, false);
	}
	
	/**
	 * Get if WDR Mode is ON or OFF
	 * will raise event wdrmode
	 * @param ID value 1 - 7
	 */
	public void Get_WDRMode(int ID) {
		if (SendData(true,MakeID(ID), 9, 4, 0x3D, 0xFF)) {
			byte[] result = ReadData(4);
			if (ValidCommandRead(result, ID, 4)) {
				raise_wdrmode(true, ID, result[2]==2);
				return;
			}
		}
		raise_wdrmode(false, ID, false);
	}
	
	/**
	 * Get if BackLightCompensation (BLC) Mode is ON or OFF
	 * will raise event blcmode
	 * @param ID value 1 - 7
	 */
	public void Get_BLCMode(int ID) {
		if (SendData(true,MakeID(ID), 9, 4, 0x33, 0xFF)) {
			byte[] result = ReadData(4);
			if (ValidCommandRead(result, ID, 4)) {
				raise_blcmode(true, ID, result[2]==2);
				return;
			}
		}
		raise_blcmode(false, ID, false);
	}
	
	/**
	 * Get if Live Freeze Mode is ON or OFF
	 * will raise event livefreeze
	 * @param ID value 1 - 7
	 */
	public void Get_LiveFreezeMode(int ID) {
		if (SendData(true,MakeID(ID), 9, 4, 0x62, 1, 0xFF)) {
			byte[] result = ReadData(4);
			if (ValidCommandRead(result, ID, 4)) {
				raise_livefreeze(true, ID, result[2]==2);
				return;
			}
		}
		raise_livefreeze(false, ID, false);
	}
	
	/**
	 * Get if Preset Freeze Mode is ON or OFF
	 * will raise event presetfreeze
	 * @param ID value 1 - 7
	 */
	public void Get_PresetFreezeMode(int ID) {
		if (SendData(true,MakeID(ID), 9, 4, 0x62, 2, 0xFF)) {
			byte[] result = ReadData(4);
			if (ValidCommandRead(result, ID, 4)) {
				raise_presetfreeze(true, ID, result[2]==2);
				return;
			}
		}
		raise_presetfreeze(false, ID, false);
	}
	
	/**
	 * Get Firmware Version
	 * will raise event firmwareversion
	 * @param ID value 1 - 7
	 */
	public void Get_FirmwareVersion(int ID) {
		if (SendData(true,MakeID(ID), 9, 0x36, 0x69, 4, 0xFF)) {
			byte[] result = ReadData(11);
			if (ValidCommandRead(result, ID, 11)) {
				StringBuilder str = new StringBuilder();
				str.append(ByteToInt(result[2])).append(".");
				str.append(ByteToInt(result[3])).append(".");
				str.append(ToInt(result[4], result[5], result[6], result[7])).append(".");
				str.append(WordToInt(result[8], result[9]));
				raise_firmwareversion(true, ID, str.toString());
				return;
			}
		}
		raise_firmwareversion(false, ID, "");
	}
	
	/**
	 * Get USB Plugged status
	 * will raise event usbpluggedstatus
	 * @param ID value 1 - 7
	 */
	public void Get_USBPluggedStatus(int ID) {
		if (SendData(true,MakeID(ID), 9, 0x36, 0x69, 5, 0xFF)) {
			byte[] result = ReadData(4);
			if (ValidCommandRead(result, ID, 4)) {
				raise_usbpluggedstatus(true, ID, result[2]==1);
				return;
			}
		}
		raise_usbpluggedstatus(false, ID, false);
	}
	
	/**
	 * Get UVC Stream ON or OFF
	 * will raise event uvcstatus
	 * @param ID value 1 - 7
	 */
	public void Get_UVCStatus(int ID) {
		if (SendData(true,MakeID(ID), 9, 0x36, 0x69, 6, 0xFF)) {
			byte[] result = ReadData(4);
			if (ValidCommandRead(result, ID, 4)) {
				raise_uvcstatus(true,ID, result[2]==1);
				return;
			}
		}
		raise_uvcstatus(false, ID, false);
	}
	
	/**
	 * Convert Byte to Int
	 * @param bb byte value
	 * @return int value
	 */
	private int ByteToInt(byte bb) {
		return (bb & 0xFF);
	}
	
	private int WordToInt(byte bh, byte bl) {
		return (ByteToInt(bh) << 8) + ByteToInt(bl);
	}
	
	private int ToInt(byte b3, byte b2, byte b1, byte b0) {
		return (ByteToInt(b3)<<24) | (ByteToInt(b2)<<16) | (ByteToInt(b1)<<8) | (ByteToInt(b0));
	}
	
	/**
	 * Make ID for sending data
	 * sending data always 0x8y , with y = ID
	 * @param ID 1 - 7
	 * @return value in 0x8y
	 */
	private int MakeID(int ID) {
		if (ID<1) ID = 1;
		if (ID>7) ID = 7;
		return (0x80 + ID);
	}
	
	/**
	 * Make ID for Inquiry data
	 * getting data always 0xY0, with Y = ID
	 * @param ID 1 - 7
	 * @return value in 0xY0
	 */
	private int MakeIDGet(int ID) {
		if (ID<1) ID = 1;
		if (ID>7) ID = 7;
		return (0x10 * ID);
	}
	
	/**
	 * Send Integer Data to UDP
	 * @param IsInquiry if true, is a Get command
	 * @param cmd array of integer
	 * @return true if can be send
	 */
	private boolean SendData(boolean IsInquiry, int... cmd ) {
		if (cmd!=null) {
			if (cmd.length>0) {
				// ID dalam format 0x8Y
				// dengan Y = 1 - 7
				int ID = cmd[0];
				if (ID>=0x81 && ID<=0x87) {
					ID = ID & 0x0F;
					InetSocketAddress sa = map.get(ID);
					if (sa!=null) {
						if (IsOpened()) {
							byte[] bytecmd = new byte[cmd.length+8];
							bytecmd[0] = 1;
							bytecmd[1] = (byte) (IsInquiry ? 0x10 : 0);
							bytecmd[2] = 0;
							bytecmd[3] = (byte) cmd.length;
							
							bytecmd[4] = GetByteFromInt(sequence_number,3);
							bytecmd[5] = GetByteFromInt(sequence_number,2);
							bytecmd[6] = GetByteFromInt(sequence_number,1);
							bytecmd[7] = GetByteFromInt(sequence_number,0);
							if (sequence_number<Integer.MAX_VALUE) sequence_number+=1; else sequence_number=0;
							
							for(int ii=0;ii<cmd.length;ii++) bytecmd[8+ii] = (byte)(cmd[ii]);
							
							DatagramPacket dp = new DatagramPacket(bytecmd,bytecmd.length, sa);
							try {
								myport.send(dp);
								return true;
							} catch (IOException e) {
								raise_log("SendData to "+SocketAddressToString(sa)+" failed, exception="+e.getMessage());
							}
							
						} else raise_log("SendData failed, UDP not Opened");
					} else raise_log("SendData failed, ID="+ID+" is not registered");
				} else raise_log("SendData failed, ID must in format 0x8Y");
			} else raise_log("SendData Failed, command length is zero");
		} else raise_log("SendData Failed, command is null");
		return false;
	}
	
	private byte GetByteFromInt(int value, int position) {
		switch(position) {
		case 1 :
			return (byte)((value & 0x00F0)>>8);
		case 2 : 
			return (byte)((value & 0x0F00)>>16);
		case 3 : 
			return (byte)((value & 0xF000)>>24);
		default :
			return (byte) (value & 0x000F);
				
		}
	}
	
	/**
	 * Read Data from Serial Port
	 * @param expectedlength number of bytes expected to be read
	 * @return empty array if failed, or array with expectedlength if success
	 */
	private byte[] ReadData(int expectedlength) {
		if (IsOpened()) {
			
			byte[] buf = new byte[expectedlength+8];
			DatagramPacket dp = new DatagramPacket(buf, buf.length);
			try {
				myport.receive(dp);
				buf = dp.getData();
				if (buf.length>=(expectedlength+8)) {
					if (buf[0]==1) {
						if (buf[1]==0x11) {
							byte[] result = new byte[expectedlength];
							for(int ii=0;ii<result.length;ii++) result[ii] = buf[ii+8];
							return result;
						} else raise_log("ReadData failed, result[1] invalid");
					} else raise_log("ReadData failed, result[0] invalid");
				} else raise_log("ReadData failed, UDP received bytes below expected length");
			} catch (IOException e) {
				raise_log("ReadData failed, UDP Receive exception="+e.getMessage());
			}
		} else raise_log("ReadData failed, UDP not opened");
		return new byte[0];
	}
	
	/**
	 * Check if Read Bytes are valid Command
	 * @param bb array of bytes to check
	 * @param ID value 1 - 7
	 * @param expectedlength expected length of bb
	 * @return true if valid Command
	 */
	private boolean ValidCommandRead(byte[] bb, int ID, int expectedlength) {
		if (bb!=null) {
			int length = bb.length;
			if (length>=expectedlength) {
				// minimal reply itu 4 bytes
				int header = ByteToInt(bb[0]);
				int footer = ByteToInt(bb[length-1]);
				int code = ByteToInt(bb[1]);
				if (footer == 0xFF) {
					if (code==0x50) {
						return (header==MakeIDGet(ID));
					}
				}
			}
		}
		return false;
	}
	
	private void raise_log(String msg) {
		if (need_log_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_log", false, new Object[] {msg});
	}
	
	private void raise_camerapower(boolean success, int id, boolean value) {
		if (need_camerapower_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_camerapower", false, new Object[] {success, id, value});
	}
	
	private void raise_whitebalancemode(boolean success, int id, String value) {
		if (need_whitebalancemode_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_whitebalancemode", false, new Object[] {success, id, value});
	}
	
	private void raise_rgain(boolean success, int id, int value) {
		if (need_rgain_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_rgain", false, new Object[] {success, id, value});
	}
	
	private void raise_bgain(boolean success, int id, int value) {
		if (need_bgain_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_bgain", false, new Object[] {success, id, value});
	}
	
	private void raise_aemode(boolean success, int id, String value) {
		if (need_aemode_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_aemode", false, new Object[] {success, id, value});
	}
	
	private void raise_shutterposition(boolean success, int id, int value) {
		if (need_shutterposition_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_shutterposition", false, new Object[] {success, id, value});
	}
	
	private void raise_irisposition(boolean success, int id, int value) {
		if (need_irisposition_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_irisposition", false, new Object[] {success, id, value});
	}
	
	private void raise_gainposition(boolean success, int id, int value) {
		if (need_gainposition_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_gainposition", false, new Object[] {success, id, value});
	}
	
	private void raise_brightposition(boolean success, int id, int value) {
		if (need_brightposition_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_brightposition", false, new Object[] {success, id, value});
	}
	
	private void raise_expcompposition(boolean success, int id, int value) {
		if (need_expcompposition_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_expcompposition", false, new Object[] {success, id, value});
	}
	
	private void raise_focusmode(boolean success, int id, String value) {
		if (need_focusmode_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_focusmode", false, new Object[] {success, id, value});
	}
	
	private void raise_focusposition(boolean success, int id, int value) {
		if (need_focusposition_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_focusposition", false, new Object[] {success, id, value});
	}
	
	private void raise_zoomposition(boolean success, int id, int value) {
		if (need_zoomposition_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_zoomposition", false, new Object[] {success, id, value});
	}
	
	private void raise_pantiltposition(boolean success, int id, int panvalue, int tiltvalue) {
		if (need_pantiltposition_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_pantiltposition", false, new Object[] {success, id, panvalue, tiltvalue});
	}
	
	private void raise_preset(boolean success, int id, int value) {
		if (need_preset_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_preset", false, new Object[] {success, id, value});
	}
	
	private void raise_trackingstatus(boolean success, int id, boolean value) {
		if (need_trackingstatus_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_trackingstatus", false, new Object[] {success, id, value});
	}
	
	private void raise_trackingmode(boolean success, int id, String value) {
		if (need_trackingmode_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_trackingmode", false, new Object[] {success, id, value});
	}
	
	private void raise_trackingbodysize(boolean success, int id, String value) {
		if (need_trackingbodysize_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_trackingbodysize", false, new Object[] {success, id, value});
	}
	
	private void raise_osdmenu(boolean success, int id, boolean value) {
		if (need_osdmenu_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_osdmenu", false, new Object[] {success, id, value});
	}
	
	private void raise_tally(boolean success, int id, boolean value) {
		if (need_tally_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_tally", false, new Object[] {success, id, value});
	}
	
	private void raise_wdrmode(boolean success, int id, boolean value) {
		if (need_wdrmode_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_wdrmode", false, new Object[] {success, id, value});
	}
	
	private void raise_blcmode(boolean success, int id, boolean value) {
		if (need_blcmode_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_blcmode", false, new Object[] {success, id, value});
	}
	
	private void raise_livefreeze(boolean success, int id, boolean value) {
		if (need_livefreeze_event) ba.raiseEventFromDifferentThread(Me,  null, 0, event+"_livefreeze", false, new Object[] {success, id, value});
	}
	
	private void raise_presetfreeze(boolean success, int id, boolean value) {
		if (need_presetfreeze_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_presetfreeze", false, new Object[] {success, id, value});
	}
	
	private void raise_firmwareversion(boolean success, int id, String value) {
		if (need_firmwareversion_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_firmwareversion", false, new Object[] {success, id, value});
	}
	
	private void raise_usbpluggedstatus(boolean success, int id, boolean value) {
		if (need_usbpluggedstatus_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_usbpluggedstatus", false, new Object[] {success, id, value});
	}
	
	private void raise_uvcstatus(boolean success, int id, boolean value) {
		if (need_uvcstatus_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_uvcstatus", false, new Object[] {success, id, value});
	}
}
