/***************************************************************************
 *   copyright           : (C) 2004 by Hendrik Sattler                     *
 *   mail                : post@hendrik-sattler.de                         *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#ifndef ATCOMMAND_H
#define ATCOMMAND_H

#include "intincl.h"

#include "stdlib.h"
#include <sys/types.h>

struct at_hw_access {
  char* (*read) (int (*stop_condition)(const char*, const size_t));
  int (*write) (const char* data, size_t count);
};

/** MUST be run before any other at_* function is used
 * @param tty must not be NULL, specifies how to access the tty
 * @param pin may be NULL, PIN to use _once_ in automatic pin handling
 */
void at_init (struct at_hw_access* tty, char* pin);
void at_set_tty(struct at_hw_access* tty);

/** test if the vendor is supported and model not blacklisted
 */
int at_sie_supported ();

/* useful wrapper around tty_read_line() that removes
 *   echos, empty lines and does pin handling
 * use tty_read_line() if you don't need those things
 */
char* at_read_line ();

/* used as callback for tty_read_line()
 */
int at_check_line_end (const char* input, const size_t len);

/** may be used directly for simple commands of the form AT<command>[=<parmlist>]
 * @param command must not be NULL
 * @param parmlist may be NULL, also see AT_READ_SUFFIX
 */
void at_command_send (const char* command, const char* parmlist);

/** may be used by syntax/value requests of the form AT<command>?
 * @param command must not be NULL
 */
void at_syntax_request (const char* command);

/** may be used to send data, e.g. requested by an "> " prompt
 */
void at_data_send (const char* data, size_t size);

/** evaluate a return value (a line returned by the phone)
 * @param reponse the reponse line
 * @param command may be NULL, needed to detect a command prefix
 * @param content if a prefix was detected and content is not NULL
 *                *content is a pointer to the first character after
 *                the command prefix in response. If no command prefix
 *                was detectet, *content points to response
 */
enum return_code {
  AT_RET_ERROR = 0x01, //also mask for errors
  AT_RET_ERROR_CME = 0x03,
  AT_RET_ERROR_CMS = 0x05,
  AT_RET_OK = 0x00,
  AT_RET_ANSWER = 0x02, //answer line for a command
  AT_RET_OTHER = 0x04 //none of the above
};
enum return_code at_line_type (const char* response,
			       const char* command,
			       char** content);


/* comfort functions */

/* used by commands that expect only two lines in the response
 * - first line for the data
 * - second line for command status
 * This returns the  data or NULL on any error.
 * A possible command prefix is removed from the data.
 * command may be NULL (avoids prefix removal)
 */
char* at_get_value (const char* command);

/** parse an AT string list
 * @param a string list that looks like '("...","...",.....,"...")'
 * @return same format as str_split()
 */
char** at_parse_stringlist (char* stringlist);

/* some shortcuts with caching
 */
char* at_get_vendor (void);
char* at_get_model (void);

/* end of comfort functions */




/** send a fragment of a binary file to the phone
 * if part or total is 0 (means deleting) the value of total is ignored
 * if part or total is negative, part and total are ignored
 * @param ftype file type, must not be NULL
 * @param slot must be a valid value for the chosen file type
 * @param part count, starting at 1, less or equal than total
 * @param total maximum part number
 */
char* at_sie_binary_write (const char* ftype, unsigned int slot,
			   int part, int total);

/** read binary files
 * @param ftype file type, must not be NULL
 * @param slot must be a valid value for the chosen file type
 */
char* at_sie_binary_read (const char* ftype, unsigned int slot);

/** write a phonebook entry
 * If number or text are NULL, both are ignored.
 * @param slot where to write to
 * @param number number of the entry
 * @param numtype GSM number type of the entry
 * @param text text of the entry
 */
void at_gen_phonebook_write (unsigned int slot, const char* number,
			     unsigned int numtype, const char* text);

/** read phonebook with a defined range
 * @param slot_low start of the range
 * @param slot_high end of the range
 */
char* at_gen_phonebook_read (unsigned int slot_low, unsigned int slot_high);
char* at_sie_phonebook_read_sorted (unsigned int slot_low, unsigned int slot_high);

/** read address book slots like a phonebook
 * @param slot address book slot to access
 * @param type type of numbers: 0-3; ignored if <0
 */
char* at_sie_phonebook_vcf_read (unsigned int slot, int type);

/** select the phonebook memory to use for further action
 * @param mem must not be NULL
 * @return return the used command or NULL if mem is NULL
 */
char* at_gen_phonebook_select (const char* mem);
char* at_sie_phonebook_select (const char* mem);

/** delete slot from the previously selected phonebook memory
 */
void at_gen_sms_delete (unsigned int slot);

/** send SMS from slot to number
 * @param number if NULL, it is ignored
 */
void at_gen_sms_slot_send (unsigned int slot, const char* number);

/** send a SMS directly (not stored in the phone)
 * @param len PDU length (use the libsmspdu helper function!)
 */
void at_gen_sms_send (unsigned int len);

/** store a SMS in the phone (not sent)
 * @param len PDU length (use the libsmspdu helper function!)
 */
void at_gen_sms_store (unsigned int len);

/** select SMS storages
 * @param mem1 must not be NULL,
 * @param mem2 if NULL, mem2 and mem3 are ignored,
 * @param mem3 if NULL, mem3 is ignored
 */
void at_gen_sms_mem (const char* mem1, const char* mem2, const char* mem3);


char* at_gen_sms_slot_read (unsigned int slot);
char* at_sie_sms_slot_read (unsigned int slot);
char* at_gen_sms_list_read (unsigned int list_id);
char* at_sie_sms_list_read (unsigned int list_id);


void at_gen_charset (const char* charset);
void at_gen_smsc (const char* number);
void at_gen_pin (const char* pin);

char* at_gen_lock (const char* lock, int mode,
		   const char* password, uint8_t class);
char* at_sie_lock (const char* lock, int mode,
		   const char* password, uint8_t class);
char* at_gen_password (const char* lock,
		       const char* oldpin,
		       const char* newpin);
char* at_sie_password (const char* lock,
		       const char* oldpin,
		       const char* newpin);

/* those functions are for direct SMS receive mode
 * see Siemens manual for L55, S45 or S35i for details
 */
void at_gen_sms_phase (int enable);
void at_gen_msg_direct (int mode, int mt, int bm, int ds);

/* Returns NULL if all keys from keylist were processed
 * else returns a pointer in keylist to the first unprocessed key.
 * This is normal, just recall it again with the new pointer
 *   (after you read the response to the issued command).
 */
char* at_gen_keypad (char* keylist, uint8_t duration, uint8_t pause);




/* common strings
 */
#define AT_PREFIX          "AT"
#define AT_GENERIC_PREFIX  "+C"
#define AT_SIEMENS_PREFIX  "^S"
#define AT_READ_SUFFIX     "?"
#define AT_REPLY_SEPERATOR ": "
#define AT_WRITE_DELIM     "="

/* often, commands are prefixed to a reply
 * or the following status messages appear
 */
#define AT_OK         "OK"
#define AT_ERROR      "ERROR"
#define AT_REPLY_PREFIX(s)  s""AT_REPLY_SEPERATOR
#define AT_ERROR_CME  AT_REPLY_PREFIX("+CME ERROR")
#define AT_ERROR_CMS  AT_REPLY_PREFIX("+CMS ERROR")

/* generic commands
 * those may work for phones from all vendors
 */
//those have no parameters at all
#define AT_GEN_INIT        "Z"     // init the phone to defaults
#define AT_GEN_VENDOR      "+CGMI" // get vendor
#define AT_GEN_MODEL       "+CGMM" // get model
#define AT_GEN_REVISION    "+CGMR" // get model revision
#define AT_GEN_IMSI        "+CGSN" // get international mobile subcriber identity ?????
#define AT_GEN_IMEI        "+CIMI" // get international mobile entity identity
#define AT_GEN_BATTERY     "+CBC"  // get battery status
#define AT_GEN_SIGNAL      "+CSQ"  // get signal strength/ber
#define AT_GEN_HANGUP      "+CHUP" // terminate a call
#define AT_GEN_CALLINFO    "+CLCC" // list current calls

//these ones may use the parameter scheme ?/=?/=<...>
#define AT_GEN_ECHO_ENABLE   "E1"    // enable echo response
#define AT_GEN_ECHO_DISABLE  "E0"    // disable echo response
#define AT_GEN_ERROR         "+CMEE" // select type of response for errors
#define AT_GEN_PB_SELECT     "+CPBS" // select phonebook memory / get list of phonebook memories
#define AT_GEN_PB_READ       "+CPBR" // read entries from phonebook
#define AT_GEN_PB_WRITE      "+CPBW" // write entries to phonebook
#define AT_GEN_SMS_MEM       "+CPMS" // select SMS memory / get list
#define AT_GEN_SMS_STORE     "+CMGW" // store SMS to slot
#define AT_GEN_SMS_DELETE    "+CMGD" // delete SMS slot
#define AT_GEN_SMS_SEND      "+CMGS" // send SMS (without storing to a slot)
#define AT_GEN_SMS_SLOT_SEND "+CMSS" // send SMS from slot
#define AT_GEN_SMS_SLOT_READ "+CMGR" // read SMS from slot (marks unread as read)
#define AT_GEN_SMS_LIST_READ "+CMGL" // read SMS by status (marks unread as read)
#define AT_GEN_SMS_PHASE     "+CSMS"
#define AT_GEN_MSG_DIRECT    "+CNMI"
#define AT_GEN_MSG_ACK       "+CNMA"
#define AT_GEN_SMSC          "+CSCA" // set/get SMSC
#define AT_GEN_CHARSET       "+CSCS" // set/get current character set
#define AT_GEN_PIN           "+CPIN" // enter pin (DANGEROUS)
#define AT_GEN_TIME          "+CCLK" // set/read time
#define AT_GEN_OPERATOR      "+COPS" // get operator
#define AT_GEN_CSD_STATUS    "+CREG" // get area code and cell id (for CSD)
#define AT_GEN_GPRS_STATUS   "+CGREG" // get area code and cell id (for GPRS)
#define AT_GEN_GPRS_ATTACH   "+CGATT" // is GPRS in attached mode?
#define AT_GEN_GPRS_CLASS    "+CGCLASS" //get GPRS class
#define AT_GEN_LOCK          "+CLCK" // set/get lock status
#define AT_GEN_PASSWORD      "+CPWD" // set/change password to a lock
#define AT_GEN_TERM_CMODE    "+CMEC" // mobile termination control mode (needed for keypad control)
#define AT_GEN_KEYPAD        "+CKPD" // keypad control

/* siemens-specific commands
 * probably only works with phones made by Siemens
 * not all of those are (really) fully documented
 */
#define AT_SIE_PB_VCF_READ    "^SDBR" // read address book like phonebook
#define AT_SIE_PB_READ_SORTED "^SPBG" // read phonebook pre-sorted
#define AT_SIE_PB_SELECT      "^SPBS" // select phonebook memory / get list of phonebook memories
#define AT_SIE_PB_DELETE      "^SDLD" // delete for phonebooks (only DC, MD and LD)
#define AT_SIE_CARD_ID        "^SCID" // get SIM card identity number
#define AT_SIE_BIN_READ       "^SBNR" // read binary data 
#define AT_SIE_BIN_WRITE      "^SBNW" // write binary data
#define AT_SIE_SMS_SLOT_READ  "^SMGR" // read SMS from slot (without marking unread as read)
#define AT_SIE_SMS_LIST_READ  "^SMGL" // read SMS by list (without marking unread as read)
#define AT_SIE_LOCK           "^SLCK" // set/get lock status
#define AT_SIE_PASSWORD       "^SPWD" // set/change password to a lock
#define AT_SIE_PREF_OP_READ   "^SPLR" // read an entry from the preferred operator list
#define AT_SIE_PREF_OP_WRITE  "^SPLW" // write an entry to the preferred operator list
#define AT_SIE_OP_LIST        "^SPLM" // read PLMN list

/* currentyl not used but available on some phones
   ^SABD // accessory for bluetooth data
   ^SACD // accessory data
   ^SACM // output ACM
   ^SBLK // clear blacklist
   ^SBMH // bookmark handling
   ^SCCM // CC monitor
   ^SCKA // sim card status
   ^SCKS // sim card status (unsolicited)
   ^SCNI // call number information
   ^SGDV // GPRS data volume
   ^SICO // icon control
   ^SIFS // query interface setting
   ^SKPD // keypad control
   ^SLNG // language settings
   ^SMSO // mobile switch off
   ^SNFS // NF hardware select
   ^SNFV // volume set
   ^SPIC // output PIN counter
   ^SPLM // get PLMN
   ^SPLR // read preferred operator list
   ^SPLW // write preferred operator list
   ^SPST // play signal tone
   ^SPTT // push to talk
   ^SRMP // ring melody playback
   ^SSET // profile setting control
   ^SSTK // SIM ToolKit
   ^SVMC // voice memo control
 */

#endif
