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