1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
|
// SPDX-License-Identifier: BSD-3-Clause
//go:build darwin && !arm64
package sensors
import (
"context"
"errors"
"unsafe"
"github.com/shirou/gopsutil/v4/internal/common"
)
func TemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
ioKit, err := common.NewLibrary(common.IOKit)
if err != nil {
return nil, err
}
defer ioKit.Close()
smc, err := common.NewSMC(ioKit)
if err != nil {
return nil, err
}
defer smc.Close()
temperatures := make([]TemperatureStat, 0, len(temperatureKeys))
for _, key := range temperatureKeys {
temperatures = append(temperatures, TemperatureStat{
SensorKey: key,
Temperature: getTemperature(smc, key),
})
}
return temperatures, nil
}
var temperatureKeys = []string{
"TA0P", // AMBIENT_AIR_0
"TA1P", // AMBIENT_AIR_1
"TC0D", // CPU_0_DIODE
"TC0H", // CPU_0_HEATSINK
"TC0P", // CPU_0_PROXIMITY
"TB0T", // ENCLOSURE_BASE_0
"TB1T", // ENCLOSURE_BASE_1
"TB2T", // ENCLOSURE_BASE_2
"TB3T", // ENCLOSURE_BASE_3
"TG0D", // GPU_0_DIODE
"TG0H", // GPU_0_HEATSINK
"TG0P", // GPU_0_PROXIMITY
"TH0P", // HARD_DRIVE_BAY
"TM0S", // MEMORY_SLOT_0
"TM0P", // MEMORY_SLOTS_PROXIMITY
"TN0H", // NORTHBRIDGE
"TN0D", // NORTHBRIDGE_DIODE
"TN0P", // NORTHBRIDGE_PROXIMITY
"TI0P", // THUNDERBOLT_0
"TI1P", // THUNDERBOLT_1
"TW0P", // WIRELESS_MODULE
}
type smcReturn struct {
data [32]uint8
dataType uint32
dataSize uint32
kSMC uint8
}
type smcPLimitData struct {
version uint16
length uint16
cpuPLimit uint32
gpuPLimit uint32
memPLimit uint32
}
type smcKeyInfoData struct {
dataSize uint32
dataType uint32
dataAttributes uint8
}
type smcVersion struct {
major byte
minor byte
build byte
reserved byte
release uint16
}
type smcParamStruct struct {
key uint32
vers smcVersion
plimitData smcPLimitData
keyInfo smcKeyInfoData
result uint8
status uint8
data8 uint8
data32 uint32
bytes [32]byte
}
const (
smcKeySize = 4
dataTypeSp78 = "sp78"
)
func getTemperature(smc *common.SMC, key string) float64 {
result, err := readSMC(smc, key)
if err != nil {
return 0.0
}
if result.dataSize == 2 && result.dataType == toUint32(dataTypeSp78) {
return 0.0
}
return float64(result.data[0])
}
func readSMC(smc *common.SMC, key string) (*smcReturn, error) {
input := new(smcParamStruct)
resultSmc := new(smcReturn)
input.key = toUint32(key)
input.data8 = common.KSMCGetKeyInfo
result, err := callSMC(smc, input)
resultSmc.kSMC = result.result
if err != nil || result.result != common.KSMCSuccess {
return resultSmc, errors.New("ERROR: IOConnectCallStructMethod failed")
}
resultSmc.dataSize = uint32(result.keyInfo.dataSize)
resultSmc.dataType = uint32(result.keyInfo.dataSize)
input.keyInfo.dataSize = result.keyInfo.dataSize
input.data8 = common.KSMCReadKey
result, err = callSMC(smc, input)
resultSmc.kSMC = result.result
if err != nil || result.result != common.KSMCSuccess {
return resultSmc, err
}
resultSmc.data = result.bytes
return resultSmc, nil
}
func callSMC(smc *common.SMC, input *smcParamStruct) (*smcParamStruct, error) {
output := new(smcParamStruct)
inputCnt := unsafe.Sizeof(*input)
outputCnt := unsafe.Sizeof(*output)
result := smc.CallStruct(common.KSMCHandleYPCEvent,
uintptr(unsafe.Pointer(input)), inputCnt, uintptr(unsafe.Pointer(output)), &outputCnt)
if result != 0 {
return output, errors.New("ERROR: IOConnectCallStructMethod failed")
}
return output, nil
}
func toUint32(key string) uint32 {
if len(key) != smcKeySize {
return 0
}
var ans uint32
var shift uint32 = 24
for i := 0; i < smcKeySize; i++ {
ans += uint32(key[i]) << shift
shift -= 8
}
return ans
}
|