# -*- mode: text; tab-stop-list: (2 4 40 42); indent-tabs-mode: t -*- # $Id$ # Simple TAP client with modem dialer. # Typographical conventions. As far as l2poe is concerned, hyphens # are equivalent to underscores in symbol names. # The general structure and format for his is shamelessly nicked from # Libero, which lives at . #------------------------------------------------------------------------------ # The section defines simple macros. Macros may be defined # two ways: assigned and unassigned. # # Assigned macros simply assign some text to a macro name. When the # macro is invoked, it's replaced with the text that was assigned to # it. For example: # # MacroName = "Some Text Here" # # Unassigned macros are assumed to be runstate variables. The # following assigned and unassigned macros are equivalent: # # MacroName = $_[RUNSTATE]->{MacroName} # MacroName # # Unassigned macros exist as a convenience. # Port Pager_ID Message Device_Name Sys = $_[KERNEL] Arg0 = $_[ARG0] Arg1 = $_[ARG1] Arg2 = $_[ARG2] #------------------------------------------------------------------------------ # The section defines code that will be used in event handlers. # Subs which are only used once could be inlined into the state # machine definition, but that would make the definition beholden to a # single language. It should be possible to rip the Perl bits out of # l2poe and replace them with a schema like Libero does. # # Multi-line subs look like regular Perl subs, but their names can # contain hyphens. Hyphens are translated to underscores when it's # time to generate code. sub open-port { Port = POE::Wheel::ReadWrite->new ( Handle => Async->new( Device => Device_Name, Speed => 38400, Size => 7, Parity => 'e', Stop => 1, Vmin => 1, ), InputFilter => POE::Filter::Line->new( Literal => "\x0D\x0A" ), OutputFilter => POE::Filter::Stream->new(), Driver => POE::Driver::SysRW->new( BlockSize => 1 ), InputState => 'input', ); } # It turns out that a lot of subs are single lines. The single-line # sub syntax is relatively new. sub close-port delete Port; sub set-close-settle-delay Sys->delay( port_settled => 1 ); sub send-first-init-string &put( Port, 'ATZ' . CR ); sub send-second-init-string &put( Port, 'ATE0M0' . CR ); sub set-init-timeout Sys->delay( init_timeout => 5 ); sub clear-init-timeout Sys->delay( 'init_timeout' ); sub set-redial-timeout Sys->delay( redial_timeout => 4 ); sub clear-redial-timeout Sys->delay( 'redial_timeout' ); sub send-dial-command { &put( Port, 'ATDT ' . substr(Pager_ID, 3, 3) . '-6683' . CR ); } sub set-dial-timeout Sys->delay( dial_timeout => 90 ); sub clear-dial-timeout Sys->delay( 'dial_timeout' ); sub set-id-timeout Sys->delay( id_timeout => 2 ); sub clear-id-timeout Sys->delay( 'id_timeout' ); sub set-state-timeout Sys->delay( state_timeout => 15 ); sub clear-state-timeout Sys->delay( 'state_timeout' ); sub send-cr &put( Port, CR ); sub send-esc-pg1-cr { Port->set_input_filter( POE::Filter::Line->new( Literal => CR ) ); &put( Port, ESC . 'PG1' . CR ); } sub send-packet { &put( Port, &make_packet( Pager_ID, Message ) ); } sub send-eot-cr &put( Port, EOT . CR ); sub exit # does nothing sub trace-input { print STDERR "<<< ", &show($_[ARG0]), "\n"; } sub store-page-info { Device_Name = Arg0; Pager_ID = Arg1; Message = Arg2; } #------------------------------------------------------------------------------ # Each section defines a state machine. The # directive includes the name of the machine being defined, so you can # define more than one machine in the same file. This example defines # a state machine named "tap-machine". # # States follow the format: # # state-name: # event-name -> optional-default-transition # action -> optional-transition-if-action-is-true # action -> optional-transition-if-action-is-true # action -> optional-transition-if-action-is-true # ... # # The first outbound transition is followed; subsequent actions are # ignored. # start: enter -> open-modem &store-page-info open-modem: enter &open-port &set-close-settle-delay port-settled -> init-1 close-modem: (template open-modem) enter &close-port &set-close-settle-delay port-settled -> open-modem init-1: enter &send-first-init-string &set-init-timeout init-timeout -> close-modem input &trace-input /^OK$/ -> init-2 leave &clear-init-timeout init-2: enter &send-second-init-string &set-init-timeout init-timeout -> close-modem input &trace-input /^OK$/ -> dial leave &clear-init-timeout redial: enter &set-redial-timeout redial-timeout -> dial dial: enter &send-dial-command &set-dial-timeout input &trace-input /^CONNECT (\d+)/ -> tap-await-id /^NO CARRIER$/ -> redial dial-timeout -> close-modem leave &clear-dial-timeout tap-await-id: enter &set-id-timeout &set-state-timeout id-timeout &send-cr &set-id-timeout state-timeout -> close-modem input &trace-input /^ID=$/ -> tap-send-page-type /^NO CARRIER$/ -> close-modem leave &clear-id-timeout &clear-state-timeout tap-send-page-type: enter &set-state-timeout &send-esc-pg1-cr state-timeout -> close-modem input &trace-input /^\e\[p$/ -> tap-send-page-packet /^NO CARRIER$/ -> close-modem leave &clear-state-timeout tap-send-page-packet: enter &set-state-timeout &send-packet state-timeout -> close-modem input &trace-input /^\006$/ -> tap-wait-disconnect /^NO CARRIER$/ -> close-modem leave &clear-state-timeout tap-wait-disconnect: enter &set-state-timeout &send-eot-cr state-timeout -> done input &trace-input /^\e\004$/ -> done /^NO CARRIER$/ -> done leave &clear-state-timeout done: (inherits close-modem with exit) enter &close-port &set-close-settle-delay port-settled -> exit # Make a separate state for exiting to test inheritance with done. exit: enter &exit #------------------------------------------------------------------------------ # The