昨天写了短信的发送,今天我们在来谈谈如果读取SIM卡中的短信息,然后将SIM中经过编码的内容进行解码。

首先,我们熟悉几个读取短信的AT命令:



AT+CMGL=0  读取电话上全部未读过的SMS消息



AT+CMGL=2  列出已有的短信息



AT+CMGL=4  读取全部SMS消息



AT+CMGR=X 读取第X条短消息



使用串口工具MCOM,可以调试以上几条命令,具体方法就不谈了。下面谈谈如果完整的读取完缓冲区中所有的短信和如何对短信进行解码



 



1.初始化串口,打开串口


1  
       var serialPort =  
       new SerialPort( 
       " 
       COM6 
       ",  
       115200, Parity.None,  
       8, StopBits.One) 
       
2             { 
       
3                 WriteTimeout =  
       500, 
       
4                 ReadTimeout =  
       5000, 
       
5                 RtsEnable =  
       true, 
       
6                 DtrEnable =  
       true 
       
7             }; 
       
8 
    
AT+CMGF=0\r
 
    
1 serialPort.Write(SMSUtil.GenSendFormatCmd()); 
       
2             Thread.Sleep( 
       500); 
       
3              
       var result = ReadBuffer(serialPort); 
       
4 
    

      3.读取全部的SMS信息: 
     AT+CMGL=4\r 
    
 
    
1 serialPort.Write(SMSUtil.GenGetList(MessageListType.All)); 
       
2             Thread.Sleep( 
       500); 
       
3 
    
4.读取返回接收缓冲区的内容
 
    
这里需要介绍一下接收时的作法,因为之前我试的时候,一直没能接收完整。
 
    
 1  
       /// 
         
       <summary> 
       
 
        2  
                
       /// 
        读取缓冲区的内容
 
        3  
                
       /// 
         
       </summary> 
       
 
        4  
                
       /// 
         
       <param name="serialPort"> 
       The serial port. 
       </param> 
       
 
        5  
                
       /// 
         
       <returns></returns> 
       
 
        6          
       private  
       static  
       string ReadBuffer(SerialPort serialPort) 
       
 7         { 
       
 8              
       var len = serialPort.BytesToRead; 
       
 9              
       var result =  
       new StringBuilder(); 
       
10              
       while (len >  
       0) 
       
11             { 
       
12                  
       var buffer =  
       new  
       byte[len]; 
       
13                 serialPort.Read(buffer,  
       0, len); 
       
14                 result.Append(Encoding.ASCII.GetString(buffer)); 
       
15  
       
16                 Thread.Sleep( 
       500); 
       
17                 len = serialPort.BytesToRead; 
       
18             } 
       
19              
       return result.ToString(); 
       
20 
    

      上面这段代码,采用了循环读取缓冲区的作法,直到返回的字节数为0,则判断当前已经把缓冲区的所有短信读取完毕。这里要注意,在进行下一次读取时,一定要先休眠500毫秒或者更多,否则此时缓冲区中的字节数为0,嗯,这里没时间研究,不知道是什么原因,求大神指点。当然,应该不是缓冲区不足的原因。之前我没有休眠直接读取时,第一次的返回都只能读取一条短信,不超过200字节,然后重新打开串口,就能返回之后的所有短信内容。 
    
 
    

      当然,上面的代码是阻塞式的,效率肯定不高,但是还没想到怎么优化。 
    
 
    

      返回的内容如下: 
    
 
    
AT+CMGF=0 
OK
AT+CMGL=0 
+CMGL: 8,0,,58
0891683108705505F0040D91683115509050F00000217040518530232B207499CD7EB3DA61B93DED66B9DF77103DDD2E83D273900C1693BD6E2F1A2816D3C56A3A180E
+CMGL: 9,0,,57
0891683108705505F0040D91683115509050F00000217040518511232AE8329BFD66B5C3727BDACD72BFEF207ABA5D06A5E720192C267BDD5E34502CA68BD574301C
+CMGL: 10,0,,57
0891683108705505F0040D91683115509050F00000217040518591232AE8329BFD66B5C3727BDACD72BFEF207ABA5D06A5E720192C267BDD5E34502CA68BD574301C第一行的+CMGL:8,0,,58的格式如下:+CMGL:[当前信息在SIM卡中的索引],[是否已读取],,[返回串的字节长度]
第二行为实际的返回串,包括了信息发送服务中心的号码,发送的时间戳,发送者的号码,发送内容等。具体的解码参考下面的代码
 
 
     
 1  
       /// 
         
       <summary> 
       
 
        2  
                
       /// 
        将接收的ASCII码解析为SMSItem
 
        3  
                
       /// 
         
       </summary> 
       
 
        4  
                
       /// 
         
       <param name="src"> 
       The SRC. 
       </param> 
       
 
        5  
                
       /// 
         
       <returns></returns> 
       
 
        6          
       public  
       static SMSItem DecodeSrc( 
       string src) 
       
 7         { 
       
 8              
       var item =  
       new SMSItem(); 
       
 9             item.ServiceCenterNo = PopServiceCenterNo( 
       ref src); 
       // 
       服务中心所在号码
 
       10  
                    
       // 
       pdu类型 
       
 
       11              
       var pduType = PopByte( 
       ref src); 
       
12              
       var bits =  
       new System.Collections.BitArray( 
       new[] { pduType }); 
       
13             item.ReplyPathExists = bits[ 
       7]; 
       // 
       ? 
       
 
       14             item.UserDataStartsWithHeader = bits[ 
       6]; 
       // 
       用户数据区是否具有头部 
       
 
       15             item.StatusReportIndication = bits[ 
       5]; 
       // 
       ? 
       
 
       16             item.ValidityPeriodFormat = (ValidityPeriodFormat)(pduType &  
       0x18); 
       // 
       时间有效性格式 
       
 
       17             item.Direction = (SMSDirection)(pduType &  
       1); 
       // 
       当前内容是提交发送的还是接收到的 
       
 
       18  
       
19              
       if (item.Direction == SMSDirection.Submited) item.MessageReference = PopByte( 
       ref src); 
       // 
       如果是提交的,该字节为信息类型(TP-Message-Reference) 
       
 
       20             item.SenderNo = PopSenderNo( 
       ref src); 
       
21             item.ProtocolIdentifier = PopByte( 
       ref src); 
       // 
       协议标识TP-PID 
       
 
       22             item.DataCodingScheme = PopByte( 
       ref src); 
       // 
       数据编码方案TP-DCS(TP-Data-Coding-Scheme) 
       
 
       23  
       
24              
       if (item.Direction == SMSDirection.Submited) 
       
25             { 
       // 
       如果是提交的信息,则该字节为数据的有效性 
       
 
       26                 item.SetValidityPeriod(PopByte( 
       ref src)); 
       
27             } 
       
28              
       else 
       
29             { 
       // 
       如果是接收的,则表示信息中心发送短信的时间 
       
 
       30                 item.ServiceCenterTimeStamp = PopDate( 
       ref src); 
       
31             } 
       
32  
       
33             item.UserData = src; 
       // 
       未解码的用户数据区 
       
 
       34              
       if ( 
       string.IsNullOrEmpty(src))  
       return item; 
       
35  
       
36              
       int userDataLength = PopByte( 
       ref src); 
       // 
       用户数据区长度 
       
 
       37              
       if (userDataLength ==  
       0)  
       return item; 
       
38  
       
39              
       if (item.UserDataStartsWithHeader) 
       
40             { 
       
41                  
       var userDataHeaderLength = PopByte( 
       ref src); 
       
42                 item.UserDataHeader = PopBytes( 
       ref src, userDataHeaderLength); 
       
43                 userDataLength -= userDataHeaderLength +  
       1; 
       
44             } 
       
45  
       
46              
       if (userDataLength ==  
       0)  
       return item; 
       
47  
       
48              
       switch ((SMSEncoding)item.DataCodingScheme & SMSEncoding.ReservedMask) 
       
49             { 
       // 
       根据不同的编码方案进行解码 
       
 
       50                  
       case SMSEncoding._7Bit: 
       
51                     item.Message = Decode7Bit(src, userDataLength); 
       
52                      
       break; 
       
53                  
       case SMSEncoding._8Bit: 
       
54                     item.Message = Decode8Bit(src, userDataLength); 
       
55                      
       break; 
       
56                  
       case SMSEncoding.UCS2: 
       
57                     item.Message = DecodeUCS2(src, userDataLength); 
       
58                      
       break; 
       
59             } 
       
60  
       
61              
       return item; 
       
62 
     
下面是上述解码函数中设计的操作方法:
 
 
     
  1  
       #region 解析接收串 
       
  2          
       /// 
         
       <summary> 
       
 
         3  
                
       /// 
        把Source中的第一个字节(16进制)移除,并转化为Byte类型
 
         4  
                
       /// 
         
       </summary> 
       
 
         5  
                
       /// 
         
       <param name="source"> 
       The source. 
       </param> 
       
 
         6  
                
       /// 
         
       <returns></returns> 
       
 
         7          
       private  
       static  
       byte PopByte( 
       ref  
       string source) 
       
  8         { 
       
  9              
       var b = Convert.ToByte(source.Substring( 
       0,  
       2),  
       16); 
       
 10             source = source.Substring( 
       2); 
       
 11  
       
 12              
       return b; 
       
 13         } 
       
 14  
       
 15          
       /// 
         
       <summary> 
       
 
        16  
                
       /// 
        把Source中的指定长度的字节(16进制)移除,并转化为Byte数组
 
        17  
                
       /// 
         
       </summary> 
       
 
        18  
                
       /// 
         
       <param name="source"> 
       The source. 
       </param> 
       
 
        19  
                
       /// 
         
       <param name="length"> 
       The length. 
       </param> 
       
 
        20  
                
       /// 
         
       <returns></returns> 
       
 
        21          
       public  
       static  
       byte[] PopBytes( 
       ref  
       string source,  
       int length) 
       
 22         { 
       
 23              
       var bytes = source.Substring( 
       0, length *  
       2); 
       
 24             source = source.Substring(length *  
       2); 
       
 25  
       
 26              
       return GetBytes(bytes,  
       16); 
       
 27         } 
       
 28  
       
 29          
       /// 
         
       <summary> 
       
 
        30  
                
       /// 
        把Source中的服务中心部分的字符串移除,正常的电话号码类型
 
        31  
                
       /// 
         
       </summary> 
       
 
        32  
                
       /// 
         
       <param name="source"> 
       The source. 
       </param> 
       
 
        33  
                
       /// 
         
       <returns></returns> 
       
 
        34          
       private  
       static  
       string PopServiceCenterNo( 
       ref  
       string source) 
       
 35         { 
       
 36              
       var addrLen = PopByte( 
       ref source); 
       // 
       地址的长度(指示字节个数) 
       
 
        37              
       return addrLen ==  
       0 ?  
       string.Empty : PopPhoneNo( 
       ref source, addrLen *  
       2); 
       
 38         } 
       
 39  
       
 40          
       /// 
         
       <summary> 
       
 
        41  
                
       /// 
        把Source中的发送者的号码部分的字符串移除,正常的电话号码类型
 
        42  
                
       /// 
         
       </summary> 
       
 
        43  
                
       /// 
         
       <param name="source"> 
       The source. 
       </param> 
       
 
        44  
                
       /// 
         
       <returns></returns> 
       
 
        45          
       private  
       static  
       string PopSenderNo( 
       ref  
       string source) 
       
 46         { 
       
 47              
       int addrLen = PopByte( 
       ref source); 
       
 48  
       
 49              
       return (addrLen = addrLen +  
       2) ==  
       2 
       
 50                 ?  
       string.Empty : 
       
 51                 PopPhoneNo( 
       ref source, addrLen + (addrLen %  
       2)); 
       
 52         } 
       
 53  
       
 54          
       /// 
         
       <summary> 
       
 
        55  
                
       /// 
        把Source中的指定长度的字符串移除,并转化为正常的电话号码类型
 
        56  
                
       /// 
         
       </summary> 
       
 
        57  
                
       /// 
         
       <param name="source"> 
       The source. 
       </param> 
       
 
        58  
                
       /// 
         
       <param name="length"> 
       The length. 
       </param> 
       
 
        59  
                
       /// 
         
       <returns></returns> 
       
 
        60          
       private  
       static  
       string PopPhoneNo( 
       ref  
       string source,  
       int length) 
       
 61         { 
       
 62              
       var address = source.Substring( 
       0, length); 
       
 63             source = source.Substring(address.Length); 
       
 64  
       
 65              
       var addressType = PopByte( 
       ref address); 
       
 66             address = SwapOddEven(address).Trim( 
       ' 
       F 
       '); 
       
 67  
       
 68              
       if ( 
       0x09 == addressType >>  
       4) address =  
       " 
       + 
       " + address; 
       
 69  
       
 70              
       return address; 
       
 71         } 
       
 72  
       
 73          
       /// 
         
       <summary> 
       
 
        74  
                
       /// 
        把Source中的前面表示时间的字符串移除,并转化为正常的时间格式
 
        75  
                
       /// 
         
       </summary> 
       
 
        76  
                
       /// 
         
       <param name="source"> 
       The source. 
       </param> 
       
 
        77  
                
       /// 
         
       <returns></returns> 
       
 
        78          
       private  
       static DateTime PopDate( 
       ref  
       string source) 
       
 79         { 
       
 80              
       var bytes = GetBytes(SwapOddEven(source.Substring( 
       0,  
       12)),  
       10); 
       
 81  
       
 82             source = source.Substring( 
       14); 
       
 83  
       
 84              
       return  
       new DateTime( 
       2000 + bytes[ 
       0], bytes[ 
       1], bytes[ 
       2], bytes[ 
       3], bytes[ 
       4], bytes[ 
       5]); 
       
 85         } 
       
 86  
       
 87          
       /// 
         
       <summary> 
       
 
        88  
                
       /// 
        把某10进制或者16进制的字符串转换为byte数组
 
        89  
                
       /// 
         
       </summary> 
       
 
        90  
                
       /// 
         
       <param name="source"> 
       字符串 
       </param> 
       
 
        91  
                
       /// 
         
       <param name="fromBase"> 
       进制数,10或者16 
       </param> 
       
 
        92  
                
       /// 
         
       <returns></returns> 
       
 
        93          
       private  
       static  
       byte[] GetBytes( 
       string source,  
       int fromBase) 
       
 94         { 
       
 95              
       var bytes =  
       new List< 
       byte>(); 
       
 96  
       
 97              
       for ( 
       var i =  
       0; i < source.Length /  
       2; i++) 
       
 98             { 
       
 99                 bytes.Add(Convert.ToByte(source.Substring(i *  
       2,  
       2), fromBase)); 
       
100             } 
       
101  
       
102              
       return bytes.ToArray(); 
       
103         } 
       
104  
       
105          
       /// 
         
       <summary> 
       
 
       106  
                
       /// 
        Decode8s the bit.
 
       107  
                
       /// 
         
       </summary> 
       
 
       108  
                
       /// 
         
       <param name="source"> 
       The source. 
       </param> 
       
 
       109  
                
       /// 
         
       <param name="length"> 
       The length. 
       </param> 
       
 
       110  
                
       /// 
         
       <returns></returns> 
       
 
       111          
       private  
       static  
       string Decode8Bit( 
       string source,  
       int length) 
       
112         { 
       
113              
       // 
       or ASCII? 
       
 
       114              
       return Encoding.UTF8.GetString(GetBytes(source.Substring( 
       0, length *  
       2),  
       16)); 
       
115         } 
       
116  
       
117          
       /// 
         
       <summary> 
       
 
       118  
                
       /// 
        Decodes the UCS2.
 
       119  
                
       /// 
         
       </summary> 
       
 
       120  
                
       /// 
         
       <param name="source"> 
       The source. 
       </param> 
       
 
       121  
                
       /// 
         
       <param name="length"> 
       The length. 
       </param> 
       
 
       122  
                
       /// 
         
       <returns></returns> 
       
 
       123          
       private  
       static  
       string DecodeUCS2( 
       string source,  
       int length) 
       
124         { 
       
125              
       return Encoding.BigEndianUnicode.GetString(GetBytes(source.Substring( 
       0, length *  
       2),  
       16)); 
       
126         } 
       
127  
       
128          
       /// 
         
       <summary> 
       
 
       129  
                
       /// 
        Decode7s the bit.
 
       130  
                
       /// 
         
       </summary> 
       
 
       131  
                
       /// 
         
       <param name="source"> 
       The source. 
       </param> 
       
 
       132  
                
       /// 
         
       <param name="length"> 
       The length. 
       </param> 
       
 
       133  
                
       /// 
         
       <returns></returns> 
       
 
       134          
       private  
       static  
       string Decode7Bit( 
       string source,  
       int length) 
       
135         { 
       
136              
       var bytes = GetInvertBytes(source); 
       
137  
       
138              
       var temp =  
       new StringBuilder(); 
       
139              
       foreach ( 
       var b  
       in bytes) temp.Append(Convert.ToString(b,  
       2).PadLeft( 
       8,  
       ' 
       0 
       ')); 
       
140              
       var binary = temp.ToString().PadRight(length *  
       7,  
       ' 
       0 
       '); 
       // 
       转换为2进制,不足在右边补0 
       
 
       141  
       
142             temp.Clear(); 
       
143              
       for ( 
       var i =  
       1; i <= length; i++) temp.Append(( 
       char)Convert.ToByte(binary.Substring(binary.Length - i *  
       7,  
       7),  
       2)); 
       
144  
       
145              
       return temp.ToString().Replace( 
       ' 
       \x0 
       ',  
       ' 
       \x40 
       '); 
       
146         } 
       
147  
       
148          
       /// 
         
       <summary> 
       
 
       149  
                
       /// 
        把字符串(16进制)转换为byte数组,并反转
 
       150  
                
       /// 
         
       </summary> 
       
 
       151  
                
       /// 
         
       <param name="source"> 
       The source. 
       </param> 
       
 
       152  
                
       /// 
         
       <returns></returns> 
       
 
       153          
       private  
       static IEnumerable< 
       byte> GetInvertBytes( 
       string source) 
       
154         { 
       
155              
       var bytes = GetBytes(source,  
       16); 
       
156             Array.Reverse(bytes); 
       
157              
       return bytes; 
       
158         } 
       
159          
       #endregion 
     
 
最后是信息内容的封装类:
 
 
     
  1  
       public  
       class SMSItem 
       
  2     { 
       
  3          
       /// 
         
       <summary> 
       
 
         4  
                
       /// 
        服务中心的号码
 
         5  
                
       /// 
         
       </summary> 
       
 
         6  
                
       /// 
         
       <value> 
       The service center no. 
       </value> 
       
 
         7          
       public  
       string ServiceCenterNo {  
       get;  
       set; } 
       
  8          
       /// 
         
       <summary> 
       
 
         9  
                
       /// 
        服务中心发送的时间戳
 
        10  
                
       /// 
         
       </summary> 
       
 
        11  
                
       /// 
         
       <value> 
       The service center time stamp. 
       </value> 
       
 
        12          
       public DateTime ServiceCenterTimeStamp {  
       get;  
       set; } 
       
 13          
       /// 
         
       <summary> 
       
 
        14  
                
       /// 
        发送者的电话号码
 
        15  
                
       /// 
         
       </summary> 
       
 
        16  
                
       /// 
         
       <value> 
       The sender no. 
       </value> 
       
 
        17          
       public  
       string SenderNo {  
       get;  
       set; } 
       
 18          
       public  
       bool ReplyPathExists {  
       get;  
       set; } 
       
 19          
       /// 
         
       <summary> 
       
 
        20  
                
       /// 
        用户数据区是否以报文头开始
 
        21  
                
       /// 
         
       </summary> 
       
 
        22  
                
       /// 
         
       <value> 
       
 
        23  
                
       /// 
             
       <c> 
       true 
       </c> 
        if [user data starts with header]; otherwise,  
       <c> 
       false 
       </c> 
       .
 
        24  
                
       /// 
         
       </value> 
       
 
        25          
       public  
       bool UserDataStartsWithHeader {  
       get;  
       set; } 
       
 26          
       public  
       bool StatusReportIndication {  
       get;  
       set; } 
       
 27          
       public TimeSpan ValidityPeriod {  
       get;  
       set; } 
       
 28          
       /// 
         
       <summary> 
       
 
        29  
                
       /// 
        时间有效性格式
 
        30  
                
       /// 
         
       </summary> 
       
 
        31  
                
       /// 
         
       <value> 
       The validity period format. 
       </value> 
       
 
        32          
       public ValidityPeriodFormat ValidityPeriodFormat {  
       get;  
       set; } 
       
 33          
       /// 
         
       <summary> 
       
 
        34  
                
       /// 
        当前报文是提交发送的还是接收到的
 
        35  
                
       /// 
         
       </summary> 
       
 
        36  
                
       /// 
         
       <value> 
       The direction. 
       </value> 
       
 
        37          
       public SMSDirection Direction {  
       get;  
       set; } 
       
 38  
       
 39          
       public  
       byte MessageReference {  
       get;  
       set; } 
       
 40          
       public  
       byte ProtocolIdentifier {  
       get;  
       set; } 
       
 41  
       
 42          
       /// 
         
       <summary> 
       
 
        43  
                
       /// 
        用户数据编码格式
 
        44  
                
       /// 
         
       </summary> 
       
 
        45  
                
       /// 
         
       <value> 
       The data coding scheme. 
       </value> 
       
 
        46          
       public  
       byte DataCodingScheme {  
       get;  
       set; } 
       
 47          
       /// 
         
       <summary> 
       
 
        48  
                
       /// 
        用户数据头
 
        49  
                
       /// 
         
       </summary> 
       
 
        50  
                
       /// 
         
       <value> 
       The user data header. 
       </value> 
       
 
        51          
       public  
       byte[] UserDataHeader {  
       get;  
       set; } 
       
 52          
       /// 
         
       <summary> 
       
 
        53  
                
       /// 
        用户数据(未解码)
 
        54  
                
       /// 
         
       </summary> 
       
 
        55  
                
       /// 
         
       <value> 
       The user data. 
       </value> 
       
 
        56          
       public  
       string UserData {  
       get;  
       set; } 
       
 57          
       /// 
         
       <summary> 
       
 
        58  
                
       /// 
        用户短信的内容
 
        59  
                
       /// 
         
       </summary> 
       
 
        60  
                
       /// 
         
       <value> 
       The message. 
       </value> 
       
 
        61          
       public  
       string Message {  
       get;  
       set; } 
       
 62  
       
 63          
       #region Methods 
       
 64          
       /// 
         
       <summary> 
       
 
        65  
                
       /// 
        设置时间验证格式
 
        66  
                
       /// 
         
       </summary> 
       
 
        67  
                
       /// 
         
       <param name="v"> 
       The v. 
       </param> 
       
 
        68          
       public  
       void SetValidityPeriod( 
       byte v) 
       
 69         { 
       
 70              
       if (v >  
       196) ValidityPeriod =  
       new TimeSpan((v -  
       192) *  
       7,  
       0,  
       0,  
       0); 
       
 71              
       else  
       if (v >  
       167) ValidityPeriod =  
       new TimeSpan((v -  
       166),  
       0,  
       0,  
       0); 
       
 72              
       else  
       if (v >  
       143) ValidityPeriod =  
       new TimeSpan( 
       12, (v -  
       143) *  
       30,  
       0); 
       
 73              
       else ValidityPeriod =  
       new TimeSpan( 
       0, (v +  
       1) *  
       5,  
       0); 
       
 74         } 
       
 75          
       /// 
         
       <summary> 
       
 
        76  
                
       /// 
        设置时间验证格式
 
        77  
                
       /// 
         
       </summary> 
       
 
        78  
                
       /// 
         
       <param name="v"> 
       The v. 
       </param> 
       
 
        79          
       public  
       void SetValidityPeriod(TimeSpan v) 
       
 80         { 
       
 81              
       if (v.Days >  
       441) 
       
 82                  
       throw  
       new ArgumentOutOfRangeException( 
       " 
       TimeSpan.Days 
       ", v.Days,  
       " 
       Value must be not greater 441 days. 
       "); 
       
 83  
       
 84              
       if (v.Days >  
       30)  
       // 
       Up to 441 days 
       
 
        85                 SetValidityPeriod(( 
       byte)( 
       192 + v.Days /  
       7)); 
       
 86              
       else  
       if (v.Days >  
       1)  
       // 
       Up to 30 days 
       
 
        87                 SetValidityPeriod(( 
       byte)( 
       166 + v.Days)); 
       
 88              
       else  
       if (v.Hours >  
       12)  
       // 
       Up to 24 hours 
       
 
        89                 SetValidityPeriod(( 
       byte)( 
       143 + (v.Hours -  
       12) *  
       2 + v.Minutes /  
       30)); 
       
 90              
       else  
       if (v.Hours >  
       1 || v.Minutes >  
       1)  
       // 
       Up to 12 days 
       
 
        91                 SetValidityPeriod(( 
       byte)(v.Hours *  
       12 + v.Minutes /  
       5 -  
       1)); 
       
 92              
       else 
       
 93             { 
       
 94                 ValidityPeriodFormat = ValidityPeriodFormat.FieldNotPresent; 
       
 95                  
       return; 
       
 96             } 
       
 97  
       
 98             ValidityPeriodFormat = ValidityPeriodFormat.Relative; 
       
 99         } 
       
100          
       #endregion 
       
101