对于RIL功能的一个封装

前段时间,为了实现WM手机的一些底层功能,需要对RIL的一些函数进行调用,这个过程中发现RILNOTIFYCALLBACK表现得不尽如意:在模拟器上实现的Notification注册在手机上却没有成功,因为缺少文档也没有找到原因。结果实现的功能主要是基于RILResultCallback的。当时为了提高效率,对RIL进行了封装,最近觉得这个封装应该进一步修改,想想自己的Blog还没有什么干货,干脆就先把以前实现的在这里总结一下,虽然因为工作的关系不能公布绝大多数代码,但也许我的思路和方法能对别人有所裨益。

大体来说,最直接地实现RIL Result Callback需要以下几步(可参见http://bbs.cnw.com.cn/viewthread.php?tid=134138):

1)定义相应的数据结构,例如RILCELLTOWERINFO,需要区别C++中数据类型与CTS类型的转换;

2)定义函数原型(包括RIL_InitializeRIL_DeinitializeRILRESULTCALLBACK, RILNOTIFYCALLBACK);

3)定义具体调用的RIL Native函数原型,例如RIL_GetCellTowerInfo,这个函数的调用需要RIL_Initialize成功初始化后抓到的Handle;

4)需要定义一个符合RILRESULTCALLBACK签名的回调函数,比如我定义的OnResultCallback,来处理调用RIL_GetCellTowerInfo后返回的内容;

到这里其实都是些预备工作,真正的调用过程非常格式化:

5)执行初始化,主要是RIL_Initialize获得一个执行后续函数的Handle,同时设定处理回调数据的函数(OnResultCallback),这里out hRes指示初始化是否成功;

6)以这个Handle为参数,执行具体的Native函数,比如这里的RIL_GetCellTowerInfo

7)执行RIL_Deinitialize并释放5)得到的Handle,当然为避免锁死这里应该用AutoResetEvent

 

总体来说,调用不同RIL ResultCallback函数的过程基本都是5)、6)、7)这三步,差别在于6)用到的RIL函数,以及5)设定的回调函数这两块,很自然的我就考虑能否定义一个泛型方法来实现不同RIL函数的调用。

经过考虑,发现RIL定义的绝大多数数据结构都有非常类似的框架和处理模式,特别是大多数结构的头两项分别是dwSize(有时也叫cbSize)和dwParams,分别存储结构体的长度并指示后续字段是否有效(dwParams其实就是一个基于bit的Flag,bit0指示之后第一个字段的有效性,bit1指示之后第二个。。。)。不过之后的字段比较麻烦,可能有几种不同的类型,主要分别对应CTS的UInt32、Int32、byte[]、String,也有一些可能是枚举或者嵌套的RIL结构体。由于工作初期我关注的是有效显示这些内容,所以在基类里实现ToString就足够了。这样一来,就可以定义一个基类,通过反射机制提取继承类的有效信息,代码如下就不赘述了。

             #region GetCellTowerInfo()
        [StructLayout(LayoutKind.Sequential)]
        public abstract class RilResultStructure
        {
 
            public override string ToString()
            {
                StringBuilder sb = new StringBuilder(500);

                Type theRilType = this.GetType();
                MemberInfo[] members =                  // will return public, non-static, and non-inherited members.
                    theRilType.GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);

                sb.Append(theRilType.Name + "\r\n");
                sb.Append("======================\r\n");


                uint mask = uint.MaxValue;
                int maskPos = 0;
                bool isValid;
                FieldInfo fi;

                for (int i = 0; i < members.Length; i++)
                {
                    MemberTypes memberType = members[i].MemberType;

                    if (memberType == MemberTypes.Field)
                    {
                        fi = members[i] as FieldInfo;

                        switch (members[i].Name)
                        {
                            case "dwSize":
                            case "cbSize":
                                sb.Append(fi.Name + " = " + (uint)fi.GetValue(this) + "\r\n");
                                continue;
                            case "dwParams":
                                mask = (uint)(fi.GetValue(this));
                                maskPos = i;
                                string binStr = Convert.ToString(mask, 2);
                                //string binStr = Convert.ToString(mask, 2).Trim(new char[] { '0' });
                                int count = System.Text.RegularExpressions.Regex.Matches(binStr, "1").Count;
                                sb.Append("dwParams = 0x" + mask.ToString("X2"));
                                sb.Append("\t (" + count + " valid values)\r\n");
                                continue;
                            default:
                                isValid = (mask == uint.MaxValue) ? true : ((mask >> (i - 1 - maskPos)) & 0x01) != 0;
                                if (isValid)
                                {
                                    string typeName = fi.FieldType.Name;

                                    sb.Append(fi.Name + " = ");

                                    switch (typeName)
                                    {
                                        case "UInt32":
                                            uint var = (uint)fi.GetValue(this);
                                            sb.Append(var.ToString());
                                            sb.Append(" [0x" + Convert.ToString(var, 16) + "]\r\n");
                                            break;
                                        case "Int32":
                                            int vari = (int)fi.GetValue(this);
                                            sb.Append(vari.ToString() + "\r\n");
                                            break;
                                        case "Byte[]":
                                            byte[] bytes = (byte[])(fi.GetValue(this));
                                            if (bytes != null)
                                            {
                                                int length = Array.IndexOf<byte>(bytes, 0);
                                                //byte[] unicodeBytes = Encoding.Convert(Encoding.ASCII, Encoding.Unicode, bytes, 0, length);
                                                //char[] chars = Encoding.Unicode.GetChars(unicodeBytes);
                                                char[] chars = Encoding.Default.GetChars(bytes, 0, length);
                                                string content = new string(chars);
                                                sb.Append(content + "\r\n");
                                            }
                                            break;
                                        case "String":
                                            sb.Append((string)(fi.GetValue(this)) + "\r\n");
                                            break;
                                        default:
                                            if (fi.FieldType.IsEnum)
                                            {
                                                sb.Append((fi.GetValue(this)).ToString() + "\r\n");
                                            }
                                            //else if (fi.FieldType.IsArray)
                                            //{
                                            //    object arrays = fi.GetValue(this);
                                            //}
                                            else if (fi.FieldType.IsNestedPublic)
                                            {
                                                if (fi.FieldType.IsClass)
                                                {
                                                    Debug.WriteLine("The nested object shall be struct instead of class: " + fi.FieldType.Name);
                                                    break;
                                                }
                                                sb.Append("\r\n" + fi.GetValue(this).ToString());
                                            }
                                            else
                                            {
                                                sb.Append(fi.FieldType.ToString() + "\r\n");
                                            }
                                            break;
                                    }

                                }
                                break;
                        }                   

                    }
                }

                return sb.ToString();
            }
        }

#endregion

这样一来,不同的Ril结构定义就极大地简化了,以RILCELLTOWERINFO为例,只需要继承自RilResultStructure就OK了。

        #region RIL Cell Tower Info
        // refer to http://msdn.microsoft.com/en-us/library/aa921533.aspx
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public class RILCELLTOWERINFO : RilResultStructure
        {
            public uint cbSize;
            public uint dwParams;
            public uint dwMobileCountryCode;
            public uint dwMobileNetworkCode;
            public uint dwLocationAreaCode;
            public uint dwCellID;
            public uint dwBaseStationID;
            public uint dwBroadcastControlChannel;
            public uint dwRxLevel;
            public uint dwRxLevelFull;
            public uint dwRxLevelSub;
            public uint dwRxQuality;
            public uint dwRxQualityFull;
            public uint dwRxQualitySub;
            public uint dwIdleTimeSlot;
            public uint dwTimingAdvance;
            public uint dwGPRSCellID;
            public uint dwGPRSBaseStationID;
            public uint dwNumBCCH;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = RIL.MAXLENGTH_BCCH)]
            public Byte[] rgbBCCH;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = RIL.MAXLENGTH_NMR)]
            public Byte[] rgbNMR;
        }
        #endregion

由于返回数据继承于同一个基类,实际上回调函数OnResultCallback也就实现基类提供的ToString,就可以把派生类的内容正确显示。于是,我所期望的泛型函数其实只需要一个指向具体RIL Native函数的指针就够了。不过真正实现时,为了表面回调函数处理后的数据结构类型,还是需要提供一个new派生类,存储结果的同时指示OnResultCallback中lpData引用数据的结构。

最终这样一个泛型就实现了5)、6)、7)这三步:

        public static void GenericRilResult<T>(T result, RilResultFuncDelegate rilFuncDel) where T : RilResultStructure, new()
        {
            // Invoke the RIL function stored in rilFunc Delegate
            if (rilFuncDel == null || result == null)
            {
                Debug.WriteLine("Parameter Error.");
                return;
            }

            if (initialize(result))
            {
                IntPtr hRes = rilFuncDel(hRilResult);

                deinitialize();
            }

            return;
        }

 

其中RilResultFuncDelegate 是对绝大多数RIL函数签名的定义:

        public delegate IntPtr RilResultFuncDelegate(IntPtr hRil);    //hRil: Handle to the RIL instance returned by RIL_Initialize.

调用不同RIL函数也就因此能够实现标准化(其中rilResult是一个全局object):

        public static RILCELLTOWERINFO GetCellTowerInfo()
        {
            GenericRilResult(new RILCELLTOWERINFO(), new RilResultFuncDelegate(RIL_GetCellTowerInfo));

            return rilResult as RILCELLTOWERINFO;
        }
        #endregion

要正确显示结果的内容就可以这样:

            textBox1.Text = RIL.GetCellTowerInfo().ToString();

至于有些拥有不同签名的RIL函数,例如RIL_GetCurrentOperator,也可以定义一个类似的泛型函数,大体就差不多了。

 

这么做的结果就是要支持新的RIL函数,基本只需要定义相应的派生于RilResultStructure的数据结构和Native函数原型,然后调用泛型就可以了。

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值