- #! / usr / bin / perl
- # connect the Time :: HiRes module and import
- # in the current namespace function sleep
- # feature of this function - the ability to specify
- # delay less than second
- use Time :: HiRes qw ( sleep ) ;
- # connect cc_cause.pl file containing Disconnect cause codes
- # These codes show the reason for ending the call
- # Not used in this script, but for writing
- # full-fledged dialers need to analyze this
- # parameter in the ^ CEND output: call_index, duration, end_status, cc_cause
- # my% cc_cause = do 'cc_cause.pl';
- # connect the end_status.pl file containing Call endind cause codes
- # These codes show the status of the device after the end of the call
- # Not used in this script, but for writing
- # full-fledged dialers need to analyze this
- # parameter in the ^ CEND output: call_index, duration, end_status, cc_cause
- # my% end_status = do 'end_status.pl';
- # For information:
- # CEND type messages are issued by the modem at call completion
- # and contain information about the call, the reason for ending the call
- # and the status of the device.
- # output format ^ CEND: call_index, duration, end_status, cc_cause
- # where:
- # call_index - unique call identifier
- # duration - call duration in seconds
- # end_status - device status code after call termination
- # cc_cause - call completion reason code
- # when connecting a modem to a computer with OS Linux
- # 3 usb interfaces are created for data exchange with a modem
- # usually this:
- # / dev / ttyUSB0 - modem command interface
- # / dev / ttyUSB1 - voice (with voice mode turned on) modem interface
- # / dev / ttyUSB2 - modem command interface. Different from / dev / ttyUSB0 topics
- # that it is possible to read not only modem responses to commands, but also service ones
- # posts. Such as signal quality data, ^ CEND output, etc.
- # specify the port for sending sound to the modem
- $ VOICE_PORT = "/ dev / ttyUSB1" ;
- # specify the port for submitting commands to the modem
- $ COMMAND_PORT = "/ dev / ttyUSB2" ;
- # set to:
- # 0 - to disable debug output
- # 1 - to enable debug output
- $ VERBOSE = 1 ;
- # Open the command port of the modem for reading and writing
- open my $ SENDPORT , '+ <' , $ COMMAND_PORT or die "Can't open '$ COMMAND_PORT': $! \ n " ;
- # Open the modem voice port for reading and writing
- # reading audio stream from the port in this program is not used
- # but nothing prevents you from turning this script into an answering machine for example
- open my $ SENDPORT_WAV , '+ <' , $ VOICE_PORT or die "Can't open '$ VOICE_PORT': $! \ n " ;
- # connect the list.01.pl file containing subscriber data
- my @user_list = do 'list.01.pl' ;
- # call the call function, which passes 2 parameters:
- # 1st - file name with voice message
- # 2 - subscriber data array
- call_list ( "test.voice.raw" , \ @user_list ) ;
- # at the end of the call we close all open files / ports
- exit_call ( ) ;
- # this function calls subscribers on the list
- sub call_list {
- # get the name of the file with the voice message
- my $ l_file = shift ;
- # get link to list with subscriber data
- my $ l_list = shift ;
- # load data from file with voice message
- my $ l_voice = load_voice ( $ l_file ) ;
- # This cycle runs through the list of subscribers
- # and trying to dial
- foreach $ l_info ( @ { $ l_list } ) {
- # call the function of calling to the subscriber
- my $ l_msg = call_one ( $ l_info , $ l_voice ) ;
- # Display the received message
- print $ l_msg ;
- # before calling the next caller
- # wait for 3 seconds.
- sleep 3 ;
- }
- }
- # this function tries to call the specified number
- # and if successful - broadcast voice message
- sub call_one {
- my $ l_info = shift ; # HASH with current subscriber data
- my $ l_bufer = shift ; # array with 320 byte chunks of the head message
- # this command turns on voice mode in modem
- # Once you turn it on you can delete / zaremarit
- # this command. The modem will remember the state.
- #at_send ('AT ^ CVOICE = 0');
- # give the modem a command to dial the number $ l_info -> {phone}
- # and expect a response from the modem:
- # OK - the call was successful
- # NO CARRIER - no connection to the cellular network
- my $ l_rec = at_send ( "ATD $ l_info -> {phone};" , qr / ( OK | NO CARRIER ) / ) ;
- # in case the dialing did not happen - exit the function and return the corresponding message
- Return "Subscriber $ l_info -> {name} [$ l_info -> {phone}] is not notified. NETWORK \ n " if $ l_rec eq 'NO CARRIER' ;
- # we expect the subscriber to pick up the phone
- # CONN: .... - the subscriber picked up the phone
- # CEND: .... - the subscriber is unavailable, busy or dropped a call
- $ l_rec = at_rec ( qr / \ ^ (CONN \: 1 \, 0 | CEND \:) / ) ;
- # in case the subscriber did not pick up the phone, we exit the function and return the corresponding message
- Return "The $ l_info -> {name} [$ l_info -> {phone}] subscriber is not notified. NOT AVAILABLE or RESET \ n " if $ l_rec eq 'CEND:' ;
- # switch the modem to the mode of receiving / transmitting voice
- # OK - the switch was successful
- # ERROR - switching failed
- # CEND: .... - the subscriber is unavailable, busy or dropped a call
- $ l_rec = at_send ( 'AT ^ DDSETEX = 2' , qr / ( OK | ERROR | CEND \ :) / ) ;
- # in case you failed to switch to voice mode or the subscriber did not pick up
- # tube - exit the function and return the corresponding message
- Return "The subscriber $ l_info -> {name} [$ l_info -> {phone}] is not notified. NOT AVAILABLE or RESET \ n " if $ l_rec ne 'OK' ;
- # If you get here, then the call is established and the subscriber picked up the phone
- # Sound should be transmitted to the modem in portions of 320 bytes every 0.02 seconds.
- # Set the service variable $ | In unit it disables buffering.
- # Thus, the data in the audio port will be sent immediately.
- $ | = 1 ;
- # Buffer loop with 320 byte voice message chunks
- foreach my $ c ( @ { $ l_bufer } ) {
- # Record the next piece in the voice port of the modem
- syswrite $ SENDPORT_WAV , $ c , 320 ;
- # We expect 0.02 seconds before continuing the cycle
- sleep ( 0.02 ) ;
- }
- # Hang up.
- at_send ( 'AT + CHUP' ) ;
- # We return a message about a successful alert.
- return "Subscriber $ l_info -> {name} [$ l_info -> {phone}] SUCCESSFULLY AVAILABLE \ n " ;
- }
- # This function loads a voice message into an array of 320 byte chunks.
- # takes 1 parameter - file name
- # audio data format - pcm, mono, 8000 Hertz, 16 bits, signed
- sub load_voice {
- my $ l_file_name = shift ;
- my $ l_fh = new IO :: File "<$ l_file_name" or die "Cannot open $ l_file_name: $!" ;
- binmode ( $ l_fh ) ;
- my @l_bufer = ( ) ;
- while ( read ( $ l_fh , $ l_bufer [ $ i ] , 320 ) ) { $ i ++; }
- close $ l_fh ;
- return \ @l_bufer ;
- }
- # This function sends a command to the modem's command port.
- # and waiting for the response specified in the regular expression
- # takes 2 parameters:
- # 1st - team
- # 2 - Regular Expression describing the options for the expected answers (OK by default)
- sub at_send {
- my $ l_cmd = shift ;
- my $ l_rx = shift || qr / (OK) / ;
- print $ SENDPORT "$ l_cmd \ r " ;
- print "SEND: [$ l_cmd] \ n " if $ VERBOSE ;
- return at_rec ( $ l_rx ) ;
- }
- # This function expects a response from the modem specified in the regular expression
- # takes 1 parameter - a regular expression describing the options for expected answers (OK by default)
- sub at_rec {
- my $ l_rx = shift || qr / ok / ;
- my $ recive = '' ;
- while ( ! ( $ recive = ~ $ l_rx ) ) {
- $ recive = < $ SENDPORT >;
- $ recive = ~ s / [ \ n \ r ] + // msg ;
- print "RECIVE: [$ recive] \ n " if $ VERBOSE && $ recive ;
- }
- $ recive = ~ $ l_rx ;
- print "END RECIVE: [$ recive] [$ 1] [$ l_rx] \ n " if $ VERBOSE ;
- return $ 1 ;
- }
- # This function closes the previously open ports of the modem.
- sub exit_call {
- print "ANNOUNCEMENT IS COMPLETED \ n " ;
- close $ SENDPORT_WAV ;
- at_send ( 'AT + CHUP' ) ;
- close $ SENDPORT ;
- }
# List of subscribers.
# This is an array of hash arrays in which each entry contains
# subscriber data:
# phone - subscriber's phone
# name - name of the subscriber
# It is also possible to store other subscriber data
(
{ phone => '+79111234567' , name => 'Petrov Petr Petrovich' } ,
{ phone => '+79117654321' , name => 'Vasilyev Vasily Vasilyevich' }
) ;
# disconnect cause (cc)
# English http://www.eversoft.net/dcc.html
# in Russian http://ru.wikipedia.org/wiki/Q.931
# mana by huawei
# HUAWEI CDMA Datacard Modem AT Command Interface Specification
# "http://www.letswireless.com.cn/asp_bin/downfile/2009929121443234.pdf"
#
# HUAWEI UMTS Datacard Modem AT Command Interface Specification
# "http://www.net139.com/UploadFile/menu/HUAWEI%20UMTS%20Datacard%20Modem%20AT%20Command%20Interface%20Specification_V2.3.pdf"
(
'1' => 'UNASSIGNED_CAUSE' ,
'3' => 'NO_ROUTE_TO_DEST' ,
'6' => 'CHANNEL_UNACCEPTABLE' ,
'8' => 'OPERATOR_DETERMINED_BARRING' ,
'16' => 'NORMAL_CALL_CLEARING' ,
'17' => 'USER_BUSY' ,
'18' => 'NO_USER_RESPONDING' ,
'19' => 'USER_ALERTING_NO_ANSWER' ,
'21' => 'CALL_REJECTED' ,
'22' => 'NUMBER_CHANGED' ,
'26' => 'NON_SELECTED_USER_CLEARING' ,
'27' => 'DESTINATION_OUT_OF_ORDER' ,
'28' => 'INVALID_NUMBER_FORMAT' ,
'29' => 'FACILITY_REJECTED' ,
'30' => 'RESPONSE_TO_STATUS_ENQUIRY' ,
'31' => 'NORMAL_UNSPECIFIED' ,
'34' => 'NO_CIRCUIT_CHANNEL_AVAILABLE' ,
'38' => 'NETWORK_OUT_OF_ORDER' ,
'41' => 'TEMPORARY_FAILURE' ,
'42' => 'SWITCHING_EQUIPMENT_CONGESTION' ,
'43' => 'ACCESS_INFORMATION_DISCARDED' ,
'44' => 'REQUESTED_CIRCUIT_CHANNEL_NOT_AVAILABLE' ,
'47' => 'RESOURCES_UNAVAILABLE_UNSPECIFIED' ,
'49' => 'QUALITY_OF_SERVICE_UNAVAILABLE' ,
'50' => 'REQUESTED_FACILITY_NOT_SUBSCRIBED' ,
'55' => 'INCOMING_CALL_BARRED_WITHIN_CUG' ,
'57' => 'BEARER_CAPABILITY_NOT_AUTHORISED' ,
'58' => 'BEARER_CAPABILITY_NOT_PRESENTLY_AVAILABLE' ,
'63' => 'SERVICE_OR_OPTION_NOT_AVAILABLE' ,
'65' => 'BEARER_SERVICE_NOT_IMPLEMENTED' ,
'68' => 'ACM_GEQ_ACMMAX' ,
'69' => 'REQUESTED_FACILITY_NOT_IMPLEMENTED' ,
'70' => 'ONLY_RESTRICTED_DIGITAL_INFO_BC_AVAILABLE' ,
'79' => 'SERVICE_OR_OPTION_NOT_IMPLEMENTED' ,
'81' => 'INVALID_TRANSACTION_ID_VALUE' ,
'87' => 'USER_NOT_MEMBER_OF_CUG' ,
'88' => 'INCOMPATIBLE_DESTINATION' ,
'91' => 'INVALID_TRANSIT_NETWORK_SELECTION' ,
'95' => 'SEMANTICALLY_INCORRECT_MESSAGE' ,
'96' => 'INVALID_MANDATORY_INFORMATION' ,
'97' => 'MESSAGE_TYPE_NON_EXISTENT' ,
'98' => 'MESSAGE_TYPE_NOT_COMPATIBLE_WITH_PROT_STATE' ,
'99' => 'IE_NON_EXISTENT_OR_NOT_IMPLEMENTED' ,
'100' => 'CONDITIONAL_IE_ERROR' ,
'101' => 'MESSAGE_NOT_COMPATIBLE_WITH_PROTOCOL_STATE' ,
'102' => 'RECOVERY_ON_TIMER_EXPIRY' ,
'111' => 'PROTOCOL_ERROR_UNSPECIFIED' ,
'127' => 'INTERWORKING_UNSPECIFIED' ,
'160' => 'REJ_UNSPECIFIED' ,
'161' => 'AS_REJ_RR_REL_IND' ,
'162' => 'AS_REJ_RR_RANDOM_ACCESS_FAILURE' ,
'163' => 'AS_REJ_RRC_REL_IND' ,
'164' => 'AS_REJ_RRC_CLOSE_SESSION_IND' ,
'165' => 'AS_REJ_RRC_OPEN_SESSION_FAILURE' ,
'166' => 'AS_REJ_LOW_LEVEL_FAIL' ,
'167' => 'AS_REJ_LOW_LEVEL_FAIL_REDIAL_NOT_ALLOWD' ,
'168' => 'MM_REJ_INVALID_SIM' ,
'169' => 'MM_REJ_NO_SERVICE' ,
'170' => 'MM_REJ_TIMER_T3230_EXP' ,
'171' => 'MM_REJ_NO_CELL_AVAILABLE' ,
'172' => 'MM_REJ_WRONG_STATE' ,
'173' => 'MM_REJ_ACCESS_CLASS_BLOCKED' ,
'174' => 'ABORT_MSG_RECEIVED' ,
'175' => 'OTHER_CAUSE' ,
'176' => 'CNM_REJ_TIMER_T303_EXP' ,
'177' => 'CNM_REJ_NO_RESOURCES' ,
'178' => 'CNM_MM_REL_PENDING' ,
'179' => 'CNM_INVALID_USER_DATA'
) ;
# codes Call ending cause codes
# mana by huawei
#
# HUAWEI CDMA Datacard Modem AT Command Interface Specification
# "http://www.letswireless.com.cn/asp_bin/downfile/2009929121443234.pdf"
#
# HUAWEI UMTS Datacard Modem AT Command Interface Specification
# "http://www.net139.com/UploadFile/menu/HUAWEI%20UMTS%20Datacard%20Modem%20AT%20Command%20Interface%20Specification_V2.3.pdf"
(
'0' => 'The board is offline.' ,
'21' => 'Board is out of service.' ,
'22' => 'Call is ended normally.' ,
'23' => 'Call is interrupted by BS.' ,
'24' => 'BS record is received during a call.' ,
'25' => 'BS releases a call.' ,
'26' => 'BS rejects the current SO service.' ,
'27' => 'There is an incoming BS call.' ,
'28' => 'received alert stop from BS.' ,
'29' => 'Call is ended normally.' ,
'30' => 'received end activation - OTASP call.' ,
'31' => 'MC ends call initiation or call.' ,
'34' => 'RUIM is not available.' ,
'99' => 'NDSS error.' ,
'100' => 'rxd' , cc_cause ' ,
'101' => 'After a MS initiates a call, the network fails to respond.' ,
'102' => 'MS rejects an incoming call.' ,
'103' => 'A call is rejected during the put-through process.' ,
'104' => 'The release is from the details, check' ,
'105' => 'The phone fee is used up.' ,
'106' => 'The MS is out of the service'
) ;
Source: https://habr.com/ru/post/192930/
All Articles