S19文件及mot文件解析


S19文件格式与mot文件类似,这里以S19文件为例

S19文件每一行数据全部由记录类型和十六进制数字组成,包含类型、长度、地址、数据和校验和五个部分。

上图中“S3”为类型,“25”为长度,意味着整行记录(除类型和长度)总共有37字节(74字符),“00008020”为该记录起始地址,

“000003E80004BAF00003D090000000000003345000061A8000035B6000061A80”为数据,共有32字节(64字符)数据,“B9”为校验和;

此行就是将数据依次刷写到起始地址为“00008020”的连续地址中

每字节数据被编码成2个16进制字符,第一个字符代表数据的高四位,第二个字符代表数据的低4位。

 

1.类型

S19中记录类型包括S0、S1、S2、S3、S5、S7、S8、S9等

S0,位于文件的第一行,和其他行不同,地址部分没有使用,用0000置位,整行表示记录的开始

 

“S00600004844521B”中“484452”为文件路径,“1B”为校验和

S1表示地址长度为两字节(4字符)的记录,包含类型、长度、地址、数据和校验和五个部分

S2表示地址长度为三字节(6字符)的记录,包含类型、长度、地址、数据和校验和五个部分

S3表示地址长度为四字节(8字符)的记录,包含类型、长度、地址、数据和校验和五个部分

S5表示文件中含有S1、S2、S3记录的个数,其后不接数据,包含S5的记录并不是每个文件必须的

S7表示地址长度为四字节(8字符)的记录,包含类型、长度、地址和校验和四个部分,此行表示程序的结束

S8表示地址长度为三字节(6字符)的记录,包含类型、长度、地址和校验和四个部分,此行表示程序的结束

S9表示地址长度为两字节(4字符)的记录,包含类型、长度、地址和校验和四个部分,此行表示程序的结束

只有S1、S2、S3、S5需要写入Flash中

“S50300807C”中“03”表示S3的记录。“0080”表示含有128行的S3记录

“S7050000000FA”表示结束

 

2.长度

包含一个字节(两个字符),长度=地址字节数+数据字节数+校验和字节数

 

3.地址

表示该行的其实地址,字节数由类型决定,S1位两个字节,S2为三个字节,S3位四个字节

 

4.数据

包含0-32个字节

 

5.校验和

包含一个字节,校验和=0xFF-长度字节-地址字节-数据字节

 0x25+0x00+0x00+0x80+0x20+0x00+0x00+...+0x1A+0x80=0x746

取46,0xFF-0x46=0xB9

 

6.读写修改S19文件代码 

 

如有错误,欢迎指正

 

  1 public class S19
  2     {
  3         public string path;                                    //选择文件的路径
  4         public List<string> listAllline;                     //存储所有的记录包括(S0、S5等)
  5 
  6 
  7         /// <summary>
  8         /// 读取S19文件,将所有记录存储在List中,便于调用修改
  9         /// </summary>
 10         /// <param name="file_path"></param>
 11         public bool Read_S19(string file_path)
 12         {
 13             int line = 0;                                      //记录当前读取的行数
 14             FileStream File_Stream = null;
 15             StreamReader Stream_Reader = null;
 16             try
 17             {
 18                 path = file_path;
 19                 File_Stream = new FileStream(this.path, FileMode.Open, FileAccess.Read);
 20                 Stream_Reader = new StreamReader(File_Stream, Encoding.Default);
 21                 listAllline = new List<string>();
 22                 while (true)
 23                 {
 24                     line++;
 25                     string str = Stream_Reader.ReadLine();      //一行一行读取数据
 26                     if (str == null || str.Trim().Length == 0)
 27                     {
 28                         break;
 29                     }
 30                     listAllline.Add(str.Trim());
 31                 }
 32               
 33                 Console.WriteLine("文件中共有" + line + "行数据");
 34                 return true;
 35             }
 36             catch (Exception ex)
 37             {
 38                 Console.WriteLine(ex.ToString() + line);
 39                 return false;
 40             }
 41             finally
 42             {
 43                 File_Stream.Close();
 44                 Stream_Reader.Close();
 45             }
 46         }
 47 
 48         /// <summary>
 49         /// 依据地址和数据修改S19文件
 50         /// </summary>
 51         /// <param name="startAdd"></param>
 52         /// <param name="modifyStr"></param>
 53         /// <returns></returns>
 54         public bool Modify_S19(uint startAdd, string modifyStr)
 55         {
 56             try
 57             {
 58                 List<string> listTemp = new List<string>();
 59                 foreach (var item in listAllline)
 60                 {
 61                     listTemp.Add(item);
 62                 }
 63                 listAllline.Clear();
 64 
 65                 string lineData = " ";                                 //当前行数据
 66                 int line = 0;                                          //当前行数
 67                 int modifyLen = modifyStr.Length;                      //修改的数据长度,判断修改是否完成
 68 
 69                 if (path.Substring(path.Length - 4, 4) == ".s19" || path.Substring(path.Length - 4, 4) == ".S19")
 70                 {
 71                     while (lineData != null)
 72                     {
 73                         if (lineData.Length >= 10)                    //跳过非记录数据,所有记录数据中最短S5包含10个字符
 74                         {
 75                             if (lineData.Substring(0, 2) == "S3")     //选择S3记录
 76                             {
 77                                 uint currentAdd = Convert.ToUInt32(lineData.Substring(4, 8), 16);            //当前行记录中包含的地址
 78                                 if (startAdd >= currentAdd && Convert.ToUInt32(startAdd - currentAdd) < Convert.ToUInt32(lineData.Substring(2, 2), 16) - 5)//找到需要修改的数据的起始地址所在行
 79                                 {
 80                                     while (modifyLen > 0)
 81                                     {
 82                                         currentAdd = Convert.ToUInt32(lineData.Substring(4, 8), 16);
 83                                         int differenceAdd = Convert.ToInt32(startAdd - currentAdd);          //一行中需修改的起始地址之前的数据地址
 84                                         int modifyAdd = Convert.ToInt32(lineData.Substring(2, 2), 16) * 2 - 10 - differenceAdd * 2;//每行中需要修改的数据长度
 85 
 86                                         if (Convert.ToInt32(lineData.Substring(2, 2), 16) - 5 - differenceAdd >= modifyLen / 2)//判断需要修改的数据地址是不是在同一行,5 = 地址4字节+校验位1字节
 87                                         {
 88                                             string str1 = lineData.Remove(12 + (differenceAdd) * 2, modifyLen);//从修改的起始地址位置开始移除旧数据,长度为需要修改的数据长度,12 = 类型2字符+长度2字符+地址8字符
 89                                             string str2 = str1.Insert(12 + (differenceAdd) * 2, modifyStr);//将新数据插入当前记录行
 90                                             string sum_string = Checksum(str2.Remove(str2.Length - 2));//计算新的校验位字节
 91                                             lineData = str2.Remove(str2.Length - 2, 2) + sum_string;//移除旧校验位,加入新校验位
 92                                             modifyLen = modifyLen - modifyAdd;//正常情况下,修改的数据地址在同一行,此时计算之后modifyLen=0,跳出循环
 93                                         }
 94                                         else                 //地址不在同一行
 95                                         {
 96                                             string str1 = lineData.Remove(12 + (differenceAdd) * 2, Convert.ToInt32(lineData.Substring(2, 2), 16) * 2 - 10 - differenceAdd * 2);//移除地址后面的所有数据和校验位
 97                                             string str2 = str1.Insert(12 + (differenceAdd) * 2, modifyStr.Substring(0, (Convert.ToInt32(lineData.Substring(2, 2), 16) - 5 - (differenceAdd)) * 2));//加入新数据
 98                                             string sum_string = Checksum(str2.Remove(str2.Length - 2));
 99                                             lineData = str2.Remove(str2.Length - 2, 2) + sum_string;
100                                             modifyLen = modifyLen - modifyAdd;//计算剩余需要修改的数据长度
101                                             modifyStr = modifyStr.Remove(0, modifyAdd);//移除已经修改的数据
102                                             startAdd = startAdd + (Convert.ToUInt32(lineData.Substring(2, 2), 16) - 5 - Convert.ToUInt32(differenceAdd));//计算剩余数据的起始地址
103                                         }
104                                         listAllline.Add(lineData);//将修改好的或者不许修改的记录行存入list
105                                         if (line == listTemp.Count)
106                                         {
107                                             break;
108                                         }
109                                         lineData = listTemp[line];//提取新的记录行
110                                         line++;
111                                     }
112                                 }
113                             }
114                             listAllline.Add(lineData);
115                         }
116                         if (line == listTemp.Count)//判断是否到最后一行
117                         {
118                             break;
119                         }
120                         lineData = listTemp[line];
121                         line++;
122                     }
123                 }
124 
125             }
126             catch (Exception ex)
127             {
128                 MessageBox.Show(ex.ToString());
129                 return false;
130             }
131 
132             return true;
133         }
134 
135         /// <summary>
136         /// 计算一行数据的校验和
137         /// </summary>
138         /// <param name="line"> 不包含校验位的行数据</param>
139         /// <returns></returns>
140         private string Checksum(string line)
141         {
142             string checkSum = null;
143             int sum = 0;
144             string[] byteNum = new string[line.Length / 2];//计算字节数
145             for (int i = 1; i < line.Length / 2; i++)
146             {
147                 byteNum[i] = line.Substring(i * 2, 2);//从长度位将一行数据按照字节分割为字节数组
148                 sum += Convert.ToInt32(byteNum[i], 16);//将数据进行累加
149             }
150 
151             string check = Convert.ToString(255 - sum, 16); //计算校验位
152             checkSum = check.Substring(check.Length - 2, 2).ToUpper();//校验位字节
153             return checkSum;
154 
155         }
156 
157         /// <summary>
158         /// 生成新的S19文件
159         /// </summary>
160         /// <param name="newFilepath"></param>
161         /// <returns></returns>
162         public bool Write_S19(string newFilepath)
163         {
164             StreamWriter Stream_Writer =null;
165             try
166             {
167                 string[] allLineArray = listAllline.ToArray();
168                 Stream_Writer = new StreamWriter(newFilepath + ".s19", false);
169                 int lines = listAllline.Count;
170 
171                 while (lines != 0)
172                 {
173                     Stream_Writer.WriteLine(allLineArray[listAllline.Count - lines]);
174                     lines--;
175                 }
176                 return true;
177             }
178             catch(Exception ex)
179             {
180                 Console.WriteLine(ex.Message );
181                 return false;
182             }
183             finally
184             {
185                 Stream_Writer.Close();
186             }
187 
188         }
189 
190         /// <summary>
191         /// 检查每行记录数据是否有缺失
192         /// </summary>
193         /// <returns></returns>
194         public bool CompleteCheck()
195         {
196             string currentLine = string.Empty ;
197             string type = string.Empty;
198             string length = string.Empty;
199             string address = string.Empty;
200             int dataLen;
201             int currentLineLen;
202             for (int i = 0; i < listAllline .Count; i++)
203             {
204                 currentLine = listAllline[i];
205                 if (currentLine.Length >= 10)
206                 {
207                     type = currentLine.Substring(0, 2);
208                     if(type=="S1" || type == "S2"|| type == "S3")
209                     {
210                         length = currentLine.Substring(2, 2);
211                         switch (type)
212                         {
213                             case "S1":
214                                 address = currentLine.Substring(4, 4);
215                                 dataLen = Convert.ToInt32(length, 16) - 6;
216                                 currentLineLen = currentLine.Length - 10;
217                                 if (dataLen != currentLineLen)
218                                 {
219                                     Console.WriteLine("" + (i + 1) + "行数据缺失");
220                                     return false;
221                                 }
222                                 break;
223                             case "S2":
224                                 address = currentLine.Substring(4, 6);
225                                 dataLen = Convert.ToInt32(length, 16) - 8;
226                                 currentLineLen = currentLine.Length - 12;
227                                 if (dataLen != currentLineLen)
228                                 {
229                                     Console.WriteLine("" + (i + 1) + "行数据缺失");
230                                     return false;
231                                 }
232                                 break;
233                             case "S3":
234                                 address = currentLine.Substring(4, 8);
235                                 dataLen = Convert.ToInt32(length, 16) - 10;
236                                 currentLineLen = currentLine.Length - 14;
237                                 if (dataLen != currentLineLen)
238                                 {
239                                     Console.WriteLine("" + (i + 1) + "行数据缺失");
240                                     return false;
241                                 }
242                                 break;
243                             default:
244                                 break;
245                         }
246                     }
247                     
248                 }
249             }
250             return true;
251         }
252 
253 
254         /// <summary>
255         /// 检查记录地址连续性 并提取每行记录的地址,判断每个区间起始地址是否正确
256         /// </summary>
257         /// <param name="startAdd">包含每个区间的起始地址</param>
258         /// <param name="addList">返回所有记录地址</param>
259         /// <returns></returns>
260         public bool RecordStartAdd(string[] startAdd,ref List<string> addList)
261         {
262             bool firstLine = true;                                   //判断文件第一行记录
263             int addLen = 0;                                          //S19记录地址长度s3为4字节,s2为三字节,s1为两字节
264             uint currentAdd = 0;
265             uint dataLength = 0 ;
266             uint lastDataLength = 0;
267             uint lastAdd = 0;
268             int index = 0;
269 
270             foreach (string currentLine in listAllline)
271             {
272                 if (currentLine.Length < 10)
273                 {
274                     continue;
275                 }
276                 else
277                 {
278                     if (currentLine.Substring(0, 2) == "S0")//跳过不需刷写的记录行
279                     {
280                         continue;
281                     }
282                     switch (currentLine.Substring(0, 2))
283                     {
284                         case "S1":
285                             addLen = 2;
286                             break;
287                         case "S2":
288                             addLen = 3;
289                             break;
290                         case "S3":
291                             addLen = 4;
292                             break;
293                         default:
294                             addLen = 4;
295                             break;
296                     }
297                     if (firstLine)
298                     {
299                         if(currentLine.Substring(4, addLen * 2)!=startAdd [index])//检查第一行记录起始地址是否错误
300                         {
301                             Console.WriteLine(""+ index +"区间起始地址错误");
302                             addList.Clear();
303                             return false;
304                         }
305                         addList.Add(currentLine.Substring(4, addLen * 2));                     //取出第一行记录起始地址
306                         firstLine = false;
307                         currentAdd = Convert.ToUInt32(currentLine.Substring(4, addLen * 2), 16);      //本行文件开始地址
308                         dataLength = Convert.ToUInt32(currentLine.Substring(2, 2), 16) - Convert.ToUInt32(addLen) - 1;
309                         continue;
310                     }
311 
312                     if (currentLine.Substring(0, 2) == "S7" || currentLine.Substring(0, 2) == "S8" || currentLine.Substring(0, 2) == "S9")//记录结束
313                     {
314                         break;
315                     }
316 
317                     lastAdd = currentAdd;                                                        //记录上一行地址
318                     lastDataLength = dataLength;                                                 //记录上一行数据长度
319                     currentAdd = Convert.ToUInt32(currentLine.Substring(4, addLen * 2), 16);      //本行文件开始地址
320                     dataLength = Convert.ToUInt32(currentLine.Substring(2, 2), 16) - Convert.ToUInt32(addLen) - 1;
321 
322                     if(lastAdd + lastDataLength == currentAdd)//判断相邻行地址是否连续
323                     {
324                         addList.Add(Convert.ToString(lastAdd + lastDataLength, 16).PadLeft(8, '0').ToUpper());   //依据上一行记录的地址和长度计算出当前行的地址,存入list
325                     }
326                     else  //不连续意味着大区间地址结束,继续下一个大区间起始地址
327                     {
328                         index++;
329                         if (currentLine.Substring(4, addLen * 2) != startAdd[index]) //检查每个区间起始地址是否错误
330                         {
331                             Console.WriteLine("" + index + "区间起始地址错误");
332                             addList.Clear();
333                             return false;
334                         }
335                         addList.Add(Convert.ToString(currentAdd, 16).PadLeft(8, '0').ToUpper());
336                     }
337                 }
338             }
339             return true;
340         }
341         
342 
343         /// <summary>
344         /// 记录每个区间第一行及它们的起始位置和起始地址
345         /// </summary>
346         /// <param name="intervalList"></param>
347         /// <returns></returns>
348         public Dictionary<int,string>  RecordInterval(ref List<string> intervalList)
349         {
350             Dictionary<int, string> intervaiDic = new Dictionary<int, string>();
351             bool firstLine = true;                                   //判断文件第一行记录
352             int addLen = 0;                                          //S19记录地址长度s3为4字节,s2为三字节,s1为两字节
353             uint currentAdd = 0;
354             uint dataLength = 0;
355             uint lastDataLength = 0;                                 //上一行数据长度
356             uint lastAdd = 0;                                        //上一行地址
357             int index = 0;                                           //当前行数
358 
359             foreach (string currentLine in listAllline)
360             {
361                 index++;
362                 if (currentLine.Length < 10)
363                 {
364                     continue;
365                 }
366                 else
367                 {
368                     if (currentLine.Substring(0, 2) == "S0")//跳过不需刷写的记录行
369                     {
370                         continue;
371                     }
372                     switch (currentLine.Substring(0, 2))
373                     {
374                         case "S1":
375                             addLen = 2;
376                             break;
377                         case "S2":
378                             addLen = 3;
379                             break;
380                         case "S3":
381                             addLen = 4;
382                             break;
383                         default:
384                             addLen = 4;
385                             break;
386                     }
387                     if (firstLine)
388                     {
389                         firstLine = false;
390                         intervaiDic.Add(index, currentLine.Substring(4, addLen * 2));
391                         intervalList.Add(currentLine.Substring(4, addLen * 2));
392                         currentAdd = Convert.ToUInt32(currentLine.Substring(4, addLen * 2), 16);      //本行文件开始地址
393                         dataLength = Convert.ToUInt32(currentLine.Substring(2, 2), 16) - Convert.ToUInt32(addLen) - 1;
394                         continue;
395                     }
396 
397                     if (currentLine.Substring(0, 2) == "S7" || currentLine.Substring(0, 2) == "S8" || currentLine.Substring(0, 2) == "S9")//记录结束
398                     {
399                         break;
400                     }
401 
402                     lastAdd = currentAdd;                                                        //记录上一行地址
403                     lastDataLength = dataLength;                                                 //记录上一行数据长度
404                     currentAdd = Convert.ToUInt32(currentLine.Substring(4, addLen * 2), 16);      //本行文件开始地址
405                     dataLength = Convert.ToUInt32(currentLine.Substring(2, 2), 16) - Convert.ToUInt32(addLen) - 1;
406 
407                     if (lastAdd + lastDataLength != currentAdd)//判断相邻行地址是否连续  //不连续意味着大区间地址结束,继续下一个大区间起始地址
408                     {
409                         intervaiDic.Add(index, currentLine.Substring(4, addLen * 2));
410                         intervalList.Add(currentLine.Substring(4, addLen * 2));
411                     }
412                 }
413             }
414 
415             return intervaiDic;
416         }
417 
418 
419 
420         /// <summary>
421         /// 将区间不连续的地址补全
422         /// </summary>
423         /// <param name="completeValue">用于补全的字符</param>
424         /// <returns></returns>
425         public List<string> CompleteFile(string completeValue)
426         {
427             List<string> list = new List<string>();
428             bool firstLine = true;                                   //判断文件第一行记录
429             int addLen = 0;                                          //S19记录地址长度s3为4字节,s2为三字节,s1为两字节
430             uint currentAdd = 0;
431             uint dataLength = 0;
432             uint lastDataLength = 0;                                 //上一行数据长度
433             uint lastAdd = 0;                                        //上一行地址
434             int completeLine = 0;                                    //计算补全的行数
435             string lastLine;                                         //上一行的记录
436 
437             try
438             {
439                 foreach (string currentLine in listAllline)
440                 {
441                     if (currentLine.Length < 10)
442                     {
443                         list.Add(currentLine);
444                         continue;
445                     }
446                     else
447                     {
448                         if (currentLine.Substring(0, 2) == "S0")//跳过不需刷写的记录行
449                         {
450                             list.Add(currentLine);
451                             continue;
452                         }
453                         switch (currentLine.Substring(0, 2))
454                         {
455                             case "S1":
456                                 addLen = 2;
457                                 break;
458                             case "S2":
459                                 addLen = 3;
460                                 break;
461                             case "S3":
462                                 addLen = 4;
463                                 break;
464                             default:
465                                 addLen = 4;
466                                 break;
467                         }
468 
469                         if (firstLine)
470                         {
471                             firstLine = false;
472                             list.Add(currentLine);
473                             currentAdd = Convert.ToUInt32(currentLine.Substring(4, addLen * 2), 16);      //本行文件开始地址
474                             dataLength = Convert.ToUInt32(currentLine.Substring(2, 2), 16) - Convert.ToUInt32(addLen) - 1;
475                             continue;
476                         }
477 
478                         if (currentLine.Substring(0, 2) == "S7" || currentLine.Substring(0, 2) == "S8" || currentLine.Substring(0, 2) == "S9")//记录结束
479                         {
480                             list.Add(currentLine);
481                             break;
482                         }
483 
484                         lastAdd = currentAdd;                                                        //记录上一行地址
485                         lastDataLength = dataLength;                                                 //记录上一行数据长度
486                         lastLine = currentLine;
487                         currentAdd = Convert.ToUInt32(currentLine.Substring(4, addLen * 2), 16);      //本行文件开始地址
488                         dataLength = Convert.ToUInt32(currentLine.Substring(2, 2), 16) - Convert.ToUInt32(addLen) - 1;
489 
490                         if (lastAdd + lastDataLength < currentAdd)          //判断相邻行地址是否连续 ,不连续意味着大区间地址结束,开始做补全
491                         {
492                             int completeLen = Convert.ToInt32(currentAdd - lastAdd - lastDataLength);    //计算需要补全的长度
493                             uint newAdd = lastAdd;                                      //每行新记录填补的地址
494                             StringBuilder temp = new StringBuilder();
495                             while (completeLen > 0)
496                             {
497                                 if (completeLen <= lastDataLength)               //需要补的数据长度不足上一行记录的数据长度
498                                 {
499                                     completeLine++;
500                                     temp.Clear();
501                                     temp.Append(lastLine.Substring(0, 2));     //记录上一行的类型
502                                     string newLen = Convert.ToString(completeLen + 5, 16).PadLeft(2, '0').ToUpper();
503                                     temp.Append(newLen);
504                                     string newAdd_string = Convert.ToString(newAdd + completeLen, 16).PadLeft(8, '0').ToUpper();
505                                     temp.Append(newAdd_string);
506                                     for (int i = 0; i < completeLen; i++)
507                                     {
508                                         temp.Append(completeValue);
509                                     }
510                                     temp.Append(Checksum(temp.ToString()));
511                                     list.Add(temp.ToString());
512                                     completeLen -= completeLen;                  //减去已补过的长度
513                                 }
514                                 else
515                                 {
516                                     completeLine++;
517                                     temp.Clear();
518                                     temp.Append(lastLine.Substring(0, 4));
519                                     string newAdd_string = Convert.ToString(newAdd + lastDataLength, 16).PadLeft(8, '0').ToUpper();
520                                     temp.Append(newAdd_string);
521                                     for (int i = 0; i < Convert.ToInt32(lastDataLength); i++)
522                                     {
523                                         temp.Append(completeValue);
524                                     }
525                                     temp.Append(Checksum(temp.ToString()));
526                                     list.Add(temp.ToString());
527                                     completeLen -= Convert.ToInt32(lastDataLength);
528                                 }
529 
530                                 newAdd = newAdd + lastDataLength;
531                             }
532                             currentAdd = newAdd + lastDataLength;                               //当前行的地址
533 
534                             //if (currentLine.Substring(4, 8) == "0000C000")//针对氮氧二代这一行记录特殊情况采取的措施,上下都不连续
535                             //{
536                             //    currentAdd = 50144;
537                             //}
538 
539                             list.Add(currentLine);
540                         }
541                         else
542                         {
543                             list.Add(currentLine);
544                         }
545                     }
546                 }
547                 Console.WriteLine(completeLine);
548                 return list;
549             }
550             catch (Exception ex)
551             {
552                 Console.WriteLine(ex.Message);
553                 MessageBox.Show(ex.Message);
554                 return null;
555             }            
556         }
557 }
View Code

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM