//solution to all programming exercises of chapter 7 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "program_version.h" #define BT_L2CAP_HCI_PACKET_TYPE (BT_HCI_PACKET_TYPE_DM1 | BT_HCI_PACKET_TYPE_DH1 | \ BT_HCI_PACKET_TYPE_DM3 | BT_HCI_PACKET_TYPE_DH3) FILE *uart_terminal; struct btstack* stack; struct bt_l2cap_stack* l2cap_stack; struct bt_rfcomm_stack* rfcomm_stack; #define MIN_CREDITS 10 #define MAX_CREDITS 40 void rcv_cb(u_char dlci, u_char * payload, u_short len, void *arg) { u_short idx; if (len > 0) { printf("\n"); for (idx = 0; idx < len; idx++) printf("%c ", payload[idx]); } } void con_cb(u_char dlci, u_char type, void *arg) { if (type == BT_RFCOMM_CONNECT) { printf("RFCOMM Connect on dlci %d...\n", dlci); bt_rfcomm_send_credits(dlci, MAX_CREDITS - BT_RFCOMM_DEF_CREDITS); } else { printf("RFCOMM Disconnect on dlci %d...\n", dlci); } } void line_cb(u_char dlci, u_char flags, void *arg) { printf("rfcomm Line status has changed: dlci: %d, flags: %02x\n", dlci, flags); } void credit_cb(u_char dlci, u_char credits, void *arg) { printf("rfcomm Credits running low for dlci %d. Credits remaining: %d\n", dlci, credits); printf("rfcomm Send new credits: %d\n", MAX_CREDITS - credits); bt_rfcomm_send_credits(dlci, MAX_CREDITS - credits); } //returns the 7bit ASCII value of a character int character_value(char character) { //Lookup table for 7bit ASCII code const char alphabet[128] = {'@', '@', '$', '@', '@', '@', '@', '@', '@', '@', '\n', '@', '@', '\r','@', '@','@', '_', '@', '@', '@', '@', '@','@', '@', '@', '@','@', '@', '@', '@', '@',' ', '!', '"', '#', '@', '%', '&', '\'', '(', ')','*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7','8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S','T', 'U', 'V', 'W', 'X', 'Y', 'Z', '@', '@', '@', '@', '@', '@', 'a','b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o','p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '@', '@', '@','@', '@'}; int i; for(i=0;i<128;i++){ if(character == alphabet[i]){ return i; } } return -1; //no valid character } //convert binary to integer int bin2int(char * binary) { int i; int sum = 0; int length; length = strlen(binary); for(i=0;i160){ length = 160; } strcat(message_str, "0000"); } itoa(length, buffer, 16); //convert integer to hex string strcat(message_str, buffer); for(i=0;i<=length;i++){ if(i == length){ if(base[0] != '\0'){ character = bin2int(base); itoa(character, base, 16); if(strlen(base)==1){ base[1]=base[0]; base[0]='0'; base[2]='\0'; } strcat(message_str, base); } break; } character = character_value(message[i]); if(character != -1){ strcpy(buffer,"0000000"); itoa(character, rdbuffer, 2); strcpy(buffer+7-strlen(rdbuffer), rdbuffer); if(i != 0 && i%8 !=0){ strncpy(carry, buffer+7-i%8, i%8); carry[i%8] = '\0'; strcat(carry, base); character = bin2int(carry); itoa(character, carry, 16); if(strlen(carry)==1){ carry[1]=carry[0]; carry[0]='0'; carry[2]='\0'; } strcat(message_str, carry); strncpy(base, buffer, 7-i%8); base[7-i%8] = '\0'; } else{ strcpy(base, buffer); } } else{ //ERROR: Not a valid character } } } char * process_phone_number(char * number_str, char * number) { char buffer[3] = ""; int length; //init number_str[0]='\0'; if(*number == '+'){ //skip '+' character in phone number number++; } length = strlen(number); if(length > 15){ //invalid phone number return number_str; } else { itoa(length, buffer, 16); //convert integer to hex string } strcat(number_str, buffer); strcat(number_str,"91"); while(*number != '\0' && *(number+1) != '\0'){ buffer[0] = *(number+1); buffer[1] = *number; buffer[2] = '\0'; strcat(number_str,buffer); number += 2; } if(length % 2 != 0){ buffer[0] = 'f'; buffer[1] = *number; buffer[2] = '\0'; strcat(number_str,buffer); } return number_str; } void send_sms_pdu_mode(char * number, char * message) { char* pdu = NutHeapAllocClear(172); char buffer[13]="\0"; int length; char rdbuffer[4]="\0"; char number_str[19] = ""; char* message_str = NutHeapAllocClear(147); //message header strcat(pdu,"0025000"); //process phone number if(process_phone_number(number_str, number)[0] == '\0'){ //invalid phone number return; } printf("encoded number: [%s]\n",number_str); NutSleep(500); strcat(pdu, number_str); //process message process_message(message_str, message); NutSleep(500); printf("encoded message: [%s]\n",message_str); NutSleep(500); strcat(pdu, message_str); printf("pdu: [%s]\n", pdu); NutSleep(500); //pdu length length = strlen(pdu)/2-1; //line delimiter strcat(pdu, "\x1a"); //at commands strcpy(buffer,"at+cmgs="); itoa(length, rdbuffer, 10); strcat(buffer, rdbuffer); strcat(buffer, "\r"); //sms format: pdu bt_rfcomm_send(2, "at+cmgf=0\r", 10); NutSleep(1000); //sms command bt_rfcomm_send(2, buffer, strlen(buffer)); NutSleep(1000); //message bt_rfcomm_send(2, pdu, strlen(pdu)); //insert some delay to receive the send ok message NutSleep(5000); } void send_sms(char* arg) { // configure this! // bt-address of the phone (reverse order !) bt_addr_t BTaddr = {0x9f, 0xef, 0x61, 0xde, 0x0f, 0x00}; // destination number to which sms is sent to char number[17] = "+41774325509"; char* message = NutHeapAllocClear(161); // the message strcpy(message, "Greetings from the BTnode."); //connect printf("connecting to ["ADDR_FMT"]\n",ADDR(BTaddr)); if(bt_rfcomm_start_session(BTaddr, 0, 0)){ printf("session error\n"); return; } NutSleep(1000); if(bt_rfcomm_connect(1, con_cb, rcv_cb, line_cb, credit_cb, 10, NULL)){ printf("connection error\n"); return; } NutSleep(1000); //general AT Commands bt_rfcomm_send(2, "at&f\r", 5); NutSleep(2000); bt_rfcomm_send(2, "at+cgmi\r", 8); NutSleep(1000); bt_rfcomm_send(2, "at+cgmm\r", 8); NutSleep(1000); bt_rfcomm_send(2, "at+cgsn\r", 8); NutSleep(1000); //send sms send_sms_pdu_mode(number, message); //disconnect bt_rfcomm_disconnect(2); } /** * main function that initializes the hardware, led, terminal, bluetooth * and acl communication stack and registers some predefined commands. * Use tab-tab to see the registered commands once the program is running. */ int main(void) { // serial baud rate u_long baud = 57600; // hardware init btn_hardware_init(); btn_led_init(1); // init app uart NutRegisterDevice(&APP_UART, 0, 0); freopen(APP_UART.dev_name, "r+", stdout); _ioctl(_fileno(stdout), UART_SETSPEED, &baud); // hello world! printf_P(PSTR("\n# --------------------------------------------")); printf_P(PSTR("\n# Welcome to BTnut (c) 2005 ETH Zurich\n")); printf_P(PSTR("# send-sms program version: %s\n"), PROGRAM_VERSION); printf_P(PSTR("# --------------------------------------------")); printf_P(PSTR("\nbooting bluetooth module... ")); // bluetooth module on (takes a while) btn_hardware_bt_on(); // Start the stack and let the initialization begin stack = bt_hci_init(&BT_UART); bt_hci_write_local_cod(stack, BT_HCI_SYNC, 200); printf_P(PSTR("ok.\n\r")); // give hint printf_P(PSTR("hit tab twice for a list of commands\n\r")); // terminal init btn_terminal_init(stdout, "[send-sms]$"); bt_cmds_init(stack); // Start L2CAP and RFCOMM l2cap_stack = bt_l2cap_init(stack, 8, 8, BT_L2CAP_HCI_PACKET_TYPE); l2cap_cmds_init(l2cap_stack, 1, BT_L2CAP_MIN_MTU, BT_L2CAP_MTU_DEFAULT); rfcomm_stack = bt_rfcomm_init(l2cap_stack, BT_RFCOMM_DEF_MFS, 4, 5); rfcomm_cmds_init(); bt_cmds_register_cmds(); btn_cmds_register_cmds(); nut_cmds_register_cmds(); l2cap_cmds_register_cmds(); rfcomm_cmds_register_cmds(); btn_terminal_register_cmd("sendsms", send_sms); // terminal mode btn_terminal_run(BTN_TERMINAL_NOFORK, 0); return 0; }