Line No. | Rev | Author | Line |
---|---|---|---|
1 | 32 | kaklik | /********************************************************************* |
2 | * |
||
3 | * MPFS Generator Library |
||
4 | * |
||
5 | ********************************************************************* |
||
6 | * FileName: MPFSlib.cs |
||
7 | * Dependencies: Microsoft .NET Framework 2.0 |
||
8 | * Processor: x86 |
||
9 | * Complier: Microsoft Visual C# 2008 Express Edition |
||
10 | * Company: Microchip Technology, Inc. |
||
11 | * |
||
12 | * Software License Agreement |
||
13 | * |
||
14 | * This software is owned by Microchip Technology Inc. ("Microchip") |
||
15 | * and is supplied to you for use exclusively as described in the |
||
16 | * associated software agreement. This software is protected by |
||
17 | * software and other intellectual property laws. Any use in |
||
18 | * violation of the software license may subject the user to criminal |
||
19 | * sanctions as well as civil liability. Copyright 2008 Microchip |
||
20 | * Technology Inc. All rights reserved. |
||
21 | * |
||
22 | * |
||
23 | * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT |
||
24 | * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT |
||
25 | * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A |
||
26 | * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL |
||
27 | * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR |
||
28 | * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF |
||
29 | * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS |
||
30 | * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE |
||
31 | * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER |
||
32 | * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT |
||
33 | * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE. |
||
34 | * |
||
35 | * |
||
36 | * Author Date Comment |
||
37 | *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
||
38 | * Elliott Wood 4/17/2008 Original |
||
39 | ********************************************************************/ |
||
40 | using System; |
||
41 | using System.Collections.Generic; |
||
42 | using System.Collections.ObjectModel; |
||
43 | using System.Text; |
||
44 | using System.IO; |
||
45 | using System.IO.Compression; |
||
46 | using System.Text.RegularExpressions; |
||
47 | |||
48 | namespace Microchip |
||
49 | { |
||
50 | public enum MPFSOutputFormat |
||
51 | { |
||
52 | BIN, |
||
53 | C18, |
||
54 | ASM30, |
||
55 | C32, |
||
56 | MDD, |
||
57 | } |
||
58 | |||
59 | public class FileRecord |
||
60 | { |
||
61 | #region Fields |
||
62 | public UInt16 nameHash; |
||
63 | public UInt32 fileRecordOffset; |
||
64 | public UInt32 dynVarCntr=0; |
||
65 | |||
66 | #endregion |
||
67 | |||
68 | public FileRecord(UInt16 nameHash, UInt32 fileRecordOffset,UInt32 dynVarCntr) |
||
69 | { |
||
70 | this.nameHash = nameHash; |
||
71 | this.fileRecordOffset = fileRecordOffset; |
||
72 | this.dynVarCntr = dynVarCntr; |
||
73 | } |
||
74 | } |
||
75 | |||
76 | public abstract class MPFSBuilder |
||
77 | { |
||
78 | #region Fields |
||
79 | protected String Mddpath ; |
||
80 | protected String localPath; |
||
81 | protected String localFile; |
||
82 | protected List<string> log; |
||
83 | protected List<MPFSFileRecord> files; |
||
84 | protected String generatedImageName; |
||
85 | protected bool indexUpdated; |
||
86 | #endregion |
||
87 | |||
88 | #region Properties |
||
89 | /// <summary> |
||
90 | /// Specifies the path for the image file, along with any associated index files |
||
91 | /// </summary> |
||
92 | protected String LocalPath |
||
93 | { |
||
94 | get { return this.localPath; } |
||
95 | set { this.localPath = value; } |
||
96 | } |
||
97 | |||
98 | /// <summary> |
||
99 | /// Specifies the name of the image file to save to the file system |
||
100 | /// </summary> |
||
101 | protected String LocalFile |
||
102 | { |
||
103 | get { return this.localFile; } |
||
104 | set { this.localFile = value; } |
||
105 | } |
||
106 | |||
107 | /// <summary> |
||
108 | /// Retrieves the file name of the most recently generated image |
||
109 | /// </summary> |
||
110 | public String GeneratedImageFileName |
||
111 | { |
||
112 | get { return this.generatedImageName; } |
||
113 | } |
||
114 | |||
115 | /// <summary> |
||
116 | /// Retrieves the log from the last procedure |
||
117 | /// </summary> |
||
118 | public List<string> Log |
||
119 | { |
||
120 | get { return this.log; } |
||
121 | } |
||
122 | |||
123 | /// <summary> |
||
124 | /// Indicates whether or not the index file was updated |
||
125 | /// </summary> |
||
126 | public bool IndexUpdated |
||
127 | { |
||
128 | get { return this.indexUpdated; } |
||
129 | } |
||
130 | #endregion |
||
131 | |||
132 | #region Constructor |
||
133 | /// <summary> |
||
134 | /// Creates a new MPFSBuilder |
||
135 | /// </summary> |
||
136 | public MPFSBuilder() |
||
137 | { |
||
138 | // do nothing |
||
139 | } |
||
140 | #endregion |
||
141 | |||
142 | #region Methods |
||
143 | /// <summary> |
||
144 | /// Adds a file to the MPFS image |
||
145 | /// </summary> |
||
146 | /// <param name="localName">Local file name to read</param> |
||
147 | /// <param name="imageName">Name to use in image file</param> |
||
148 | public abstract bool AddFile(String localName, String imageName); |
||
149 | |||
150 | /// <summary> |
||
151 | /// Recursively adds a directory of files to the image |
||
152 | /// </summary> |
||
153 | /// <param name="dataPath">Local directory name to add</param> |
||
154 | /// <param name="imagePath">Path in MPFS image to add files to</param> |
||
155 | public abstract bool AddDirectory(String dataPath, String imagePath); |
||
156 | |||
157 | /// <summary> |
||
158 | /// Generates the MPFS image and any necessary support files |
||
159 | /// </summary> |
||
160 | public abstract bool Generate(MPFSOutputFormat format); |
||
161 | #endregion |
||
162 | |||
163 | } |
||
164 | |||
165 | public class MPFSClassicBuilder : MPFSBuilder |
||
166 | { |
||
167 | #region Fields |
||
168 | public UInt32 ReserveBlock; |
||
169 | #endregion |
||
170 | |||
171 | #region Constructor |
||
172 | /// <summary> |
||
173 | /// Creates a new MPFS Classic image builder |
||
174 | /// </summary> |
||
175 | /// <param name="localPath">The directory to save the image in</param> |
||
176 | /// <param name="localFile">The output file name for the image</param> |
||
177 | public MPFSClassicBuilder(String localPath, String localFile) |
||
178 | { |
||
179 | if (!localPath.EndsWith("\\")) |
||
180 | localPath += "\\"; |
||
181 | this.LocalPath = localPath; |
||
182 | this.LocalFile = localFile; |
||
183 | this.ReserveBlock = 0; |
||
184 | this.log = new List<string>(); |
||
185 | this.files = new List<MPFSFileRecord>(); |
||
186 | this.indexUpdated = false; |
||
187 | } |
||
188 | #endregion |
||
189 | |||
190 | #region Constants |
||
191 | const byte MPFS_DATA = 0x00; |
||
192 | const byte MPFS_DELETED = 0x01; |
||
193 | const byte MPFS_DLE = 0x03; |
||
194 | const byte MPFS_ETX = 0x04; |
||
195 | |||
196 | String MPFS_C_HEADER = |
||
197 | "/***************************************************************\r\n" + |
||
198 | " * MPFSImg.c\r\n" + |
||
199 | " * Defines an MPFS2 image to be stored in program memory.\r\n" + |
||
200 | " *\r\n" + |
||
201 | " * NOT FOR HAND MODIFICATION\r\n" + |
||
202 | " * This file is automatically generated by the MPFS2 Utility\r\n" + |
||
203 | " * ALL MODIFICATIONS WILL BE OVERWRITTEN BY THE MPFS2 GENERATOR\r\n" + |
||
204 | " * Generated " + DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToLongTimeString() + "\r\n" + |
||
205 | " ***************************************************************/\r\n" + |
||
206 | "\r\n" + |
||
207 | "#define __MPFSIMG_C\r\n" + |
||
208 | "\r\n" + |
||
209 | "#include \"TCPIP Stack/TCPIP.h\"\r\n" + |
||
210 | "\r\n" + |
||
211 | "#if defined(STACK_USE_MPFS) && !defined(MPFS_USE_EEPROM) && !defined(MPFS_USE_SPI_FLASH)\r\n" + |
||
212 | "\r\n"; |
||
213 | String MPFS_C_FOOTER = |
||
214 | "/**************************************************************\r\n" + |
||
215 | " * End of MPFS\r\n" + |
||
216 | " **************************************************************/\r\n" + |
||
217 | "#endif // #if defined(STACK_USE_MPFS) && !defined(MPFS_USE_EEPROM) && !defined(MPFS_USE_SPI_FLASH)" + |
||
218 | "\r\n\r\n"; |
||
219 | String MPFS_ASM_HEADER = |
||
220 | ";**************************************************************\r\n" + |
||
221 | "; MPFSImg.s\r\n" + |
||
222 | "; Defines an MPFS2 image to be stored in program memory.\r\n" + |
||
223 | "; Defined in ASM30 assembly for optimal storage size.\r\n" + |
||
224 | ";\r\n" + |
||
225 | "; NOT FOR HAND MODIFICATION\r\n" + |
||
226 | "; This file is automatically generated by the MPFS2 Utility\r\n" + |
||
227 | "; ALL MODIFICATIONS WILL BE OVERWRITTEN BY THE MPFS2 GENERATOR\r\n" + |
||
228 | "; Generated " + DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToLongTimeString() + "\r\n" + |
||
229 | ";**************************************************************\r\n\r\n" + |
||
230 | ".equ VALID_ID,0\r\n" + |
||
231 | ".ifdecl __dsPIC30F\r\n" + |
||
232 | " .include \"p30fxxxx.inc\"\r\n" + |
||
233 | ".endif\r\n" + |
||
234 | ".ifdecl __dsPIC33F\r\n" + |
||
235 | " .include \"p33fxxxx.inc\"\r\n" + |
||
236 | ".endif\r\n" + |
||
237 | ".ifdecl __PIC24H\r\n" + |
||
238 | " .include \"p24hxxxx.inc\"\r\n" + |
||
239 | ".endif\r\n" + |
||
240 | ".ifdecl __PIC24F\r\n" + |
||
241 | " .include \"p24fxxxx.inc\"\r\n" + |
||
242 | ".endif\r\n" + |
||
243 | ".if VALID_ID <> 1\r\n" + |
||
244 | " .error \"Processor ID not specified in generic include files. New ASM30 assembler needs to be downloaded?\"\r\n" + |
||
245 | ".endif\r\n" + |
||
246 | " .text\r\n" + |
||
247 | " .section MPFSData,code\r\n\r\n" + |
||
248 | " goto END_OF_MPFS ; Prevent accidental execution of constant data.\r\n" + |
||
249 | " .global BEGIN_MPFS\r\n" + |
||
250 | "BEGIN_MPFS:\r\n"; |
||
251 | String MPFS_ASM_FOOTER = "\r\n\r\n; End of Generated Image\r\n"; |
||
252 | #endregion |
||
253 | |||
254 | #region Public Methods |
||
255 | /// <summary> |
||
256 | /// Adds a file to the MPFS image |
||
257 | /// </summary> |
||
258 | /// <param name="localName">Local file name to read</param> |
||
259 | /// <param name="imageName">Name to use in image file</param> |
||
260 | public override bool AddFile(String localName, String imageName) |
||
261 | { |
||
262 | // Skip if can't be opened |
||
263 | if (!File.Exists(localName)) |
||
264 | { |
||
265 | log.Add("\r\nERROR: Could not read " + localName); |
||
266 | return false; |
||
267 | } |
||
268 | |||
269 | // Set up the new file record |
||
270 | MPFSFileRecord newFile = new MPFSFileRecord(); |
||
271 | newFile.FileName = imageName; |
||
272 | |||
273 | // Read the data in, escaping as it is read |
||
274 | byte b; |
||
275 | List<byte> data = new List<byte>(1024); |
||
276 | FileStream fs = new FileStream(localName, FileMode.Open, FileAccess.Read); |
||
277 | BinaryReader fin = new BinaryReader(fs); |
||
278 | for (int i = 0; i < fs.Length; i++) |
||
279 | { |
||
280 | if(data.Count == data.Capacity) |
||
281 | data.Capacity *= 2; |
||
282 | |||
283 | b = fin.ReadByte(); |
||
284 | if (b == MPFS_DLE || b == MPFS_ETX) |
||
285 | data.Add(MPFS_DLE); |
||
286 | data.Add(b); |
||
287 | } |
||
288 | fin.Close(); |
||
289 | newFile.data = data.ToArray(); |
||
290 | |||
291 | // Add the file and return |
||
292 | log.Add(" " + imageName + ": " + newFile.data.Length + " bytes"); |
||
293 | files.Add(newFile); |
||
294 | |||
295 | return true; |
||
296 | } |
||
297 | |||
298 | /// <summary> |
||
299 | /// Adds a directory to the MPFS image. All non-hidden files will be included. |
||
300 | /// </summary> |
||
301 | /// <param name="dataPath">The local directory to search</param> |
||
302 | /// <param name="imagePath">Ignored for MPFS Classic</param> |
||
303 | /// <returns></returns> |
||
304 | public override bool AddDirectory(String dataPath, String imagePath) |
||
305 | { |
||
306 | // Make sure directory exists |
||
307 | if (!Directory.Exists(dataPath)) |
||
308 | { |
||
309 | log.Add("\r\nERROR: Directory " + dataPath + " does not exist."); |
||
310 | return false; |
||
311 | } |
||
312 | |||
313 | // Make sure directory is not the project directory |
||
314 | if (this.localPath.Contains(dataPath)) |
||
315 | { |
||
316 | log.Add("\r\nERROR: The project directory is located in the source " + |
||
317 | "directory. The generator cannot run if the image is to be placed " + |
||
318 | "in the source directory. Please select the base MPLAB project " + |
||
319 | "directory before continuing."); |
||
320 | return false; |
||
321 | } |
||
322 | |||
323 | // Load directory members |
||
324 | DirectoryInfo dir = new DirectoryInfo(dataPath); |
||
325 | FileInfo[] filelist = dir.GetFiles(); |
||
326 | |||
327 | log.Add(dataPath + " :"); |
||
328 | |||
329 | // Add all sub files |
||
330 | for (int i = 0; i < filelist.Length; i++) |
||
331 | if ((filelist[i].Attributes & FileAttributes.Hidden) != FileAttributes.Hidden) |
||
332 | this.AddFile(filelist[i].FullName, imagePath + filelist[i].Name); |
||
333 | |||
334 | return true; |
||
335 | } |
||
336 | |||
337 | public override bool Generate(MPFSOutputFormat format) |
||
338 | { |
||
339 | // Start with nothing |
||
340 | generatedImageName = null; |
||
341 | |||
342 | // Make sure all paths exist |
||
343 | if (!Directory.Exists(localPath)) |
||
344 | { |
||
345 | log.Add("\r\nERROR: Output directory \"" + localPath + "\" does not exist!"); |
||
346 | return false; |
||
347 | } |
||
348 | |||
349 | // Make sure we have some files |
||
350 | if(files.Count == 0) |
||
351 | return false; |
||
352 | |||
353 | // Generate based on format |
||
354 | try |
||
355 | { |
||
356 | switch (format) |
||
357 | { |
||
358 | case MPFSOutputFormat.BIN: |
||
359 | return GenerateBIN(localPath + localFile); |
||
360 | case MPFSOutputFormat.C18: |
||
361 | case MPFSOutputFormat.C32: |
||
362 | return GenerateC(localPath + localFile); |
||
363 | case MPFSOutputFormat.ASM30: |
||
364 | return GenerateASM(localPath + localFile); |
||
365 | default: |
||
366 | log.Add("\r\nERROR: Invalid output format was specified."); |
||
367 | return false; |
||
368 | } |
||
369 | } |
||
370 | catch (Exception e) |
||
371 | { |
||
372 | log.Add("\r\nERROR: " + e.Message); |
||
373 | return false; |
||
374 | } |
||
375 | |||
376 | } |
||
377 | |||
378 | private bool GenerateBIN(String filename) |
||
379 | { |
||
380 | // Open the file |
||
381 | if (!filename.EndsWith(".bin", StringComparison.OrdinalIgnoreCase)) |
||
382 | filename += ".bin"; |
||
383 | BinaryWriter fout = new BinaryWriter(new FileStream(filename, FileMode.Create), Encoding.ASCII); |
||
384 | |||
385 | // Write the FAT data |
||
386 | UInt32 baseAddr = ReserveBlock + 17 * ((UInt32)files.Count + 1); |
||
387 | foreach (MPFSFileRecord file in files) |
||
388 | { |
||
389 | fout.Write(MPFS_DATA); |
||
390 | fout.Write((byte)(baseAddr)); |
||
391 | fout.Write((byte)(baseAddr >> 8)); |
||
392 | fout.Write((byte)(baseAddr >> 16)); |
||
393 | fout.Write((byte)(baseAddr >> 24)); |
||
394 | fout.Write(NormalizeFileName(file.FileName).ToCharArray()); |
||
395 | baseAddr += (UInt32)file.data.Length + 5; |
||
396 | } |
||
397 | fout.Write(MPFS_ETX); |
||
398 | fout.Write((uint)0xffffffff); |
||
399 | fout.Write("END OF FAT ".ToCharArray()); |
||
400 | |||
401 | // Write the files |
||
402 | foreach (MPFSFileRecord file in files) |
||
403 | { |
||
404 | fout.Write(file.data); |
||
405 | fout.Write(MPFS_ETX); |
||
406 | fout.Write((uint)0xffffffff); |
||
407 | } |
||
408 | |||
409 | // Flush the output and store the file name |
||
410 | fout.Flush(); |
||
411 | fout.Close(); |
||
412 | generatedImageName = filename; |
||
413 | return true; |
||
414 | } |
||
415 | |||
416 | private bool GenerateC(String filename) |
||
417 | { |
||
418 | // Open the file |
||
419 | if (!filename.EndsWith(".c", StringComparison.OrdinalIgnoreCase)) |
||
420 | filename += ".c"; |
||
421 | StreamWriter fout = new StreamWriter(filename, false, Encoding.ASCII); |
||
422 | |||
423 | fout.Write(MPFS_C_HEADER); |
||
424 | |||
425 | // Write the files |
||
426 | int fileIndex = 0; |
||
427 | foreach (MPFSFileRecord file in files) |
||
428 | { |
||
429 | fout.Write("\r\n/*******************************\r\n * Begin "); |
||
430 | fout.Write(NormalizeFileName(file.FileName)); |
||
431 | fout.Write("\r\n ******************************/\r\nstatic ROM unsigned char MPFS_"); |
||
432 | fout.Write(Convert.ToString(fileIndex++, 16).PadLeft(4, '0') + "[] = \r\n{"); |
||
433 | |||
434 | for (int i = 0; i < file.data.Length; i++) |
||
435 | { |
||
436 | if (i % 12 == 0) |
||
437 | fout.Write("\r\n\t"); |
||
438 | fout.Write("0x" + Convert.ToString(file.data[i], 16).PadLeft(2, '0') + ","); |
||
439 | } |
||
440 | |||
441 | fout.Write("\r\n\t0x04,0xff,0xff,0xff\r\n};\r\n"); |
||
442 | } |
||
443 | |||
444 | // Write the FAT |
||
445 | fileIndex = 0; |
||
446 | fout.Write( |
||
447 | "/**************************************************\r\n" + |
||
448 | " * Start of MPFS FAT\r\n" + |
||
449 | " **************************************************/\r\n" + |
||
450 | "typedef struct\r\n" + |
||
451 | "{\r\n" + |
||
452 | " unsigned char Flags;\r\n" + |
||
453 | " ROM unsigned char* Address;\r\n" + |
||
454 | " unsigned char Name[12];\r\n" + |
||
455 | "} FAT_TABLE_ENTRY;\r\n" + |
||
456 | "\r\n" + |
||
457 | "ROM FAT_TABLE_ENTRY MPFS_Start[] = \r\n" + |
||
458 | "{" |
||
459 | ); |
||
460 | foreach (MPFSFileRecord file in files) |
||
461 | { |
||
462 | fout.Write("\r\n\t{ 0x00, MPFS_" + Convert.ToString(fileIndex++, 16).PadLeft(4, '0')); |
||
463 | foreach (byte b in NormalizeFileName(file.FileName)) |
||
464 | { |
||
465 | fout.Write(", '" + (char)b + "'"); |
||
466 | } |
||
467 | fout.Write(" },"); |
||
468 | } |
||
469 | fout.Write( |
||
470 | "\r\n\t{ 0x04, (ROM unsigned char*)0xffffff, 'E', 'N', 'D', ' ', 'O', 'F', ' ', 'F', 'A', 'T', ' ', ' ' },\r\n" + |
||
471 | "};\r\n" + |
||
472 | "/**************************************************\r\n" + |
||
473 | " * End of MPFS FAT\r\n" + |
||
474 | " **************************************************/\r\n\r\n" |
||
475 | ); |
||
476 | |||
477 | fout.Write(MPFS_C_FOOTER); |
||
478 | |||
479 | // Flush the output and store the file name |
||
480 | fout.Flush(); |
||
481 | fout.Close(); |
||
482 | generatedImageName = filename; |
||
483 | return true; |
||
484 | } |
||
485 | |||
486 | private bool GenerateASM(String filename) |
||
487 | { |
||
488 | // Open the file |
||
489 | if (!filename.EndsWith(".s", StringComparison.OrdinalIgnoreCase)) |
||
490 | filename += ".s"; |
||
491 | StreamWriter fout = new StreamWriter(filename, false, Encoding.ASCII); |
||
492 | |||
493 | fout.Write(MPFS_ASM_HEADER); |
||
494 | |||
495 | // Write the files |
||
496 | int fileIndex = 0; |
||
497 | foreach (MPFSFileRecord file in files) |
||
498 | { |
||
499 | fout.Write("\r\n;*******************************\r\n; Begin "); |
||
500 | fout.Write(NormalizeFileName(file.FileName)); |
||
501 | fout.Write("\r\n;*******************************\r\n" + |
||
502 | "\tgoto\tEND_OF_MPFS_"); |
||
503 | fout.Write(Convert.ToString(fileIndex, 16).PadLeft(4, '0')); |
||
504 | fout.Write("\t\t; Prevent accidental execution of constant data\r\n\t.global _MPFS_"); |
||
505 | fout.Write(Convert.ToString(fileIndex, 16).PadLeft(4, '0')); |
||
506 | fout.Write("\r\n_MPFS_"); |
||
507 | fout.Write(Convert.ToString(fileIndex, 16).PadLeft(4, '0')); |
||
508 | fout.Write(":"); |
||
509 | |||
510 | for (int i = 0; i < file.data.Length; i++) |
||
511 | { |
||
512 | if (i % 12 == 0) |
||
513 | fout.Write("\r\n\t.pbyte\t"); |
||
514 | fout.Write("0x" + Convert.ToString(file.data[i], 16).PadLeft(2, '0')); |
||
515 | if (i % 12 != 11 && i != file.data.Length-1) |
||
516 | fout.Write(","); |
||
517 | } |
||
518 | |||
519 | fout.Write("\r\n\t.pbyte\t0x04,0xff,0xff,0xff,0xff\r\nEND_OF_MPFS_"); |
||
520 | fout.Write(Convert.ToString(fileIndex++, 16).PadLeft(4, '0')); |
||
521 | fout.Write(":\r\n"); |
||
522 | } |
||
523 | |||
524 | // Write the FAT |
||
525 | fileIndex = 0; |
||
526 | fout.Write( |
||
527 | ";*************************************************\r\n" + |
||
528 | "; Start of MPFS FAT\r\n" + |
||
529 | ";*************************************************\r\n" + |
||
530 | "\t.section\t.const,psv\r\n" + |
||
531 | "\t.global _MPFS_Start\r\n" + |
||
532 | "_MPFS_Start:" |
||
533 | ); |
||
534 | foreach (MPFSFileRecord file in files) |
||
535 | { |
||
536 | fout.Write("\r\n\t.byte\t0x00,0x00\r\n\t.long\tpaddr(_MPFS_"); |
||
537 | fout.Write(Convert.ToString(fileIndex++, 16).PadLeft(4, '0')); |
||
538 | fout.Write(")\r\n\t.byte\t"); |
||
539 | int i = 0; |
||
540 | foreach (byte b in NormalizeFileName(file.FileName)) |
||
541 | { |
||
542 | fout.Write("'" + (char)b + "'"); |
||
543 | if (++i < 12) |
||
544 | fout.Write(","); |
||
545 | } |
||
546 | } |
||
547 | fout.Write( |
||
548 | "\r\n\t.byte\t0x04,0x00\r\n\t.long\t0xffffffff" + |
||
549 | "\r\n\t.byte\t'E','N','D',' ','O','F',' ','F','A','T',' ',' '\r\n\r\n" + |
||
550 | "\t.section MPFSEnd,code\r\n" + |
||
551 | "END_OF_MPFS:\r\n" |
||
552 | ); |
||
553 | |||
554 | fout.Write(MPFS_ASM_FOOTER); |
||
555 | |||
556 | // Flush the output and store the file name |
||
557 | fout.Flush(); |
||
558 | fout.Close(); |
||
559 | generatedImageName = filename; |
||
560 | return true; |
||
561 | } |
||
562 | |||
563 | private String NormalizeFileName(String name) |
||
564 | { |
||
565 | if (name.Length > 12) |
||
566 | name = name.Substring(0, 12); |
||
567 | return name.PadRight(12).ToUpper(); |
||
568 | } |
||
569 | |||
570 | #endregion |
||
571 | } |
||
572 | |||
573 | public class MPFS2Builder : MPFSBuilder |
||
574 | { |
||
575 | #region Fields |
||
576 | private Collection<String> dynamicTypes; |
||
577 | private Collection<String> nonGZipTypes; |
||
578 | private DynamicVariableParser dynVarParser; |
||
579 | #endregion |
||
580 | |||
581 | #region Constants |
||
582 | private const UInt16 MPFS2_FLAG_ISZIPPED = 0x0001; |
||
583 | private const UInt16 MPFS2_FLAG_HASINDEX = 0x0002; |
||
584 | #endregion |
||
585 | |||
586 | #region Constructor |
||
587 | /// <summary> |
||
588 | /// Creates a new MPFS2 image builder |
||
589 | /// </summary> |
||
590 | /// <param name="localPath">The directory to save the image in, and to read/write index files</param> |
||
591 | /// <param name="localFile">The output file name for the image</param> |
||
592 | public MPFS2Builder(String localPath, String localFile) |
||
593 | { |
||
594 | if (!localPath.EndsWith("\\")) |
||
595 | localPath += "\\"; |
||
596 | this.LocalPath = localPath; |
||
597 | this.LocalFile = localFile; |
||
598 | this.dynamicTypes = new Collection<string>(); |
||
599 | this.nonGZipTypes = new Collection<string>(); |
||
600 | this.log = new List<string>(); |
||
601 | this.files = new List<MPFSFileRecord>(); |
||
602 | this.dynVarParser = new DynamicVariableParser(localPath); |
||
603 | this.indexUpdated = false; |
||
604 | } |
||
605 | #endregion |
||
606 | |||
607 | #region Properties |
||
608 | /// <summary> |
||
609 | /// Sets a comma-separated list of types to be considered dynamic |
||
610 | /// </summary> |
||
611 | public string DynamicTypes |
||
612 | { |
||
613 | set |
||
614 | { |
||
615 | Array strings = value.Split(','); |
||
616 | dynamicTypes.Clear(); |
||
617 | foreach (String s in strings) |
||
618 | { |
||
619 | String s_trimmed = s.Replace('*', ' ').Trim(); |
||
620 | if (s_trimmed.Length > 0) |
||
621 | this.dynamicTypes.Add(s_trimmed); |
||
622 | } |
||
623 | } |
||
624 | } |
||
625 | |||
626 | /// <summary> |
||
627 | /// Sets a comma-separated list of types not to be compressed |
||
628 | /// </summary> |
||
629 | public string NonGZipTypes |
||
630 | { |
||
631 | set |
||
632 | { |
||
633 | Array strings = value.Split(','); |
||
634 | nonGZipTypes.Clear(); |
||
635 | foreach (String s in strings) |
||
636 | { |
||
637 | String s_trimmed = s.Replace('*',' ').Trim(); |
||
638 | if (s_trimmed.Length > 0) |
||
639 | this.nonGZipTypes.Add(s_trimmed); |
||
640 | } |
||
641 | } |
||
642 | } |
||
643 | #endregion |
||
644 | |||
645 | #region Public Methods |
||
646 | /// <summary> |
||
647 | /// Adds a file to the MPFS image |
||
648 | /// </summary> |
||
649 | /// <param name="localName">Local file name to read</param> |
||
650 | /// <param name="imageName">Name to use in image file</param> |
||
651 | public override bool AddFile(String localName, String imageName) |
||
652 | { |
||
653 | // Skip if can't be opened |
||
654 | if (!File.Exists(localName)) |
||
655 | { |
||
656 | log.Add("\r\nERROR: Could not read " + localName); |
||
657 | return false; |
||
658 | } |
||
659 | |||
660 | // Set up the new file record |
||
661 | MPFSFileRecord newFile = new MPFSFileRecord(); |
||
662 | newFile.FileName = imageName; |
||
663 | newFile.fileDate = File.GetLastWriteTime(localName); |
||
664 | |||
665 | // Read the data in |
||
666 | FileStream fs = new FileStream(localName, FileMode.Open, FileAccess.Read); |
||
667 | BinaryReader fin = new BinaryReader(fs); |
||
668 | newFile.data = fin.ReadBytes((int)fs.Length); |
||
669 | fin.Close(); |
||
670 | |||
671 | // Parse the file if necessary |
||
672 | MPFSFileRecord idxFile = null; |
||
673 | if (this.FileMatches(localName, this.dynamicTypes)) |
||
674 | { |
||
675 | idxFile = dynVarParser.Parse(newFile); |
||
676 | } |
||
677 | |||
678 | // GZip the file if possible |
||
679 | int gzipRatio = 0; |
||
680 | if (idxFile == null && !this.FileMatches(localName, this.nonGZipTypes)) |
||
681 | { |
||
682 | MemoryStream ms = new MemoryStream(); |
||
683 | GZipStream gz = new GZipStream(ms, CompressionMode.Compress, true); |
||
684 | gz.Write(newFile.data, 0, newFile.data.Length); |
||
685 | gz.Flush(); |
||
686 | gz.Close(); |
||
687 | |||
688 | // Only use zipped copy if it's smaller |
||
689 | if (ms.Length < newFile.data.Length) |
||
690 | { |
||
691 | gzipRatio = (int)(100 - (100 * ms.Length / newFile.data.Length)); |
||
692 | newFile.data = ms.ToArray(); |
||
693 | newFile.isZipped = true; |
||
694 | } |
||
695 | } |
||
696 | |||
697 | // Add the file and return |
||
698 | if (idxFile == null) |
||
699 | { |
||
700 | log.Add(" " + imageName + ": " + newFile.data.Length + " bytes" + |
||
701 | ((gzipRatio > 0) ? " (gzipped by " + gzipRatio + "%)" : "")); |
||
702 | files.Add(newFile); |
||
703 | } |
||
704 | else |
||
705 | { |
||
706 | log.Add(" " + imageName + ": " + newFile.data.Length + " bytes, " + (idxFile.data.Length / 8) + " vars"); |
||
707 | newFile.hasIndex = true; |
||
708 | files.Add(newFile); |
||
709 | files.Add(idxFile); |
||
710 | } |
||
711 | return true; |
||
712 | } |
||
713 | |||
714 | /// <summary> |
||
715 | /// Recursively adds a directory to the MPFS image. All non-hidden files will be included. |
||
716 | /// </summary> |
||
717 | /// <param name="dataPath">The local directory to search</param> |
||
718 | /// <param name="imagePath">The base directory this folder is in the MPFS2 image</param> |
||
719 | /// <returns></returns> |
||
720 | public override bool AddDirectory(String dataPath, String imagePath) |
||
721 | { |
||
722 | // Make sure directory exists |
||
723 | if (!Directory.Exists(dataPath)) |
||
724 | { |
||
725 | log.Add("\r\nERROR: Directory " + dataPath + " does not exist."); |
||
726 | return false; |
||
727 | } |
||
728 | |||
729 | // Make sure directory is not the project directory |
||
730 | if (this.localPath.Contains(dataPath)) |
||
731 | { |
||
732 | log.Add("\r\nERROR: The project directory is located in the source " + |
||
733 | "directory. The generator cannot run if the image is to be placed " + |
||
734 | "in the source directory. Please select the base MPLAB project " + |
||
735 | "directory before continuing."); |
||
736 | return false; |
||
737 | } |
||
738 | |||
739 | // Load directory members |
||
740 | DirectoryInfo dir = new DirectoryInfo(dataPath); |
||
741 | FileInfo[] filelist = dir.GetFiles(); |
||
742 | DirectoryInfo[] subdirs = dir.GetDirectories(); |
||
743 | |||
744 | log.Add(dataPath + " :"); |
||
745 | |||
746 | // Add all sub files |
||
747 | for (int i = 0; i < filelist.Length; i++) |
||
748 | if ((filelist[i].Attributes & FileAttributes.Hidden) != FileAttributes.Hidden) |
||
749 | this.AddFile(filelist[i].FullName, imagePath + filelist[i].Name); |
||
750 | |||
751 | // Add all subdirectories |
||
752 | for (int i = 0; i < subdirs.Length; i++) |
||
753 | if((subdirs[i].Attributes & FileAttributes.Hidden) != FileAttributes.Hidden) |
||
754 | this.AddDirectory(subdirs[i].FullName, imagePath + subdirs[i].Name + "/"); |
||
755 | |||
756 | return true; |
||
757 | } |
||
758 | |||
759 | /// <summary> |
||
760 | /// Generates an image in the specified format |
||
761 | /// </summary> |
||
762 | /// <param name="format">One of the MPFSOutputFormat constants indicating the format</param> |
||
763 | /// <returns>true if generation was successful, false otherwise</returns> |
||
764 | public override bool Generate(MPFSOutputFormat format) |
||
765 | { |
||
766 | // Start with nothing as the output name |
||
767 | generatedImageName = null; |
||
768 | |||
769 | // Make sure all paths exist |
||
770 | if (!Directory.Exists(localPath)) |
||
771 | { |
||
772 | log.Add("\r\nERROR: Output directory \"" + localPath + "\" does not exist!"); |
||
773 | return false; |
||
774 | } |
||
775 | |||
776 | // Make sure we have some files |
||
777 | if (files.Count == 0) |
||
778 | return false; |
||
779 | |||
780 | try |
||
781 | { |
||
782 | // Write any index files that have changed |
||
783 | indexUpdated = dynVarParser.WriteIndices(); |
||
784 | } |
||
785 | catch (Exception e) |
||
786 | { |
||
787 | log.Add("ERROR: " + e.Message); |
||
788 | return false; |
||
789 | } |
||
790 | |||
791 | // Determine address of each file and string |
||
792 | UInt32 numFiles = (UInt32)files.Count; |
||
793 | UInt32 lenHeader = 8; |
||
794 | UInt32 lenHashes = 2 * numFiles; |
||
795 | UInt32 lenFAT = 22 * numFiles; |
||
796 | UInt32 baseAddr = lenHeader + lenHashes + lenFAT; |
||
797 | UInt32 counter=0; |
||
798 | UInt32 loopCntr=0; |
||
799 | UInt32 numFileRecrds = 0; |
||
800 | |||
801 | foreach (MPFSFileRecord file in files) |
||
802 | { |
||
803 | file.locStr = baseAddr; |
||
804 | baseAddr += (UInt32)file.FileName.Length + 1; |
||
805 | } |
||
806 | foreach (MPFSFileRecord file in files) |
||
807 | { |
||
808 | file.locData = baseAddr; |
||
809 | baseAddr += (UInt32)file.data.Length; |
||
810 | } |
||
811 | |||
812 | // Set up the writer |
||
813 | try |
||
814 | { |
||
815 | MPFS2Writer w; |
||
816 | switch (format) |
||
817 | { |
||
818 | case MPFSOutputFormat.C18: |
||
819 | case MPFSOutputFormat.C32: |
||
820 | w = new MPFS2C18Writer(localPath + localFile); |
||
821 | WriteImage(w); |
||
822 | break; |
||
823 | case MPFSOutputFormat.ASM30: |
||
824 | w = new MPFS2ASM30Writer(localPath + localFile); |
||
825 | WriteImage(w); |
||
826 | break; |
||
827 | case MPFSOutputFormat.MDD: |
||
828 | MDDWriter(localPath); |
||
829 | break; |
||
830 | default: |
||
831 | w = new MPFS2BINWriter(localPath + localFile); |
||
832 | WriteImage(w); |
||
833 | break; |
||
834 | } |
||
835 | } |
||
836 | catch (Exception e) |
||
837 | { |
||
838 | log.Add("\r\nERROR: " + e.Message); |
||
839 | return false; |
||
840 | } |
||
841 | |||
842 | return true; |
||
843 | } |
||
844 | #endregion |
||
845 | private void WriteImage(MPFS2Writer x) |
||
846 | { |
||
847 | MPFS2Writer w; |
||
848 | |||
849 | w = x; |
||
850 | // Write the image |
||
851 | w.Write("MPFS"); |
||
852 | w.Write((byte)0x02); |
||
853 | w.Write((byte)0x01); |
||
854 | w.Write((UInt16)files.Count); |
||
855 | |||
856 | foreach (MPFSFileRecord file in files) |
||
857 | w.Write((UInt16)file.nameHash); |
||
858 | |||
859 | UInt16 flags; |
||
860 | foreach (MPFSFileRecord file in files) |
||
861 | { |
||
862 | w.Write(file.locStr); |
||
863 | w.Write(file.locData); |
||
864 | w.Write((UInt32)file.data.Length); |
||
865 | w.Write((UInt32)((file.fileDate.ToUniversalTime().Ticks - 621355968000000000) / 10000000)); |
||
866 | w.Write((UInt32)0); |
||
867 | flags = 0; |
||
868 | if (file.hasIndex) |
||
869 | flags |= MPFS2_FLAG_HASINDEX; |
||
870 | if (file.isZipped) |
||
871 | flags |= MPFS2_FLAG_ISZIPPED; |
||
872 | w.Write(flags); |
||
873 | } |
||
874 | |||
875 | foreach (MPFSFileRecord file in files) |
||
876 | { |
||
877 | w.Write(file.FileName); |
||
878 | w.Write((byte)0x00); |
||
879 | } |
||
880 | |||
881 | foreach (MPFSFileRecord file in files) |
||
882 | w.Write(file.data); |
||
883 | |||
884 | w.Close(); |
||
885 | generatedImageName = w.imageName; |
||
886 | |||
887 | log.Add("\r\nGENERATED MPFS2 IMAGE: " + w.ImageLength + " bytes"); |
||
888 | |||
889 | } |
||
890 | |||
891 | private class FilesRecordWriter : BinaryWriter |
||
892 | { |
||
893 | #region Fields |
||
894 | protected BinaryWriter fout; |
||
895 | public int ImageLength = 0; |
||
896 | #endregion |
||
897 | |||
898 | public FilesRecordWriter(String DataPath) |
||
899 | { |
||
900 | String filename = "FileRcrd.bin"; |
||
901 | |||
902 | string newPath = System.IO.Path.Combine(DataPath, filename); |
||
903 | |||
904 | if (!filename.EndsWith(".bin", StringComparison.OrdinalIgnoreCase)) |
||
905 | filename += ".bin"; |
||
906 | |||
907 | fout = new BinaryWriter(new FileStream(newPath, FileMode.Create), Encoding.ASCII); |
||
908 | } |
||
909 | |||
910 | public void Write(byte data) |
||
911 | { |
||
912 | fout.Write(data); |
||
913 | ImageLength++; |
||
914 | } |
||
915 | |||
916 | public void Close() |
||
917 | { |
||
918 | fout.Close(); |
||
919 | } |
||
920 | } |
||
921 | |||
922 | private class DynamicVarRecordWriter : BinaryWriter |
||
923 | { |
||
924 | #region Fields |
||
925 | protected BinaryWriter fout; |
||
926 | #endregion |
||
927 | |||
928 | public DynamicVarRecordWriter(String DataPath) |
||
929 | { |
||
930 | |||
931 | String filename = "DynRcrd.bin"; |
||
932 | |||
933 | |||
934 | //Create a new subfolder under the current active folder |
||
935 | string newPath = System.IO.Path.Combine(DataPath, filename); |
||
936 | |||
937 | |||
938 | if (!filename.EndsWith(".bin", StringComparison.OrdinalIgnoreCase)) |
||
939 | filename += ".bin"; |
||
940 | //BinaryWriter fout = new BinaryWriter(new FileStream(filename, FileMode.Create), Encoding.ASCII); |
||
941 | fout = new BinaryWriter(new FileStream(newPath, FileMode.Create), Encoding.ASCII); |
||
942 | |||
943 | } |
||
944 | //public override void Write(byte data) |
||
945 | public void Write(byte data) |
||
946 | { |
||
947 | fout.Write(data); |
||
948 | } |
||
949 | |||
950 | //public override void Close() |
||
951 | public void Close() |
||
952 | { |
||
953 | |||
954 | fout.Close(); |
||
955 | } |
||
956 | } |
||
957 | |||
958 | //public bool MDDWriter(String localPath) |
||
959 | public void MDDWriter(String localPath) |
||
960 | { |
||
961 | FilesRecordWriter FileRecrd /*Files with dynamic variables Record*/; |
||
962 | //RecordWriter DynVarRecrd /*Dynamic Variables Record of each file*/; |
||
963 | DynamicVarRecordWriter DynVarRecrd /*Dynamic Variables Record of each file*/; |
||
964 | |||
965 | UInt32 counter = 0; |
||
966 | UInt32 loopCntr = 0; |
||
967 | UInt32 numFileRecrds = 0; |
||
968 | |||
969 | FileRecrd = new FilesRecordWriter(localPath); |
||
970 | DynVarRecrd = new DynamicVarRecordWriter(localPath); |
||
971 | |||
972 | |||
973 | UInt16 flags; |
||
974 | List<FileRecord> FileRcrdList = new List<FileRecord>(); |
||
975 | |||
976 | foreach (MPFSFileRecord file in files) |
||
977 | { |
||
978 | counter=0; |
||
979 | loopCntr=0; |
||
980 | if(file.dynVarCntr >0) |
||
981 | { |
||
982 | FileRcrdList.Add(new FileRecord ((UInt16)file.nameHash, |
||
983 | (UInt32)file.fileRecordOffset, |
||
984 | (UInt32)file.dynVarCntr)); |
||
985 | numFileRecrds++; |
||
986 | |||
987 | |||
988 | DynVarRecrd.Write((byte)(file.fileRecordLength)); |
||
989 | DynVarRecrd.Write((byte)(file.fileRecordLength>>8)); |
||
990 | DynVarRecrd.Write((byte)(file.fileRecordLength>>16)); |
||
991 | DynVarRecrd.Write((byte)(file.fileRecordLength>>24)); |
||
992 | |||
993 | |||
994 | flags = 0; |
||
995 | if (file.hasIndex) |
||
996 | flags |= MPFS2_FLAG_HASINDEX; |
||
997 | if (file.isZipped) |
||
998 | flags |= MPFS2_FLAG_ISZIPPED; |
||
999 | |||
1000 | |||
1001 | DynVarRecrd.Write((byte)(flags)); |
||
1002 | DynVarRecrd.Write((byte)(flags>>8)); |
||
1003 | |||
1004 | /* loopCntr = (UInt16)file.FileName.Length; |
||
1005 | flags = 0x00; |
||
1006 | |||
1007 | while (loopCntr != (UInt32)flags) |
||
1008 | { |
||
1009 | DynVarRecrd.Write((byte)file.FileName[flags]); |
||
1010 | flags += 1; |
||
1011 | } |
||
1012 | */ |
||
1013 | loopCntr=0; |
||
1014 | |||
1015 | while(loopCntr!=file.dynVarCntr) |
||
1016 | { |
||
1017 | |||
1018 | DynVarRecrd.Write((byte)(file.dynVarOffsetAndIndexID[0+counter])); |
||
1019 | DynVarRecrd.Write((byte)(file.dynVarOffsetAndIndexID[1+counter])); |
||
1020 | DynVarRecrd.Write((byte)(file.dynVarOffsetAndIndexID[2+counter])); |
||
1021 | DynVarRecrd.Write((byte)(file.dynVarOffsetAndIndexID[3+counter])); |
||
1022 | |||
1023 | DynVarRecrd.Write((byte)(file.dynVarOffsetAndIndexID[4 + counter])); |
||
1024 | DynVarRecrd.Write((byte)(file.dynVarOffsetAndIndexID[5 + counter])); |
||
1025 | DynVarRecrd.Write((byte)(file.dynVarOffsetAndIndexID[6 + counter])); |
||
1026 | DynVarRecrd.Write((byte)(file.dynVarOffsetAndIndexID[7 + counter])); |
||
1027 | |||
1028 | |||
1029 | counter+=8; |
||
1030 | loopCntr+=1; |
||
1031 | } |
||
1032 | |||
1033 | } |
||
1034 | } |
||
1035 | |||
1036 | FileRcrdList.Sort(delegate(FileRecord FR1, FileRecord FR2) |
||
1037 | { |
||
1038 | return FR1.nameHash.CompareTo(FR2.nameHash); |
||
1039 | } |
||
1040 | ); |
||
1041 | |||
1042 | FileRecrd.Write((byte)(numFileRecrds)); |
||
1043 | FileRecrd.Write((byte)(numFileRecrds>>8)); |
||
1044 | FileRecrd.Write((byte)(numFileRecrds>>16)); |
||
1045 | FileRecrd.Write((byte)(numFileRecrds>>24)); |
||
1046 | |||
1047 | FileRcrdList.ForEach(delegate(FileRecord FR) |
||
1048 | { |
||
1049 | FileRecrd.Write((byte)(FR.nameHash)); |
||
1050 | FileRecrd.Write((byte)(FR.nameHash>>8)); |
||
1051 | FileRecrd.Write((byte)(FR.fileRecordOffset)); |
||
1052 | FileRecrd.Write((byte)(FR.fileRecordOffset>>8)); |
||
1053 | FileRecrd.Write((byte)(FR.fileRecordOffset>>16)); |
||
1054 | FileRecrd.Write((byte)(FR.fileRecordOffset>>24)); |
||
1055 | FileRecrd.Write((byte)(FR.dynVarCntr)); |
||
1056 | FileRecrd.Write((byte)(FR.dynVarCntr>>8)); |
||
1057 | FileRecrd.Write((byte)(FR.dynVarCntr>>16)); |
||
1058 | FileRecrd.Write((byte)(FR.dynVarCntr>>24)); |
||
1059 | |||
1060 | } |
||
1061 | ); |
||
1062 | |||
1063 | log.Add("\r\nGENERATED MPFS2 IMAGE: " + FileRecrd.ImageLength + " bytes"); |
||
1064 | |||
1065 | FileRecrd.Close(); |
||
1066 | DynVarRecrd.Close(); |
||
1067 | |||
1068 | } |
||
1069 | #region Private Methods |
||
1070 | private bool FileMatches(String fileName, Collection<String> endings) |
||
1071 | { |
||
1072 | foreach(String end in endings) |
||
1073 | if(fileName.EndsWith(end)) |
||
1074 | return true; |
||
1075 | return false; |
||
1076 | } |
||
1077 | #endregion |
||
1078 | |||
1079 | #region Writer Classes |
||
1080 | private abstract class MPFS2Writer |
||
1081 | { |
||
1082 | public int ImageLength = 0; |
||
1083 | public string imageName; |
||
1084 | |||
1085 | public abstract void Write(byte data); |
||
1086 | public abstract void Close(); |
||
1087 | |||
1088 | public void Write(byte[] data) |
||
1089 | { |
||
1090 | foreach (byte b in data) |
||
1091 | Write(b); |
||
1092 | } |
||
1093 | |||
1094 | public void Write(String data) |
||
1095 | { |
||
1096 | foreach (byte b in data) |
||
1097 | Write(b); |
||
1098 | } |
||
1099 | |||
1100 | public void Write(UInt16 data) |
||
1101 | { |
||
1102 | Write((byte)(data)); |
||
1103 | Write((byte)(data >> 8)); |
||
1104 | } |
||
1105 | |||
1106 | public void Write(UInt32 data) |
||
1107 | { |
||
1108 | Write((byte)(data)); |
||
1109 | Write((byte)(data >> 8)); |
||
1110 | Write((byte)(data >> 16)); |
||
1111 | Write((byte)(data >> 24)); |
||
1112 | } |
||
1113 | } |
||
1114 | |||
1115 | private class MPFS2BINWriter : MPFS2Writer |
||
1116 | { |
||
1117 | #region Fields |
||
1118 | protected BinaryWriter fout; |
||
1119 | #endregion |
||
1120 | |||
1121 | public MPFS2BINWriter(String filename) |
||
1122 | { |
||
1123 | if (!filename.EndsWith(".bin", StringComparison.OrdinalIgnoreCase)) |
||
1124 | filename += ".bin"; |
||
1125 | fout = new BinaryWriter(new FileStream(filename, FileMode.Create), Encoding.ASCII); |
||
1126 | imageName = filename; |
||
1127 | } |
||
1128 | |||
1129 | public override void Write(byte data) |
||
1130 | { |
||
1131 | ImageLength++; |
||
1132 | fout.Write(data); |
||
1133 | } |
||
1134 | |||
1135 | public override void Close() |
||
1136 | { |
||
1137 | fout.Flush(); |
||
1138 | fout.Close(); |
||
1139 | } |
||
1140 | } |
||
1141 | |||
1142 | private class MPFS2C18Writer : MPFS2Writer |
||
1143 | { |
||
1144 | #region Fields |
||
1145 | protected StreamWriter fout; |
||
1146 | protected string ASCIILine; |
||
1147 | #endregion |
||
1148 | |||
1149 | public MPFS2C18Writer(String filename) |
||
1150 | { |
||
1151 | if (!filename.EndsWith(".c", StringComparison.OrdinalIgnoreCase)) |
||
1152 | filename += ".c"; |
||
1153 | fout = new StreamWriter(filename, false, Encoding.ASCII); |
||
1154 | imageName = filename; |
||
1155 | fout.Write( |
||
1156 | "/***************************************************************\r\n" + |
||
1157 | " * MPFSImg2.c\r\n" + |
||
1158 | " * Defines an MPFS2 image to be stored in program memory.\r\n" + |
||
1159 | " *\r\n" + |
||
1160 | " * NOT FOR HAND MODIFICATION\r\n" + |
||
1161 | " * This file is automatically generated by the MPFS2 Utility\r\n" + |
||
1162 | " * ALL MODIFICATIONS WILL BE OVERWRITTEN BY THE MPFS2 GENERATOR\r\n" + |
||
1163 | " * Generated " + DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToLongTimeString() + "\r\n" + |
||
1164 | " ***************************************************************/\r\n" + |
||
1165 | "\r\n#define __MPFSIMG2_C\r\n\r\n" + |
||
1166 | "#include \"TCPIPConfig.h\"\r\n" + |
||
1167 | "#if !defined(MPFS_USE_EEPROM) && !defined(MPFS_USE_SPI_FLASH)\r\n\r\n" + |
||
1168 | "#include \"TCPIP Stack/TCPIP.h\"\r\n" + |
||
1169 | "#if defined(STACK_USE_MPFS2)\r\n\r\n" + |
||
1170 | "\r\n" + |
||
1171 | "/**************************************\r\n" + |
||
1172 | " * MPFS2 Image Data\r\n" + |
||
1173 | " **************************************/" |
||
1174 | ); |
||
1175 | } |
||
1176 | |||
1177 | public override void Write(byte data) |
||
1178 | { |
||
1179 | char ASCIIdata; |
||
1180 | |||
1181 | ASCIIdata = '.'; |
||
1182 | if (data >= 32 && data <= 126 && data != '*') // * cannot be displayed because it would open the possibility of */ occuring in the sequence, which would mess up our block comment |
||
1183 | ASCIIdata = (char)data; |
||
1184 | |||
1185 | if (ImageLength % 1024 == 0) |
||
1186 | ASCIILine = " " + ASCIILine; |
||
1187 | else |
||
1188 | fout.Write(","); |
||
1189 | if (ImageLength % 16 == 0) |
||
1190 | { |
||
1191 | if (ImageLength != 0) |
||
1192 | fout.Write(ASCIILine + " */"); |
||
1193 | ASCIILine = " /* "; |
||
1194 | } |
||
1195 | if (ImageLength % 1024 == 0) |
||
1196 | fout.Write("\r\n#define DATACHUNK" + Convert.ToString((ImageLength / 1024), 16).PadLeft(6, '0')); |
||
1197 | if (ImageLength % 16 == 0) |
||
1198 | fout.Write(" \\\r\n\t"); |
||
1199 | ASCIILine += ASCIIdata.ToString(); |
||
1200 | fout.Write("0x" + Convert.ToString(data, 16).PadLeft(2, '0')); |
||
1201 | ImageLength++; |
||
1202 | } |
||
1203 | |||
1204 | public override void Close() |
||
1205 | { |
||
1206 | if (ImageLength % 16 != 0) |
||
1207 | fout.Write("".PadLeft((16-(ImageLength % 16))*5+1, ' ') + ASCIILine.PadRight(20) + " */"); |
||
1208 | |||
1209 | fout.Write("\r\n\r\n\r\n"); |
||
1210 | if (ImageLength != 0) |
||
1211 | { |
||
1212 | fout.Write("/**************************************\r\n" + |
||
1213 | " * MPFS2 C linkable symbols\r\n" + |
||
1214 | " **************************************/\r\n" + |
||
1215 | "// For C18, these are split into seperate arrays because it speeds up compilation a lot. \r\n" + |
||
1216 | "// For other compilers, the entire data array must be defined as a single variable to \r\n" + |
||
1217 | "// ensure that the linker does not reorder the data chunks in Flash when compiler \r\n" + |
||
1218 | "// optimizations are turned on.\r\n" + |
||
1219 | "#if defined(__18CXX)\r\n" + |
||
1220 | "\tROM BYTE MPFS_Start[] = {DATACHUNK000000};\r\n"); |
||
1221 | |||
1222 | for (UInt32 i = 1024; i < ImageLength; i += 1024) |
||
1223 | { |
||
1224 | fout.Write("\tROM BYTE MPFS_" + Convert.ToString((i / 1024), 16).PadLeft(6, '0') + "[] = {DATACHUNK"+Convert.ToString((i / 1024), 16).PadLeft(6, '0')+ "};\r\n"); |
||
1225 | } |
||
1226 | |||
1227 | fout.Write("#else\r\n" + |
||
1228 | "\tROM BYTE MPFS_Start[] = {"); |
||
1229 | for (UInt32 i = 0; i < ImageLength; i += 1024) |
||
1230 | { |
||
1231 | fout.Write("DATACHUNK" + Convert.ToString((i / 1024), 16).PadLeft(6, '0')); |
||
1232 | if (i + 1024 < ImageLength) |
||
1233 | fout.Write(", "); |
||
1234 | } |
||
1235 | fout.Write("};\r\n" + |
||
1236 | "#endif\r\n\r\n\r\n"); |
||
1237 | } |
||
1238 | |||
1239 | fout.Write( |
||
1240 | "/**************************************************************\r\n" + |
||
1241 | " * End of MPFS\r\n" + |
||
1242 | " **************************************************************/\r\n" + |
||
1243 | "#endif // #if defined(STACK_USE_MPFS2)\r\n" + |
||
1244 | "#endif // #if !defined(MPFS_USE_EEPROM) && !defined(MPFS_USE_SPI_FLASH)\r\n" |
||
1245 | ); |
||
1246 | fout.Flush(); |
||
1247 | fout.Close(); |
||
1248 | } |
||
1249 | } |
||
1250 | |||
1251 | |||
1252 | private class MPFS2ASM30Writer : MPFS2Writer |
||
1253 | { |
||
1254 | #region Fields |
||
1255 | protected StreamWriter fout; |
||
1256 | #endregion |
||
1257 | |||
1258 | public MPFS2ASM30Writer(String filename) |
||
1259 | { |
||
1260 | if (!filename.EndsWith(".s",StringComparison.OrdinalIgnoreCase)) |
||
1261 | filename += ".s"; |
||
1262 | fout = new StreamWriter(filename, false, Encoding.ASCII); |
||
1263 | imageName = filename; |
||
1264 | fout.Write( |
||
1265 | ";**************************************************************\r\n" + |
||
1266 | "; MPFSImg2.s\r\n" + |
||
1267 | "; Defines an MPFS2 image to be stored in program memory.\r\n" + |
||
1268 | "; Defined in ASM30 assembly for optimal storage size.\r\n" + |
||
1269 | ";\r\n" + |
||
1270 | "; NOT FOR HAND MODIFICATION\r\n" + |
||
1271 | "; This file is automatically generated by the MPFS2 Utility\r\n" + |
||
1272 | "; ALL MODIFICATIONS WILL BE OVERWRITTEN BY THE MPFS2 GENERATOR\r\n" + |
||
1273 | "; Generated " + DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToLongTimeString() + "\r\n" + |
||
1274 | ";**************************************************************\r\n\r\n" + |
||
1275 | ".equ VALID_ID,0\r\n" + |
||
1276 | ".ifdecl __dsPIC30F\r\n" + |
||
1277 | " .include \"p30fxxxx.inc\"\r\n" + |
||
1278 | ".endif\r\n" + |
||
1279 | ".ifdecl __dsPIC33F\r\n" + |
||
1280 | " .include \"p33fxxxx.inc\"\r\n" + |
||
1281 | ".endif\r\n" + |
||
1282 | ".ifdecl __PIC24H\r\n" + |
||
1283 | " .include \"p24hxxxx.inc\"\r\n" + |
||
1284 | ".endif\r\n" + |
||
1285 | ".ifdecl __PIC24F\r\n" + |
||
1286 | " .include \"p24fxxxx.inc\"\r\n" + |
||
1287 | ".endif\r\n" + |
||
1288 | ".if VALID_ID <> 1\r\n" + |
||
1289 | " .error \"Processor ID not specified in generic include files. New ASM30 assembler needs to be downloaded?\"\r\n" + |
||
1290 | ".endif\r\n" + |
||
1291 | " .text\r\n" + |
||
1292 | " .section MPFSData,code\r\n\r\n" + |
||
1293 | " goto END_OF_MPFS ; Prevent accidental execution of constant data.\r\n" + |
||
1294 | " .global BEGIN_MPFS\r\n" + |
||
1295 | "BEGIN_MPFS:" |
||
1296 | ); |
||
1297 | } |
||
1298 | |||
1299 | public override void Write(byte data) |
||
1300 | { |
||
1301 | if (ImageLength % 12 == 0) |
||
1302 | fout.Write("\r\n\t.pbyte\t"); |
||
1303 | fout.Write("0x" + Convert.ToString(data, 16).PadLeft(2, '0')); |
||
1304 | ImageLength++; |
||
1305 | if(ImageLength % 12 != 0) |
||
1306 | fout.Write(","); |
||
1307 | } |
||
1308 | |||
1309 | public override void Close() |
||
1310 | { |
||
1311 | if (ImageLength % 12 == 0) |
||
1312 | fout.Write(","); |
||
1313 | fout.Write( |
||
1314 | "0x00\r\n" + |
||
1315 | "END_OF_MPFS:\r\n\r\n" + |
||
1316 | " .section .const,psv\r\n" + |
||
1317 | " .global _MPFS_Start\r\n" + |
||
1318 | "_MPFS_Start:\r\n" + |
||
1319 | " .long paddr(BEGIN_MPFS)\r\n\r\n" + |
||
1320 | " .section MPFSHelpers,code\r\n\r\n" + |
||
1321 | " .global _ReadProgramMemory\r\n" + |
||
1322 | "_ReadProgramMemory:\r\n" + |
||
1323 | " push _TBLPAG\r\n" + |
||
1324 | " mov w1,_TBLPAG\r\n" + |
||
1325 | " mov w0,w5\r\n" + |
||
1326 | " tblrdl [w5],w0\r\n" + |
||
1327 | " tblrdh [w5],w1\r\n" + |
||
1328 | " pop _TBLPAG\r\n" + |
||
1329 | " return\r\n" |
||
1330 | ); |
||
1331 | fout.Flush(); |
||
1332 | fout.Close(); |
||
1333 | } |
||
1334 | } |
||
1335 | #endregion |
||
1336 | } |
||
1337 | |||
1338 | public class MPFSFileRecord |
||
1339 | { |
||
1340 | #region Fields |
||
1341 | private String fileName; |
||
1342 | public UInt16 nameHash; |
||
1343 | public DateTime fileDate; |
||
1344 | public byte[] data; |
||
1345 | public UInt32 locStr; |
||
1346 | public UInt32 locData; |
||
1347 | public bool hasIndex; |
||
1348 | public bool isIndex; |
||
1349 | public bool isZipped; |
||
1350 | public UInt32 dynVarCntr=0;/*Number of Dynamic Variables in the file*/ |
||
1351 | public byte[] dynVarOffsetAndIndexID = new byte[0];/*Location of dynamic var and its ID*/ |
||
1352 | public UInt32 fileRecordOffset;/* Byte location in the Record file where this file record/information is written from*/ |
||
1353 | public UInt32 fileRecordLength;/* Total length/number of bytes in this file record*/ |
||
1354 | #endregion |
||
1355 | |||
1356 | #region Constructor |
||
1357 | /// <summary> |
||
1358 | /// Sets up a new MPFSFileRecord |
||
1359 | /// </summary> |
||
1360 | public MPFSFileRecord() |
||
1361 | { |
||
1362 | locStr = 0; |
||
1363 | locData = 0; |
||
1364 | hasIndex = false; |
||
1365 | isIndex = false; |
||
1366 | isZipped = false; |
||
1367 | dynVarCntr=0; |
||
1368 | } |
||
1369 | #endregion |
||
1370 | |||
1371 | public String FileName |
||
1372 | { |
||
1373 | get { return this.fileName; } |
||
1374 | set |
||
1375 | { |
||
1376 | this.fileName = value; |
||
1377 | if(value == "") |
||
1378 | this.nameHash = 0xffff; |
||
1379 | else |
||
1380 | { |
||
1381 | this.nameHash = 0; |
||
1382 | foreach (byte b in value) |
||
1383 | { |
||
1384 | nameHash += b; |
||
1385 | nameHash <<= 1; |
||
1386 | } |
||
1387 | } |
||
1388 | } |
||
1389 | } |
||
1390 | } |
||
1391 | } |
Powered by WebSVN v2.8.3