moel@308: /*
moel@308:   
moel@308:   Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@308: 
moel@308:   The contents of this file are subject to the Mozilla Public License Version
moel@308:   1.1 (the "License"); you may not use this file except in compliance with
moel@308:   the License. You may obtain a copy of the License at
moel@308:  
moel@308:   http://www.mozilla.org/MPL/
moel@308: 
moel@308:   Software distributed under the License is distributed on an "AS IS" basis,
moel@308:   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@308:   for the specific language governing rights and limitations under the License.
moel@308: 
moel@308:   The Original Code is the Open Hardware Monitor code.
moel@308: 
moel@308:   The Initial Developer of the Original Code is 
moel@308:   Michael Möller <m.moeller@gmx.ch>.
moel@308:   Portions created by the Initial Developer are Copyright (C) 2011
moel@308:   the Initial Developer. All Rights Reserved.
moel@308: 
moel@308:   Contributor(s):
moel@308: 
moel@308:   Alternatively, the contents of this file may be used under the terms of
moel@308:   either the GNU General Public License Version 2 or later (the "GPL"), or
moel@308:   the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@308:   in which case the provisions of the GPL or the LGPL are applicable instead
moel@308:   of those above. If you wish to allow use of your version of this file only
moel@308:   under the terms of either the GPL or the LGPL, and not to allow others to
moel@308:   use your version of this file under the terms of the MPL, indicate your
moel@308:   decision by deleting the provisions above and replace them with the notice
moel@308:   and other provisions required by the GPL or the LGPL. If you do not delete
moel@308:   the provisions above, a recipient may use your version of this file under
moel@308:   the terms of any one of the MPL, the GPL or the LGPL.
moel@308:  
moel@308: */
moel@308: 
moel@308: using System;
moel@308: using System.Collections.Generic;
moel@308: using System.IO;
moel@308: using System.IO.Compression;
moel@308: using System.Runtime.InteropServices;
moel@308: using System.Text;
moel@308: 
moel@308: namespace OpenHardwareMonitor.Hardware.Mainboard {
moel@308:   
moel@308:   internal class GigabyteTAMG {
moel@308:     private byte[] table;
moel@308: 
moel@308:     private Sensor[] sensors;
moel@308: 
moel@308:     private struct Sensor {
moel@308:       public string Name;
moel@308:       public SensorType Type;
moel@308:       public int Channel;
moel@308:       public float Value;
moel@308:     }
moel@308: 
moel@308:     private enum SensorType {
moel@308:       Voltage = 1,
moel@308:       Temperature = 2,      
moel@308:       Fan = 4,
moel@308:       Case = 8,
moel@308:     }
moel@308: 
moel@308:     public GigabyteTAMG(byte[] table) {
moel@308:       if (table == null)
moel@308:         throw new ArgumentNullException("table");
moel@308: 
moel@308:       this.table = table;
moel@308:       
moel@308:       int index = IndexOf(table, Encoding.ASCII.GetBytes("$HEALTH$"), 0);
moel@308: 
moel@308:       if (index >= 0) {
moel@308:         index += 8;
moel@308:         using (MemoryStream m =
moel@308:           new MemoryStream(table, index, table.Length - index))
moel@308:         using (BinaryReader r = new BinaryReader(m)) {
moel@308:           try {
moel@308:             r.ReadInt64();
moel@308:             int count = r.ReadInt32();
moel@308:             r.ReadInt64();
moel@308:             r.ReadInt32();
moel@308:             sensors = new Sensor[count];
moel@308:             for (int i = 0; i < sensors.Length; i++) {
moel@308:               sensors[i].Name = new string(r.ReadChars(32)).TrimEnd('\0');
moel@308:               sensors[i].Type = (SensorType)r.ReadByte();
moel@308:               sensors[i].Channel = r.ReadInt16();
moel@308:               sensors[i].Channel |= r.ReadByte() << 24;
moel@308:               r.ReadInt64();
moel@308:               int value = r.ReadInt32();
moel@308:               switch (sensors[i].Type) {
moel@308:                 case SensorType.Voltage:
moel@308:                   sensors[i].Value = 1e-3f * value; break;
moel@308:                 default:
moel@308:                   sensors[i].Value = value; break;
moel@308:               }
moel@308:               r.ReadInt64();
moel@308:             }
moel@308:           } catch (IOException) { sensors = new Sensor[0]; }
moel@308:         }
moel@308:       } else {
moel@308:         sensors = new Sensor[0]; 
moel@308:       }
moel@308:     }
moel@308: 
moel@308:     public static int IndexOf(byte[] array, byte[] pattern, int startIndex) {
moel@308:       if (array == null || pattern == null || pattern.Length > array.Length)
moel@308:         return -1;
moel@308: 
moel@308:       for (int i = startIndex; i < array.Length - pattern.Length; i++) {
moel@308:         bool found = true;
moel@308:         for (int j = 0; j < pattern.Length; j++) {
moel@308:           if (array[i + j] != pattern[j]) {
moel@308:             found = false;
moel@308:             break;
moel@308:           }
moel@308:         }
moel@308:         if (found) 
moel@308:           return i;
moel@308:       }
moel@308:       return -1;
moel@308:     }
moel@308: 
moel@308:     private string GetCompressedAndEncodedTable() {
moel@308:       string base64;
moel@308:       using (MemoryStream m = new MemoryStream()) {
moel@308:         using (GZipStream c = new GZipStream(m, CompressionMode.Compress)) {
moel@308:           c.Write(table, 0, table.Length);          
moel@308:         }
moel@308:         base64 = Convert.ToBase64String(m.ToArray());
moel@308:       }
moel@308: 
moel@308:       StringBuilder r = new StringBuilder();
moel@308:       for (int i = 0; i < Math.Ceiling(base64.Length / 64.0); i++) {
moel@308:         r.Append(" ");
moel@308:         for (int j = 0; j < 0x40; j++) {
moel@308:           int index = (i << 6) | j;
moel@308:           if (index < base64.Length) {
moel@308:             r.Append(base64[index]);
moel@308:           }
moel@308:         }
moel@308:         r.AppendLine();
moel@308:       }
moel@308: 
moel@308:       return r.ToString();
moel@308:     }
moel@308: 
moel@308:     public string GetReport() {
moel@308:       StringBuilder r = new StringBuilder();
moel@308: 
moel@308:       if (sensors.Length > 0) {
moel@308:         r.AppendLine("Gigabyte TAMG Sensors");
moel@308:         r.AppendLine();
moel@308: 
moel@308:         foreach (Sensor sensor in sensors) {
moel@308:           r.AppendFormat(" {0,-10}: {1,8:G6} ({2})", sensor.Name, sensor.Value,
moel@308:             sensor.Type);
moel@308:           r.AppendLine();
moel@308:         }
moel@308:         r.AppendLine();
moel@308:       }
moel@308: 
moel@308:       if (table.Length > 0) {
moel@308:         r.AppendLine("Gigabyte TAMG Table");
moel@308:         r.AppendLine();
moel@308:         r.Append(GetCompressedAndEncodedTable());
moel@308:         r.AppendLine();
moel@308:       }
moel@308: 
moel@308:       return r.ToString();
moel@308:     }
moel@308:   }
moel@308: }