One of the great mysteries to me was why calling write on an io port was ineffective.

I wanted to set the Apple II's configuration for the Composite monitor type and it wouldn't work at all.
0 = color
1 = bw
2 = green
3 = amber

Calling manager:machine():ioport().ports[":a2_config"]:write(1) would seemingly have no effect,

I could then print it out and see that there was no change:

[MAME]> print(manager:machine():ioport().ports[":a2_config"]:read())
[MAME]> print(manager:machine():ioport().ports[":a2_config"]:write(1))

[MAME]> print(manager:machine():ioport().ports[":a2_config"]:read())

and the trying of the field's set_value behaved strangely: only by passing it values of 1 or 0 would
get it to "cycle" through the possible values.

manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"]:set_value(0)
manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"]:set_value(1)

This made no sense to me at all.

But looking at the code to set the ioport_fields in ioport.cpp gave some clues:

void ioport_field::set_value(ioport_value value)
        m_digital_value = value != 0;

So here the m_digital value is only getting a value of 1 or 0.

So I thought, why not set the live value directly:

Adding a set_value function to the ioport_field_live in ioport.h

// internal live state of an input field
struct ioport_field_live
        // construction/destruction
        ioport_field_live(ioport_field &field, analog_field *analog);

        void set_value(ioport_value newvalue) {value = newvalue;};

and adding set_value and value to the ioport_field_live usertype in luaengine.cpp

	sol().registry().new_usertype<ioport_field_live>("ioport_field_live", "new", sol::no_constructor,
                        "set_value", &ioport_field_live::set_value,  // added set_value function
			"name", &ioport_field_live::name,
                        "value", &ioport_field_live::value);     // added access to member value

Now I can set the value directly:

[MAME]> manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live:set_value(0)
[MAME]> manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live:set_value(1)
[MAME]> manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live:set_value(2)
[MAME]> manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live:set_value(3)
[MAME]> manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live.value=2     
[MAME]> manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live.value=0
[MAME]> print(manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live.value) 
[MAME]> manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live.value=3
[MAME]> print(manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live.value)
[MAME]> print(manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live:set_value(5))

[MAME]> print(manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live.value)
[MAME]> print(manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live:set_value(2))

[MAME]> print(manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live.value)
[MAME]> print(manager:machine():ioport().ports[":a2_config"].fields["Shift key mod"].live.value)
[MAME]> print(manager:machine():ioport().ports[":a2_config"]:read())
[MAME]> manager:machine():ioport().ports[":a2_config"].fields["Shift key mod"].live.value=0 
[MAME]> print(manager:machine():ioport().ports[":a2_config"].fields["Shift key mod"].live.value)
[MAME]> print(manager:machine():ioport().ports[":a2_config"]:read())

If I set the value "out of bounds" like setting the monitor type to 5 the mame control panel will complain INVALID, but it doesn't seem to hurt anything since it gets masked off.

One thing I realize now is that .live.value=x and .live:set_value(x) are equivalent, so the set_value function probably isn't needed.

Another thing that is a bit perplexing is that you don't want to mix these two accesses:

This is the field set_value:
manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].set_value(1)
and this is the or
manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live.value=1
manager:machine():ioport().ports[":a2_config"].fields["Composite monitor type"].live.set_value(1)
When you use the field set_value, it causes strange behaviors when you use the live set_value, like inverting the field bits. So use the live one 8-)

[Linked Image from]

And one last bit: here's a print table function where you pass a lambda function that will print the .live.value for each field in the table:

It's pretty handy to show you all of the values of each field.

[MAME]> function printtf(a,f) for i,j in pairs(a) do print(i,f(j)) end end

[MAME]> printtf(manager:machine():ioport().ports[":a2_config"].fields, function(b) return end)
Composite monitor type	2
Shift key mod	0

And if you want to get tricky with lambda functions, this will print all of the values of the ports and fields:
[MAME]> function dopairs(a,f) for i,j in pairs(a) do f(i,j) end end     -- calls f on each pair i,j in the table
[MAME]> dopairs(manager:machine():ioport().ports,function(a,b) print("ports[\""..a.."\"]:read()="..b:read()) dopairs(b.fields,function(i,j) print("ports[\""..a.."\"].".."fields[\""..i.."\"]"..".live.value=" end) end)

ports[":a2_config"].fields["Composite monitor type"].live.value=2
ports[":a2_config"].fields["Shift key mod"].live.value=0
ports[":sl2:agraphtablet:a2mse_x"].fields["Mouse X 3"].live.value=0
... etc

Last edited by Golden Child; 04/21/19 04:27 PM.