Skip to content

Commit

Permalink
feat: allow to write a value on a key by SMC app
Browse files Browse the repository at this point in the history
  • Loading branch information
exelban committed May 29, 2021
1 parent ed362c3 commit a040bf7
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 81 deletions.
36 changes: 33 additions & 3 deletions SMC/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,63 @@
import Foundation

func main() {
let args = CommandLine.arguments.dropFirst()
var args = CommandLine.arguments.dropFirst()
let cmd = CMDType(value: args.first ?? "")
args = args.dropFirst()

switch cmd {
case .list:
var keys = SMC.shared.getAllKeys()
args.dropFirst().forEach { (arg: String) in
args.forEach { (arg: String) in
let flag = FlagsType(value: arg)
if flag != .all {
keys = keys.filter{ $0.hasPrefix(flag.rawValue)}
}
}

print("[INFO]: found \(keys.count) keys\n")

keys.forEach { (key: String) in
let value = SMC.shared.getValue(key)
print("[\(key)] ", value ?? 0)
}
case .set:
guard let keyIndex = args.firstIndex(where: { $0 == "-k" }),
let valueIndex = args.firstIndex(where: { $0 == "-v" }),
args.indices.contains(keyIndex+1),
args.indices.contains(valueIndex+1) else{
return
}

let key = args[keyIndex+1]
if key.count != 4 {
print("[ERROR]: key must contain 4 characters!")
return
}

guard let value = Int(args[valueIndex+1]) else {
print("[ERROR]: wrong value passed!")
return
}

let result = SMC.shared.write(key, value)
if result != kIOReturnSuccess {
print("[ERROR]: " + (String(cString: mach_error_string(result), encoding: String.Encoding.ascii) ?? "unknown error"))
return
}

print("[INFO]: set \(value) on \(key)")
case .help, .unknown:
print("SMC tool\n")
print("Usage:")
print(" ./smc [command]\n")
print("Available Commands:")
print(" list list keys and values")
print(" set set value to a key")
print(" help help menu\n")
print("Available Flags:")
print(" -t list temperature sensors")
print(" -v list voltage sensors")
print(" -v list voltage sensors (list cmd) / value (set cmd)")
print(" -p list power sensors")
print(" -f list fans\n")
}
Expand Down
166 changes: 91 additions & 75 deletions SMC/smc.swift
Original file line number Diff line number Diff line change
Expand Up @@ -163,71 +163,6 @@ public class SMC {
return nil
}

private func read(_ value: UnsafeMutablePointer<SMCVal_t>) -> kern_return_t {
var result: kern_return_t = 0
var input = SMCKeyData_t()
var output = SMCKeyData_t()

input.key = FourCharCode(fromString: value.pointee.key)
input.data8 = SMCKeys.READ_KEYINFO.rawValue

result = call(SMCKeys.KERNEL_INDEX.rawValue, input: &input, output: &output)
if result != kIOReturnSuccess {
return result
}

value.pointee.dataSize = UInt32(output.keyInfo.dataSize)
value.pointee.dataType = output.keyInfo.dataType.toString()
input.keyInfo.dataSize = output.keyInfo.dataSize
input.data8 = SMCKeys.READ_BYTES.rawValue

result = call(SMCKeys.KERNEL_INDEX.rawValue, input: &input, output: &output)
if result != kIOReturnSuccess {
return result
}

memcpy(&value.pointee.bytes, &output.bytes, Int(value.pointee.dataSize))

return kIOReturnSuccess
}

private func write(_ value: SMCVal_t) -> kern_return_t {
var input = SMCKeyData_t()
var output = SMCKeyData_t()

input.key = FourCharCode(fromString: value.key)
input.data8 = SMCKeys.WRITE_BYTES.rawValue
input.keyInfo.dataSize = IOByteCount(value.dataSize)
input.bytes = (value.bytes[0], value.bytes[1], value.bytes[2], value.bytes[3], value.bytes[4], value.bytes[5],
value.bytes[6], value.bytes[7], value.bytes[8], value.bytes[9], value.bytes[10], value.bytes[11],
value.bytes[12], value.bytes[13], value.bytes[14], value.bytes[15], value.bytes[16], value.bytes[17],
value.bytes[18], value.bytes[19], value.bytes[20], value.bytes[21], value.bytes[22], value.bytes[23],
value.bytes[24], value.bytes[25], value.bytes[26], value.bytes[27], value.bytes[28], value.bytes[29],
value.bytes[30], value.bytes[31])

let result = self.call(SMCKeys.KERNEL_INDEX.rawValue, input: &input, output: &output)
if result != kIOReturnSuccess {
print("Error call(WRITE_BYTES): " + (String(cString: mach_error_string(result), encoding: String.Encoding.ascii) ?? "unknown error"))
return result
}

return kIOReturnSuccess
}

private func call(_ index: UInt8, input: inout SMCKeyData_t, output: inout SMCKeyData_t) -> kern_return_t {
let inputSize = MemoryLayout<SMCKeyData_t>.stride
var outputSize = MemoryLayout<SMCKeyData_t>.stride

return IOConnectCallStructMethod(
conn,
UInt32(index),
&input,
inputSize,
&output,
&outputSize
)
}

public func getAllKeys() -> [String] {
var list: [String] = []

Expand Down Expand Up @@ -259,6 +194,21 @@ public class SMC {
return list
}

public func write(_ key: String, _ newValue: Int) -> kern_return_t {
var value = SMCVal_t(key)
value.dataSize = 2
value.bytes = [UInt8(newValue >> 6), UInt8((newValue << 2) ^ ((newValue >> 6) << 8)), UInt8(0), UInt8(0), UInt8(0), UInt8(0),
UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0),
UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0),
UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0),
UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt8(0),
UInt8(0), UInt8(0)]

return write(value)
}

// MARK: - fans

public func setFanMode(_ id: Int, mode: FanMode) {
let fansMode = Int(self.getValue("FS! ") ?? 0)
var newMode: UInt8 = 0
Expand Down Expand Up @@ -308,16 +258,6 @@ public class SMC {
}
}

public func resetFans() {
var value = SMCVal_t("FS! ")
value.dataSize = 2

let result = write(value)
if result != kIOReturnSuccess {
print("Error write: " + (String(cString: mach_error_string(result), encoding: String.Encoding.ascii) ?? "unknown error"))
}
}

public func setFanSpeed(_ id: Int, speed: Int) {
let minSpeed = Int(self.getValue("F\(id)Mn") ?? 2500)
let maxSpeed = Int(self.getValue("F\(id)Mx") ?? 4000)
Expand Down Expand Up @@ -345,4 +285,80 @@ public class SMC {
return
}
}

public func resetFans() {
var value = SMCVal_t("FS! ")
value.dataSize = 2

let result = write(value)
if result != kIOReturnSuccess {
print("Error write: " + (String(cString: mach_error_string(result), encoding: String.Encoding.ascii) ?? "unknown error"))
}
}

// MARK: - internal functions

private func read(_ value: UnsafeMutablePointer<SMCVal_t>) -> kern_return_t {
var result: kern_return_t = 0
var input = SMCKeyData_t()
var output = SMCKeyData_t()

input.key = FourCharCode(fromString: value.pointee.key)
input.data8 = SMCKeys.READ_KEYINFO.rawValue

result = call(SMCKeys.KERNEL_INDEX.rawValue, input: &input, output: &output)
if result != kIOReturnSuccess {
return result
}

value.pointee.dataSize = UInt32(output.keyInfo.dataSize)
value.pointee.dataType = output.keyInfo.dataType.toString()
input.keyInfo.dataSize = output.keyInfo.dataSize
input.data8 = SMCKeys.READ_BYTES.rawValue

result = call(SMCKeys.KERNEL_INDEX.rawValue, input: &input, output: &output)
if result != kIOReturnSuccess {
return result
}

memcpy(&value.pointee.bytes, &output.bytes, Int(value.pointee.dataSize))

return kIOReturnSuccess
}

private func write(_ value: SMCVal_t) -> kern_return_t {
var input = SMCKeyData_t()
var output = SMCKeyData_t()

input.key = FourCharCode(fromString: value.key)
input.data8 = SMCKeys.WRITE_BYTES.rawValue
input.keyInfo.dataSize = IOByteCount(value.dataSize)
input.bytes = (value.bytes[0], value.bytes[1], value.bytes[2], value.bytes[3], value.bytes[4], value.bytes[5],
value.bytes[6], value.bytes[7], value.bytes[8], value.bytes[9], value.bytes[10], value.bytes[11],
value.bytes[12], value.bytes[13], value.bytes[14], value.bytes[15], value.bytes[16], value.bytes[17],
value.bytes[18], value.bytes[19], value.bytes[20], value.bytes[21], value.bytes[22], value.bytes[23],
value.bytes[24], value.bytes[25], value.bytes[26], value.bytes[27], value.bytes[28], value.bytes[29],
value.bytes[30], value.bytes[31])

let result = self.call(SMCKeys.KERNEL_INDEX.rawValue, input: &input, output: &output)
if result != kIOReturnSuccess {
return result
}

return kIOReturnSuccess
}

private func call(_ index: UInt8, input: inout SMCKeyData_t, output: inout SMCKeyData_t) -> kern_return_t {
let inputSize = MemoryLayout<SMCKeyData_t>.stride
var outputSize = MemoryLayout<SMCKeyData_t>.stride

return IOConnectCallStructMethod(
conn,
UInt32(index),
&input,
inputSize,
&output,
&outputSize
)
}
}
4 changes: 2 additions & 2 deletions SMC/types.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@

import Foundation

// MARK: - main

enum CMDType: String {
case list
case set
case help
case unknown

init(value: String) {
switch value {
case "list": self = .list
case "set": self = .set
case "help": self = .help
default: self = .unknown
}
Expand Down
2 changes: 1 addition & 1 deletion Stats.xcodeproj/xcshareddata/xcschemes/SMC.xcscheme
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "-t"
argument = "set -k &quot;FS! &quot; -v 0000"
isEnabled = "NO">
</CommandLineArgument>
</CommandLineArguments>
Expand Down

0 comments on commit a040bf7

Please sign in to comment.