/* * File: main.c * Author: Bruno Rybársky * * Created on November 17, 2022, 12:49 PM */ //PINS //GP0 - Button 1 //GP1 - Button 2 //GP2 - Unused //GP3 - Unused //GP4 - Serial TX //GP5 - Serial RX //END PINS //FLAGS //Flag: // Flag, 0: Debounced power outage restore GPIOdeb,3 // Flag, 1: // Flag, 2: // Flag, 3: // Flag, 4: // Flag, 5: Millis2 overflow, monitored and cleared in signal strength request // Flag, 6: // Flag, 7: GPIO0 status //Flag3: // Flag3, 0: // Flag3, 1: // Flag3, 2: // Flag3, 3: Millis3 overflow // Flag3, 4: SMS data beginning // Flag3, 5: Sending SMS data // Flag3, 6: // Flag3, 7: //Flag4: // Flag4, 0: SMS is 1 ON // Flag4, 1: SMS is 1 OFF // Flag4, 2: SMS is 2 ON // Flag4, 3: SMS is 2 OFF // Flag4, 4: // Flag4, 5: // Flag4, 6: // Flag4, 7: //START STRING RECIEVING //Flag2: // Flag2, 0: in process of recieving "OK" // Flag2, 1: in process of recieving "NO CARRIER" // Flag2, 2: in process of recieving "ERROR" // Flag2, 3: in process of recieving "SMS Ready" // Flag2, 4: // Flag2, 5: // Flag2, 6: // Flag2, 7: //FlagC: // FlagC, 0: "OK" recieved // FlagC, 1: "NO CARRIER" recieved // FlagC, 2: "ERROR" recieved // FlagC, 3: "SMS Ready" recieved // FlagC, 4: // FlagC, 5: // FlagC, 6: // FlagC, 7: //END STRING RECIEVING //END Flags // PIC12F683 Configuration Bit Settings // 'C' source line config statements // CONFIG #pragma config FOSC = INTOSCIO // Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN) #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled) #pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT enabled) #pragma config MCLRE = OFF // MCLR Pin Function Select bit (MCLR pin function is digital input, MCLR internally tied to VDD) #pragma config CP = OFF // Code Protection bit (Program memory code protection is disabled) #pragma config CPD = OFF // Data Code Protection bit (Data memory code protection is disabled) #pragma config BOREN = ON // Brown Out Detect (BOR enabled) #pragma config IESO = ON // Internal External Switchover bit (Internal External Switchover mode is enabled) #pragma config FCMEN = ON // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is enabled) #define _XTAL_FREQ 8000000 //freq for delay // #pragma config statements should precede project file includes. // Use project enums instead of #define for ON and OFF. #include /* These are the definitions */ const char String1[3] = "OK"; //ok response const char String2[27] = "+CLIP: \"+421905708125\",145"; //call state change const char String4[10] = "SMS Ready"; //modem startup const char StringDial[14] = "+421905708125"; //#define TMR0_BAUD (256-133) /* trial and error value, comes to 3603 Baud */ #define TMR0_BAUD (256-128) /* trial and error value, comes to 3603 Baud */ #define TxBUF_SIZE 32 #define RxBufSize 8 volatile char TxBuf[TxBUF_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; #define TxBUF_MASK (TxBUF_SIZE-1) volatile char RxBuf[RxBufSize]; volatile char RxIPtr; volatile char RxIPtr_old; volatile char TxFlags; volatile char RxOPtr; volatile char TxIPtr; volatile char TxOPtr; volatile char TxCount; volatile char RxChar; volatile char TxChar; volatile char RecSkips; volatile char InByte; volatile char TxSkips = 3; volatile char TxCount; volatile char RxFlags; volatile char RxBufDiff; volatile char InChar; volatile char turnOffCounter = 0; //start parsing serial data: volatile char messagePointer = 0; //flags: volatile char Flag = 0x05; char Flag2 = 0xFF; volatile char Flag3 = 0; volatile char Flag4 = 0; char FlagC = 0; volatile char GPIOtemp = 0; volatile char GPIOdeb = 0; volatile char GPIOold = 0; //end parsing serial data: //measuring time volatile char Millis = 0; /* Here's the enqueuing routine for sending data */ /* Enqueue data in the transmit buffer to send down the serial line */ /* This routine adds one character at a time to the 32 byte buffer */ /* (the size is constrained b the compiler and RAM limitations of the */ /* processor). When a character has been added, the "new data" flag is */ /* set to tell the interrupt routine to restart sending data. */ /* Note: data can be added to the buffer faster than the interrupt */ /* routine can transmit it */ void SendChar(char c) { GIE = 0; /* disable interrupts to avoid a race condition */ TxBuf[TxOPtr++] = c; TxOPtr = TxOPtr & TxBUF_MASK; TxFlags |= 0x80; GIE = 1; /* safe to restart them now */ } void SendString(const char *c) { while (*c != 0x00) { SendChar(*c); ++c; } } /* here's the interrupt handler that performs the serial I-O */ /* With an 8MHz (internal R-C) clock and the timer0 count value */ /* defined above, this gives 2400 Baud duplex communication */ /* As you will see from the original, it samples the incoming */ /* data 3 times per bit */ /* general purpose interrupt handler */ void __interrupt()isr(void) { if (T0IF) { T0IF = 0; TMR0 = TMR0_BAUD; // Increment Millis //Millis++; //if (STATUS & (1 << 2)) { // if millis overflows if (!++Millis) { // if millis overflows // Debouncing code sampling GPIO2 only runs when Millis overflows //if ((GPIOtemp & 0x0D) != (GPIO & 0x0D)) { // compare current input with last round if ((GPIO & 0x03) != GPIOold) { GPIOtemp = (GPIO & 0x03) ^ GPIOold; GPIOold = GPIO & 0x03; // GPIO2 changed, perform debouncing if (GPIOtemp & 0x01) { if (!(GPIO & 0x01)) { GPIOdeb |= (1 << 4); // arm } else { GPIOdeb |= (1 << 5); // disarm } } if (GPIOtemp & 0x02) { if (!(GPIO & 0x02)) { GPIOdeb |= (1 << 6); // arm } else { GPIOdeb |= (1 << 7); // disarm } } } if (turnOffCounter > 0 && !--turnOffCounter) { GPIO &= 0xFD; } } // Routine to receive asynchronous data from GPIO5 // credit: http://www.electro-tech-online.com/micro-controllers/18828-finding-serial-start-bit-bit-banging.html#post117227 asm("decfsz _RecSkips,F"); asm("goto DoneRS232_Rx"); asm("btfss _RxFlags,0"); // b_receiving asm("goto get_start_bit"); asm("bsf STATUS, 0"); asm("btfss GPIO, 5"); asm("bcf STATUS,0"); asm("rrf _InByte,F"); asm("movlw 3"); asm("movwf _RecSkips"); asm("btfss STATUS, 0"); asm("goto DoneRS232_Rx"); asm("movf _InByte,W"); asm("movwf _RxChar"); asm("bsf _RxFlags,1"); // b_byte_available asm("bcf _RxFlags,0"); // b_receiving RxBuf[RxIPtr++] = RxChar; /* write received byte to circular buffer */ RxIPtr = RxIPtr & 0x7; asm("goto DoneRS232_Rx"); asm("get_start_bit:"); asm("incf _RecSkips,F"); // set to 1 asm("btfsc GPIO, 5"); asm("goto DoneRS232_Rx"); asm("movlw 4"); asm("movwf _RecSkips"); asm("bsf _RxFlags,0"); // b_receiving asm("movlw 80h"); asm("movwf _InByte"); asm("DoneRS232_Rx:"); // Code to transmit data from GPIO.4 // Note: this can be done while reception is in progress, // it's full duplex // Here check if there is data being sent, or ready to send asm("btfsc _TxFlags, 6"); /* already sending ?*/ asm("goto Tx_Sending"); asm("btfsc _TxFlags, 7"); // data to send asm("goto Tx_Start_Bit"); asm("incf _TxSkips, F"); // set back to 1, so we retest next time round asm("goto DoneRS232_Tx"); // nothing to do // come here to start sending a new byte asm("Tx_Start_Bit:"); asm("decfsz _TxSkips, f"); asm("goto DoneRS232_Tx"); asm("bcf GPIO, 4"); // hardware start bit TxChar = TxBuf[TxIPtr++]; TxIPtr = TxIPtr & TxBUF_MASK; TxFlags = 8; // initialise bit count, clear FULL flag asm("bsf _TxFlags, 6"); // indicate we are sending data TxSkips = 3; asm("goto DoneRS232_Tx"); //here if we are already in the process of sending data asm("Tx_Sending:"); asm("decfsz _TxSkips, F"); // only waggle o/p every third intr. asm("goto DoneRS232_Tx"); asm("btfsc _TxFlags, 5"); // time to send stop bit? asm("goto Tx_Stop_Bit"); asm("bcf STATUS, 0"); // carry bit asm("rrf _TxChar, f"); asm("btfss STATUS, 0"); asm("goto Tx_Set_Bit"); asm("bsf GPIO, 4"); asm("goto Tx_Sent_Bit"); asm("Tx_Set_Bit:"); asm("bcf GPIO, 4"); // here we have sent the data bit, decrement the bit counter asm("Tx_Sent_Bit:"); asm("movlw 3"); asm("movwf _TxSkips"); // reset Tx skip counter for 3 more intrs asm("decf _TxFlags, F"); // bit count in lower 3 bits asm("movf _TxFlags, W"); asm("andlw 7"); asm("btfss STATUS, 2"); // if result is zero asm("goto DoneRS232_Tx"); asm("bsf _TxFlags, 5"); // all data sent, sent stop bit next time asm("goto DoneRS232_Tx"); // here to send the stop bit and check if there''s more data // to send, once this byte has completed asm("Tx_Stop_Bit:"); asm("bsf GPIO, 4"); asm("movlw 3"); asm("movwf _TxSkips"); asm("bcf _TxFlags, 6"); // sending_data flag asm("bcf _TxFlags, 5"); // send_stop_bit flag TxCount = 1 + TxOPtr - TxIPtr; asm("decfsz _TxCount, F"); // counter of number of chars still to send asm("goto Tx_More"); asm("goto DoneRS232_Tx"); // all sent asm("Tx_More:"); asm("bsf _TxFlags, 7"); // signify more data to send asm("DoneRS232_Tx:"); } } void init(void) { OPTION_REGbits.T0CS = 0; OPTION_REGbits.PSA = 0; OPTION_REGbits.PS0 = 0; OPTION_REGbits.PS1 = 0; OPTION_REGbits.PS2 = 0; OPTION_REGbits.nGPPU = 0; INTCONbits.T0IE = 1; INTCONbits.GIE = 1; CMCON0bits.CM0 = 1; CMCON0bits.CM1 = 1; CMCON0bits.CM2 = 1; OSCCONbits.IRCF0 = 1; OSCCONbits.IRCF1 = 1; OSCCONbits.IRCF2 = 1; TRISIObits.TRISIO5 = 1; TRISIObits.TRISIO4 = 0; TRISIObits.TRISIO1 = 0; TRISIObits.TRISIO0 = 1; WPUbits.WPU0 = 1; ADCON0bits.ADON = 0; ANSELbits.ANS0 = 0; ANSELbits.ANS1 = 0; ANSELbits.ANS2 = 0; ANSELbits.ANS3 = 0; GPIObits.GP1 = 0; } void startSMS(const int flagBit) { if (FlagC & (1 << 3)) { SendString("AT+CMGS=\""); SendString(StringDial); SendString("\"\n"); Flag3 |= (1 << 5); Flag4 |= (1 << flagBit); } } void processString(const char *string, volatile char *inputCharacter, const int flagBit) { if (Flag2 & (1 << flagBit)) { if (!string[messagePointer]) { FlagC |= (1 << flagBit); Flag2 &= ~(1 << flagBit); if (flagBit == 3) { SendString("AT+CMGF=1\r\n"); } if (flagBit == 1) { GPIO |= 0x02; turnOffCounter = 100; SendString("ATH\n"); } } if (*inputCharacter != string[messagePointer]) { Flag2 &= ~(1 << flagBit); } } } void handleGPIO(const int pin, const int flagBit) { if (GPIOdeb & (1 << pin)) { GPIOdeb &= ~(1 << pin); startSMS(flagBit); } } void main(void) { init(); SendChar('\n'); while (1) { handleGPIO(4, 0); handleGPIO(5, 1); if (RxIPtr != RxIPtr_old) { if (RxIPtr < RxIPtr_old) { RxBufDiff = RxBufSize - (RxIPtr_old - RxIPtr); } else { RxBufDiff = RxIPtr - RxIPtr_old; } for (char iy = 0; iy < RxBufDiff; iy++) { InChar = RxBuf[iy + RxIPtr_old]; if (InChar == 0x0A) { Flag2 = 0xFF; messagePointer = 0; } else { if (InChar == '>') { if (Flag3 & (1 << 5)) { if (Flag4 & (1 << 0)) { SendString("ON"); Flag4 &= ~(1 << 0); } if (Flag4 & (1 << 1)) { SendString("OFF"); Flag4 &= ~(1 << 1); } SendChar(26); Flag3 &= ~(1 << 5); } } processString(String1, &InChar, 0); processString(String2, &InChar, 1); processString(String4, &InChar, 3); messagePointer++; } } RxIPtr_old = RxIPtr; } } }