//NOTE: will bee called by another thread
        internal void imm_AddIncommingData(YPktStreamHead stream)
        {
            if (stream.Len + _response_size > _response.Length)
            {
                byte[] tmp = new byte[_response.Length * 2];
                Buffer.BlockCopy(_response, 0, tmp, 0, _response.Length);
                _response = tmp;
            }

            uint len = stream.imm_CopyData(_response, _response_size);

            _response_size += len;
        }
        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");
                }
            }
        }