| 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