// Remove a device from YAPI after an unplug detected by device refresh internal virtual void imm_forgetDevice(string serial) { YDevice dev = _devs[serial]; if (dev == null) { return; } string lname = dev.imm_getLogicalName(); _devs.Remove(serial); if (_snByName.ContainsKey(lname) && _snByName[lname].Equals(serial)) { _snByName.Remove(lname); } YFunctionType module = _fnByType["Module"]; module.imm_forgetFunction(serial + ".module"); int count = dev.imm_functionCount(); for (int i = 0; i < count; i++) { YPEntry yp = dev.imm_getYPEntryFromOfs(i); if (_fnByType.ContainsKey(yp.Classname)) { YFunctionType functionType = _fnByType[yp.Classname]; functionType.imm_forgetFunction(yp.HardwareId); } } }
// Reindex a device in YAPI after a name change detected by device refresh internal virtual void imm_reindexDevice(YDevice dev) { string serial = dev.imm_getSerialNumber(); string lname = dev.imm_getLogicalName(); _devs[serial] = dev; if (!lname.Equals("")) { _snByName[lname] = serial; } YFunctionType module = _fnByType["Module"]; YPEntry moduleYPEntry = dev.ModuleYPEntry; module.imm_reindexFunction(moduleYPEntry); int count = dev.imm_functionCount(); for (int i = 0; i < count; i++) { YPEntry yp = dev.imm_getYPEntryFromOfs(i); string classname = yp.Classname; YFunctionType functionType; if (_fnByType.ContainsKey(classname)) { functionType = _fnByType[classname]; } else { functionType = new YFunctionType(classname, _yctx); _fnByType[classname] = functionType; } functionType.imm_reindexFunction(yp); } }
// Find the hardwareId for the first instance of a given function class internal virtual string imm_getFirstHardwareId(string className) { if (!_yctx._BaseType.ContainsKey(className)) { YFunctionType ft = imm_getFnByType(className); YPEntry yp = ft.imm_getFirstYPEntry(); if (yp == null) { return(null); } return(yp.HardwareId); } else { // using an abstract baseType YPEntry.BaseClass baseType = _yctx._BaseType[className]; foreach (YFunctionType subClassType in _fnByType.Values) { YPEntry yp = subClassType.imm_getFirstYPEntry(); if (yp != null && yp.getBaseClass().Equals(baseType)) { return(yp.HardwareId); } } return(null); } }
// Find the exact Hardware Id of the specified function, if currently connected // If device is not known as connected, return a clean error // This function will not cause any network access public virtual string getFriendlyName(YAPIContext ctx) { if (_classname.Equals("Module")) { if (_logicalName.Equals("")) { return(_serial + ".module"); } else { return(_logicalName + ".module"); } } else { YPEntry moduleYP = ctx._yHash.imm_resolveFunction("Module", _serial); string module = moduleYP.getFriendlyName(ctx); int pos = module.IndexOf(".", StringComparison.Ordinal); module = module.Substring(0, pos); if (_logicalName.Equals("")) { return(module + "." + _funcId); } else { return(module + "." + _logicalName); } } }
public void imm_handleTimedNotification(YPktStreamHead data) { uint pos = 0; YDevice ydev = _yctx._yHash.imm_getDevice(SerialNumber); if (ydev == null) { // device has not been registered; return; } while (pos < data.Len) { int funYdx = data.imm_GetByte(pos) & 0xf; bool isAvg = (data.imm_GetByte(pos) & 0x80) != 0; uint len = (uint)(1 + ((data.imm_GetByte(pos) >> 4) & 0x7)); pos++; if (data.Len < pos + len) { _yctx._Log("drop invalid timedNotification"); return; } if (funYdx == 0xf) { byte[] intData = new byte[len]; for (uint i = 0; i < len; i++) { intData[i] = data.imm_GetByte(pos + i); } ydev.imm_setDeviceTime(intData); } else { YPEntry yp = imm_getYPEntryFromYdx(funYdx); if (yp != null) { List <int> report = new List <int>((int)(len + 1)); report.Add(isAvg ? 1 : 0); for (uint i = 0; i < len; i++) { int b = data.imm_GetByte(pos + i) & 0xff; report.Add(b); } _hub.imm_handleTimedNotification(yp.Serial, yp.FuncId, ydev.imm_getDeviceTime(), report); } } pos += len; } }
// Retrieve a function advertised value by hardware id public virtual void imm_setFunctionValue(string hwid, string pubval) { if (!_ypEntries.ContainsKey(hwid)) { // device has not been correctly registered return; } YPEntry yp = _ypEntries[hwid]; if (yp.AdvertisedValue.Equals(pubval)) { return; } yp.AdvertisedValue = pubval; }
public void handleTimedNotificationV2(YPktStreamHead data) { uint pos = 0; YDevice ydev = _yctx._yHash.imm_getDevice(SerialNumber); if (ydev == null) { // device has not been registered; return; } while (pos < data.Len) { int funYdx = data.imm_GetByte(pos) & 0xf; uint extralen = (uint)((data.imm_GetByte(pos) >> 4) & 0xf); uint len = extralen + 1; pos++; // consume generic header if (funYdx == 0xf) { byte[] intData = new byte[len]; for (uint i = 0; i < len; i++) { intData[i] = data.imm_GetByte(pos + i); } ydev.imm_setDeviceTime(intData); } else { YPEntry yp = imm_getYPEntryFromYdx(funYdx); if (yp != null) { List <int> report = new List <int>((int)(len + 1)); report.Add(2); for (uint i = 0; i < len; i++) { int b = data.imm_GetByte(pos + i) & 0xff; report.Add(b); } _hub.imm_handleTimedNotification(yp.Serial, yp.FuncId, ydev.imm_getDeviceTime(), report); } } pos += len; } }
// Find the hardwareId for the next instance of a given function class internal virtual string imm_getNextHardwareId(string className, string hwid) { if (!_yctx._BaseType.ContainsKey(className)) { YFunctionType ft = imm_getFnByType(className); YPEntry yp = ft.imm_getNextYPEntry(hwid); if (yp == null) { return(null); } return(yp.HardwareId); } else { // enumeration of an abstract class YPEntry.BaseClass baseType = _yctx._BaseType[className]; string prevclass = YAPIContext.imm_functionClass(hwid); YPEntry res = imm_getFnByType(prevclass).imm_getNextYPEntry(hwid); if (res != null) { return(res.HardwareId); } foreach (string altClassName in _fnByType.Keys) { if (!prevclass.Equals("")) { if (!altClassName.Equals(prevclass)) { continue; } prevclass = ""; continue; } YFunctionType functionType = _fnByType[altClassName]; res = functionType.imm_getFirstYPEntry(); if (res != null && res.getBaseClass().Equals(baseType)) { return(res.HardwareId); } } return(null); } }
// Device constructor. Automatically call the YAPI functin to reindex device internal YDevice(YGenericHub hub, WPEntry wpRec, Dictionary <string, List <YPEntry> > ypRecs) { // private attributes _hub = hub; _wpRec = wpRec; _cache_expiration = 0; _cache_json = null; _moduleYPEntry = new YPEntry(wpRec.SerialNumber, "module", YPEntry.BaseClass.Function); _moduleYPEntry.LogicalName = wpRec.LogicalName; _ypRecs = new Dictionary <int?, YPEntry>(); List <string> keySet = ypRecs.Keys.ToList(); foreach (string categ in keySet) { foreach (YPEntry rec in ypRecs[categ]) { if (rec.Serial.Equals(wpRec.SerialNumber)) { int funydx = rec.Index; _ypRecs[funydx] = rec; } } } }
public virtual void imm_reindexFunction(YPEntry yp) { string oldLogicalName = ""; string hardwareId = yp.HardwareId; if (_ypEntries.ContainsKey(hardwareId)) { oldLogicalName = _ypEntries[hardwareId].LogicalName; } if (!oldLogicalName.Equals("") && !oldLogicalName.Equals(yp.LogicalName)) { if (_hwIdByName[oldLogicalName].Equals(hardwareId)) { _hwIdByName.Remove(oldLogicalName); } } if (!yp.LogicalName.Equals("")) { _hwIdByName[yp.LogicalName] = hardwareId; } _ypEntries[yp.HardwareId] = yp; }
// Find the best known identifier (hardware Id) for a given function internal virtual YPEntry imm_resolveFunction(string className, string func) { if (!_yctx._BaseType.ContainsKey(className)) { return(imm_getFnByType(className).imm_getYPEntry(func)); } else { // using an abstract baseType YPEntry.BaseClass baseType = _yctx._BaseType[className]; foreach (YFunctionType subClassType in _fnByType.Values) { try { YPEntry yp = subClassType.imm_getYPEntry(func); if (yp.getBaseClass().Equals(baseType)) { return(yp); } } catch (YAPI_Exception) { } } } throw new YAPI_Exception(YAPI.DEVICE_NOT_FOUND, "No function of type " + className + " found"); }
// Find the exact Hardware Id of the specified function, if currently connected // If device is not known as connected, return a clean error // This function will not cause any network access public virtual HWID imm_resolve(string func) { // Try to resolve str_func to a known Function instance, if possible, without any device access int dotpos = func.IndexOf('.'); if (dotpos < 0) { // First case: func is the logical name of a function if (_hwIdByName.ContainsKey(func)) { string hwid_str = _hwIdByName[func]; return(new HWID(hwid_str)); } // fallback to assuming that func is a logical name or serial number of a module // with an implicit function name (like serial.module for instance) func += string.Format(".{0}{1}", char.ToLower(_className[0]), _className.Substring(1)); } // Second case: func is in the form: device_id.function_id HWID hwid = new HWID(func); // quick lookup for a known pure hardware id if (_ypEntries.ContainsKey(hwid.ToString())) { return(hwid); } if (hwid.module.Length > 0) { // either the device id is a logical name, or the function is unknown YDevice dev = _yctx._yHash.imm_getDevice(hwid.module); if (dev == null) { throw new YAPI_Exception(YAPI.DEVICE_NOT_FOUND, "Device [" + hwid.module + "] not online"); } string serial = dev.imm_getSerialNumber(); hwid = new HWID(serial, hwid.Function); if (_ypEntries.ContainsKey(hwid.ToString())) { return(hwid); } // not found neither, may be funcid is a function logicalname int nfun = dev.imm_functionCount(); for (int i = 0; i < nfun; i++) { YPEntry yp = dev.imm_getYPEntryFromOfs(i); if (yp.LogicalName.Equals(hwid.Function) && _ypEntries.ContainsValue(yp)) { return(new HWID(serial, yp.FuncId)); } } } else { // only functionId (ie ".temperature") foreach (string hwid_str in _connectedFns.Keys) { HWID tmpid = new HWID(hwid_str); if (tmpid.Function.Equals(hwid.Function)) { return(tmpid); } } } throw new YAPI_Exception(YAPI.DEVICE_NOT_FOUND, "No function [" + hwid.function + "] found on device [" + hwid.module + "]"); }
/// <summary> /// Returns a global identifier of the function in the format MODULE_NAME.FUNCTION_NAME. /// The returned string uses the logical names of the module and of the function if they are defined, /// otherwise the serial number of the module and the hardware identifier of the function /// (for example: MyCustomName.relay1) /// </summary> /// <returns> a string that uniquely identifies the function using logical names /// (ex: MyCustomName.relay1) /// </returns> /// <exception cref="YAPI_Exception"> on error </exception> public virtual async Task <string> get_friendlyName() { YPEntry yp = _yapi._yHash.imm_resolveFunction(_className, _func); return(yp.getFriendlyName(_yapi)); }
private void imm_handleNotifcation(YPktStreamHead ystream) { string functionId; int firstByte = ystream.imm_GetByte(0); bool isV2 = ystream.StreamType == YGenericHub.YSTREAM_NOTICE_V2; if (isV2 || firstByte <= NOTIFY_1STBYTE_MAXTINY || firstByte >= NOTIFY_1STBYTE_MINSMALL) { int funcvalType = (firstByte >> NOTIFY_V2_TYPE_OFS) & NOTIFY_V2_TYPE_MASK; int funydx = firstByte & NOTIFY_V2_FUNYDX_MASK; YPEntry ypEntry = imm_getYPEntryFromYdx(funydx); if (ypEntry != null) { if (ypEntry.Index == funydx) { if (funcvalType == YGenericHub.NOTIFY_V2_FLUSHGROUP) { // not yet used by devices } else { if ((firstByte & NOTIFY_V2_IS_SMALL_FLAG) != 0) { // added on 2015-02-25, remove code below when confirmed dead code throw new YAPI_Exception(YAPI.IO_ERROR, "Hub Should not fwd notification"); } int len = (int)ystream.Len; byte[] data = new byte[len]; ystream.imm_CopyData(data, 0); string funcval = YGenericHub.imm_decodePubVal(funcvalType, data, 1, len - 1); _hub.imm_handleValueNotification(SerialNumber, ypEntry.FuncId, funcval); } } } } else { string serial = ystream.imm_GetString(0, YAPI.YOCTO_SERIAL_LEN); if (SerialNumber == null) { SerialNumber = serial; } uint p = YAPI.YOCTO_SERIAL_LEN; int type = ystream.imm_GetByte(p++); switch (type) { case NOTIFY_PKT_NAME: _logicalname = ystream.imm_GetString(p, YAPI.YOCTO_LOGICAL_LEN); _beacon = ystream.imm_GetByte(p + YAPI.YOCTO_LOGICAL_LEN); break; case NOTIFY_PKT_PRODNAME: _product = ystream.imm_GetString(p, YAPI.YOCTO_PRODUCTNAME_LEN); break; case NOTIFY_PKT_CHILD: break; case NOTIFY_PKT_FIRMWARE: _firmware = ystream.imm_GetString(p, YAPI.YOCTO_FIRMWARE_LEN); p += YAPI.YOCTO_FIRMWARE_LEN; p += 2; _deviceid = (ushort)(ystream.imm_GetByte(p) + (ystream.imm_GetByte(p + 1) << 8)); break; case NOTIFY_PKT_FUNCNAME: functionId = ystream.imm_GetString(p, YAPI.YOCTO_FUNCTION_LEN); p += YAPI.YOCTO_FUNCTION_LEN; string funcname = ystream.imm_GetString(p, YAPI.YOCTO_LOGICAL_LEN); if (!_usbYP.ContainsKey(functionId)) { _usbYP[functionId] = new YPEntry(serial, functionId, YPEntry.BaseClass.Function); } _usbYP[functionId].LogicalName = funcname; break; case NOTIFY_PKT_FUNCVAL: functionId = ystream.imm_GetString(p, YAPI.YOCTO_FUNCTION_LEN); p += YAPI.YOCTO_FUNCTION_LEN; string funcval = ystream.imm_GetString(p, YAPI.YOCTO_PUBVAL_SIZE); _hub.imm_handleValueNotification(serial, functionId, funcval); break; case NOTIFY_PKT_STREAMREADY: _devState = DevState.StreamReadyReceived; _wp = new WPEntry(_logicalname, _product, _deviceid, "", _beacon, SerialNumber); _yctx._Log("Device " + SerialNumber + " ready.\n"); _currentTask.SetResult(true); break; case NOTIFY_PKT_LOG: //FIXME: handle log notification break; case NOTIFY_PKT_FUNCNAMEYDX: functionId = ystream.imm_GetString(p, YAPI.YOCTO_FUNCTION_LEN - 1); p += YAPI.YOCTO_FUNCTION_LEN - 1; byte funclass = ystream.imm_GetByte(p++); funcname = ystream.imm_GetString(p, YAPI.YOCTO_LOGICAL_LEN); p += YAPI.YOCTO_LOGICAL_LEN; byte funydx = ystream.imm_GetByte(p); if (!_usbYP.ContainsKey(functionId)) { _usbYP[functionId] = new YPEntry(serial, functionId, YPEntry.BaseClass.forByte(funclass)); } // update ydx _usbYP[functionId].Index = funydx; _usbYP[functionId].LogicalName = funcname; break; case NOTIFY_PKT_PRODINFO: break; default: //fixme: Find why this happening on my dev computer throw new YAPI_Exception(YAPI.IO_ERROR, "Invalid Notification"); } } }
internal override async Task updateDeviceListAsync(bool forceupdate) { ulong now = YAPI.GetTickCount(); if (forceupdate) { _devListExpires = 0; } if (_devListExpires > now) { return; } if (!_notificationHandler.Connected) { if (_reportConnnectionLost) { throw new YAPI_Exception(YAPI.TIMEOUT, "hub " + _http_params.Url + " is not reachable"); } else { return; } } string json_data; try { byte[] data = await _notificationHandler.hubRequestSync("GET /api.json", null, YIO_DEFAULT_TCP_TIMEOUT); json_data = YAPI.DefaultEncoding.GetString(data); } catch (YAPI_Exception) { if (_reportConnnectionLost) { throw; } return; } Dictionary <string, List <YPEntry> > yellowPages = new Dictionary <string, List <YPEntry> >(); List <WPEntry> whitePages = new List <WPEntry>(); YJSONObject loadval = new YJSONObject(json_data); loadval.parse(); if (!loadval.has("services") || !loadval.getYJSONObject("services").has("whitePages")) { throw new YAPI_Exception(YAPI.INVALID_ARGUMENT, "Device " + _http_params.Host + " is not a hub"); } _serial = loadval.getYJSONObject("module").getString("serialNumber"); YJSONArray whitePages_json = loadval.getYJSONObject("services").getYJSONArray("whitePages"); YJSONObject yellowPages_json = loadval.getYJSONObject("services").getYJSONObject("yellowPages"); if (loadval.has("network")) { string adminpass = loadval.getYJSONObject("network").getString("adminPassword"); _writeProtected = adminpass.Length > 0; } // Reindex all functions from yellow pages //HashMap<String, Boolean> refresh = new HashMap<String, Boolean>(); List <string> keys = yellowPages_json.keys(); foreach (string classname in keys) { YJSONArray yprecs_json = yellowPages_json.getYJSONArray(classname); List <YPEntry> yprecs_arr = new List <YPEntry>(yprecs_json.Length); for (int i = 0; i < yprecs_json.Length; i++) { YPEntry yprec = new YPEntry(yprecs_json.getYJSONObject(i)); yprecs_arr.Add(yprec); } yellowPages[classname] = yprecs_arr; } _serialByYdx.Clear(); // Reindex all devices from white pages for (int i = 0; i < whitePages_json.Length; i++) { YJSONObject jsonObject = whitePages_json.getYJSONObject(i); WPEntry devinfo = new WPEntry(jsonObject); int index = jsonObject.getInt("index"); _serialByYdx[index] = devinfo.SerialNumber; whitePages.Add(devinfo); } await updateFromWpAndYp(whitePages, yellowPages); // reset device list cache timeout for this hub now = YAPI.GetTickCount(); _devListExpires = now + _devListValidity; }