moel@308: /*
moel@308:  
moel@344:   This Source Code Form is subject to the terms of the Mozilla Public
moel@344:   License, v. 2.0. If a copy of the MPL was not distributed with this
moel@344:   file, You can obtain one at http://mozilla.org/MPL/2.0/.
moel@308:  
moel@344:   Copyright (C) 2011 Michael Möller <mmoeller@openhardwaremonitor.org>
moel@344: 	
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: }