Frank said:
About KeepCoins and that diverter... to where does it divert? To the
internal
cashbox? And that Ejectcoins diverter dumps collected coins to the reject
bin, where the customer can take it out again? Again, I need to see the
machine. And that would be my answer during an exam too
There's probably a diverter that has to be closed to get acceptable coins
into the internal cashbox (which usually is a staple of coins). The
internal cashbox also must allow to emit coins (one by one) on the lower
side. If you don't want to have these parts time-critical, you need some
lock-stepping. E.g. if you insert a coin, the coin falls on the scales
(let's assume we just need to weight the coin). This must close the slot to
insert a new coin. If the coin is rejected, the scales open up to the
reject bin, otherwise the scales open up to the internal cashbox. If the
coin slides through either way, the slot is reopened. The internal cashbox
needs a slider which moves out one coin at a time to the reject bin if
necessary.
So "coin inserted" is an event, as is "coin accepted" or "coin rejected";
these events also drive the lock-stepping. "coin acceptable" is a flag
(generated by the scales after a suitable amount of time), but you also
could generate an event out of that flag (then you have two events: coin
acceptable/not acceptable). Outputs are pulses with specified duration (to
drive the mechanics). The machine needs internal bookkeeping (because when
you insert coins, you get an unbalanced account). There are at least three
accounts: money the machine owns, money inside the machine, but owned by
the customer, and things for sale (soft drink cans, or whatever) inside the
machine.
Does the machine need states in the classical sense? It has to react on
events (coin inserted, button pressed), and the actions in between
certainly can go through states. The states are not necessarily encoded in
the software. E.g. you are able to track where a coin is by looking at the
events, and you can create appropriate responses:
switch(wait_for_next_event()) {
coin_inserted: lock_slot(); break;
coin_acceptable: coin_value = scale_value(); coin_to_cashbox(); break;
coin_unacceptable: coin_to_rejectbin(); break;
coin_accepted: customer_balance += coin_value;
display_balance(customer_balance);
coin_rejected: unlock_slot(); break;
button_pressed: if((customer_balance > coke_price)
&& numbers_of_cokes[button]
&& eject_bin_is_empty())) {
eject_coke(button);
coke_price = price_table[button]; // more than one soft drink possible
customer_balance -= coke_price;
display_balance(customer_balance);
internal_balance += coke_price;
number_of_cokes[button]--;
if(numbers_of_cokes[button] < low_thres)
call_for("refill");
} break;
change_pressed: while(customer_balance > 0) {
coin_value = eject_largest_coin(customer_balance);
if(coin_value == 0) call_for("coins");
customer_balance -= coin_value;
display_balance(customer_balance);
} break;
timeout: call_for("service"); break;
}
Where are the states? You have some variables like slot locked/unlocked,
which are mechanical states. It makes sure that you go from state coin
insert to coin check and coin accept/reject in a sequence, without
disturbance. Generally, however, every "state" is reachable anytime. E.g.
if you want to get out 20 cans of coke out of this machine, you can have
one person inserting quarters as fast as possible (20 cokes at 60¢, that's
48 quarters), and another person could press the "coke" button as fast as
the machine delivers (which is probably slower) without taking care of the
precise order of events.
If you have a classical state machine, getting 20 cokes for 60¢ is more
time-consuming. You need two quarters and a dime for each coke (or six
dimes or two quarters and two nickles...) or three quarters and get a dime
and a nickel in return. For each coke, you must fill the machine with the
appropriate amount of money, and *then* press the button. You'll get the
coke and the return (both takes time). Only now the machine is ready to
accept coins again. You are forced to reuse the return money.
State machines vs. event driven machines are a typical case of unnecessary
sequentializing. Enforce sequential parts through locks, not through
states. It's even not sure if you need the coin lock. Maybe it's
mechanically impossible to enter more coins than the scales can measure in
that time. Or the failure mode for two coins on the scales at the same time
is that they get rejected, anyway.