Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 8 additions & 15 deletions src/services/hal/drivers/modem/mode/qmi.lua
Original file line number Diff line number Diff line change
Expand Up @@ -52,29 +52,22 @@ return function(modem)

modem.uim_get_gids = function()
local gids = {}
local key_map = {
["Card result"] = "card-result",
SW1 = 'sw1',
SW2 = 'sw2',
["Read result"] = "read-result"
}

local gid1_ctx = context.with_timeout(modem.ctx, CMD_TIMEOUT)
local gid1_cmd = qmicli.uim_read_transparent(gid1_ctx, modem.primary_port, '0x3F00,0x7FFF,0x6F3E')
gid1_cmd:setpgid(true)

local gid1_out, gid1_cmd_err = gid1_cmd:combined_output()
if gid1_cmd_err then return gids, wraperr.new(gid1_cmd_err) end

local gid1_out_parsed, gid1_parse_err = utils.parse_qmicli_output(gid1_out, key_map)
if gid1_parse_err == nil and gid1_out_parsed["read-result"] then
local gid1
-- unfortnuately the parser incorrectly identifies the hex as a key value pair
-- so f:o:o:b:a:r becomes {f = o:o:b:a:r}
for k, v in pairs(gid1_out_parsed["read-result"]) do
gid1 = k .. ":" .. v
end
gids.gid1 = gid1
-- Anchor parsing to the "Read result:" section and make it nil-safe.
-- Example expected format (simplified): "Read result: 12:34:56:78"
local gid1_hex = gid1_out:match("Read result:%s*([0-9A-Fa-f:]+)")
if not gid1_hex then
return gids, wraperr.new("failed to parse GID1 from qmicli output")
end

gids.gid1 = gid1_hex:gsub(":", "")
return gids
end

Expand Down
212 changes: 212 additions & 0 deletions tests/test_hal_qmi.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
package.path = "../src/lua-fibers/?.lua;" -- fibers submodule src
.. "../src/lua-trie/src/?.lua;" -- trie submodule src
.. "../src/lua-bus/src/?.lua;" -- bus submodule src
.. "../src/?.lua;"
.. "./test_utils/?.lua;"
.. package.path
.. ";/usr/lib/lua/?.lua;/usr/lib/lua/?/init.lua"

local fiber = require "fibers.fiber"
local context = require "fibers.context"

local function test_uim_get_gids_simple()
-- Clear cached module
package.loaded["services.hal.drivers.modem.mode.qmi"] = nil

-- Mock dependencies
local mock_context = {
with_timeout = function(ctx, timeout)
return ctx
end
}

local mock_cmd = {
setpgid_called = false,
setpgid = function(self, val)
self.setpgid_called = true
end,
combined_output = function(self)
local output = [[
[/dev/cdc-wdm1] Successfully read information from the UIM:
Card result:
SW1: '0x90'
SW2: '0x00'
Read result:
FF]]
return output, nil
end
}

local mock_qmicli = {
uim_read_transparent = function(ctx, port, id)
return mock_cmd
end
}

local mock_wraperr = {
new = function(err) return err end
}

-- Load the qmi module with mocked dependencies
package.loaded["services.hal.drivers.modem.qmicli"] = mock_qmicli
package.loaded["fibers.context"] = mock_context
package.loaded["wraperr"] = mock_wraperr
package.loaded["services.hal.utils"] = require("services.hal.utils")
package.loaded["services.log"] = require("services.log")

local qmi_module = require("services.hal.drivers.modem.mode.qmi")

-- Create a mock modem object
local modem = {
ctx = context.background(),
primary_port = "/dev/cdc-wdm1"
}

-- Initialize the modem with qmi functions
qmi_module(modem)

-- Test the function
local gids, err = modem.uim_get_gids()

assert(err == nil, "expected err to be nil but got " .. tostring(err))
assert(gids ~= nil, "expected gids to be a table but got nil")
assert(gids.gid1 == "FF", "expected gid1 to be 'FF' but got '" .. tostring(gids.gid1) .. "'")
assert(mock_cmd.setpgid_called, "expected setpgid to be called")
end

local function test_uim_get_gids_complex()
-- Clear cached module
package.loaded["services.hal.drivers.modem.mode.qmi"] = nil

-- Mock dependencies
local mock_context = {
with_timeout = function(ctx, timeout)
return ctx
end
}

local mock_cmd = {
setpgid_called = false,
setpgid = function(self, val)
self.setpgid_called = true
end,
combined_output = function(self)
local output = [[
[/dev/cdc-wdm1] Successfully read information from the UIM:
Card result:
SW1: '0x90'
SW2: '0x00'
Read result:
85:FF:FF:FF:FF:FF:47:45:4E:49:45:49:4E:20:20:20:20:20:20:20]]
return output, nil
end
}

local mock_qmicli = {
uim_read_transparent = function(ctx, port, id)
return mock_cmd
end
}

local mock_wraperr = {
new = function(err) return err end
}

-- Load the qmi module with mocked dependencies
package.loaded["services.hal.drivers.modem.qmicli"] = mock_qmicli
package.loaded["fibers.context"] = mock_context
package.loaded["wraperr"] = mock_wraperr
package.loaded["services.hal.utils"] = require("services.hal.utils")
package.loaded["services.log"] = require("services.log")

local qmi_module = require("services.hal.drivers.modem.mode.qmi")

-- Create a mock modem object
local modem = {
ctx = context.background(),
primary_port = "/dev/cdc-wdm1"
}

-- Initialize the modem with qmi functions
qmi_module(modem)

-- Test the function
local gids, err = modem.uim_get_gids()

assert(err == nil, "expected err to be nil but got " .. tostring(err))
assert(gids ~= nil, "expected gids to be a table but got nil")

local expected = "85FFFFFFFFFF47454E4945494E20202020202020"
assert(gids.gid1 == expected,
"expected gid1 to be '" .. expected .. "' but got '" .. tostring(gids.gid1) .. "'")
assert(mock_cmd.setpgid_called, "expected setpgid to be called")
end

local function test_uim_get_gids_error()
-- Clear cached module
package.loaded["services.hal.drivers.modem.mode.qmi"] = nil

-- Mock dependencies
local mock_context = {
with_timeout = function(ctx, timeout)
return ctx
end
}

local mock_cmd = {
setpgid_called = false,
setpgid = function(self, val)
self.setpgid_called = true
end,
combined_output = function(self)
return "", "command failed"
end
}

local mock_qmicli = {
uim_read_transparent = function(ctx, port, id)
return mock_cmd
end
}

local mock_wraperr = {
new = function(err) return "wrapped: " .. err end
}

-- Load the qmi module with mocked dependencies
package.loaded["services.hal.drivers.modem.qmicli"] = mock_qmicli
package.loaded["fibers.context"] = mock_context
package.loaded["wraperr"] = mock_wraperr
package.loaded["services.hal.utils"] = require("services.hal.utils")
package.loaded["services.log"] = require("services.log")

local qmi_module = require("services.hal.drivers.modem.mode.qmi")

-- Create a mock modem object
local modem = {
ctx = context.background(),
primary_port = "/dev/cdc-wdm1"
}

-- Initialize the modem with qmi functions
qmi_module(modem)

-- Test the function
local gids, err = modem.uim_get_gids()

assert(err ~= nil, "expected err to be set but got nil")
assert(err == "wrapped: command failed", "expected wrapped error but got " .. tostring(err))
assert(gids ~= nil, "expected gids to be a table but got nil")
assert(next(gids) == nil, "expected gids to be empty but it has values")
end

fiber.spawn(function ()
test_uim_get_gids_simple()
test_uim_get_gids_complex()
test_uim_get_gids_error()
fiber.stop()
end)

print("running hal qmi tests")
fiber.main()
print("passed")