i2c OnReceive event does not let other function to run

hello everyone, am trying to receive data from master to slave using the Wire.onreceive(receiveEvent) method. i successfully get the data but when i try to other code or function in the receiveEvent function it just dont run or part of it run. Am trying to run toserver() function after the i2c has finish transmitting. Here is my code:

//i2c Slave Code(uno)
#include <SoftwareSerial.h>
#include <Wire.h>

SoftwareSerial gprsSerial(2, 3);// RX, TX



float frommaster[3];

float testi=63.909099;
float testi2=-20.909099;
void setup()
{
  
  Wire.begin(5);
  Wire.onReceive(receiveEvent);
  //pinMode(13,OUTPUT);
  //digitalWrite(13,LOW);

  gprsSerial.begin(4800);
  Serial.begin(9600);

  Serial.println("Config SIM900A...");
  delay(2000);
  
  Serial.println("Done!...");
  gprsSerial.flush();
  Serial.flush();

  // attach or detach from GPRS service
  gprsSerial.println("AT+CGATT?");
  delay(100);
  toSerial();

  // bearer settings
  gprsSerial.println("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"");
  delay(2000);
  toSerial();

  // bearer settings
  gprsSerial.println("AT+SAPBR=3,1,\"APN\",\"epc.tmobile.com\"");
  delay(2000);
  toSerial();

  // bearer settings
  gprsSerial.println("AT+SAPBR=1,1");
  delay(3000);
  toSerial();
}

void loop()
{

}

void receiveEvent(int howMany)
{
  while (Wire.available())
  {
    Wire.readBytes( (char *) frommaster, sizeof(frommaster));    // read 12 bytes into the array.
      
  }
toserver();

}

void toserver() {
  gprsSerial.println("");
  gprsSerial.println("AT+HTTPTERM");
  toSerial();
  delay(300);
  
  
  
  
  gprsSerial.println("AT+HTTPINIT");
  delay(2000);
  toSerial();

  // set http param value
  gprsSerial.print("AT+HTTPPARA=\"URL\",\"http://veh.pixub.com/in.php?");
  delay(500);
  gprsSerial.print("lt=");
  gprsSerial.print(frommaster[0], 6);
  
  gprsSerial.print("&lg=");
  gprsSerial.print(frommaster[1], 6);

  gprsSerial.print("&sp=");
  gprsSerial.print(frommaster[2]);

  gprsSerial.println("\"");

  delay(5000);
  toSerial();

  // set http action type 0 = GET, 1 = POST, 2 = HEAD
  gprsSerial.println("AT+HTTPACTION=0");
  delay(7000);
  toSerial();

  // read server response
  gprsSerial.println("AT+HTTPREAD=19,12");
  delay(1000);
  toSerial();
  
  gprsSerial.println("");
  gprsSerial.println("AT+HTTPTERM");
  toSerial();
  delay(300);

  gprsSerial.println("");
  delay(600);
//interrupts();
}

void toSerial()
{
  while (gprsSerial.available() != 0)
  {
    Serial.write(gprsSerial.read());
  }
}

The onReceive() method registers an interrupt service routine to be called when there is data.

You can NOT call toserver() from an interrupt service routine. All the things that it does rely on interrupts being enabled. There are disabled while your ISR runs.

This is one of the many possibilities:

volatile boolean newData = false;
volatile float frommaster[3];

...

void loop()
{
  if( newData)
  {
    toserver();

    // When 'frommaster' is not longer used, release it to be filled again.
    newData = false;     // release the float frommaster
  }
}

...

void receiveEvent( int howMany)
{
  // Extra safety check.
  // The amount of received bytes must be okay.
  // The newData must be false, because it could be used in the loop() at this moment.
  if( howMany == sizeof(frommaster) && !newData)
  {
    Wire.readBytes( (char *) frommaster, sizeof(frommaster));    // read 12 bytes into the array.
    newData = true; 
  }
}

Koepel:
This is one of the many possibilities:

volatile boolean newData = false;

volatile float frommaster[3];

...

void loop()
{
 if( newData)
 {
   toserver();

// When 'frommaster' is not longer used, release it to be filled again.
   newData = false;     // release the float frommaster
 }
}

...

void receiveEvent( int howMany)
{
 // Extra safety check.
 // The amount of received bytes must be okay.
 // The newData must be false, because it could be used in the loop() at this moment.
 if( howMany == sizeof(frommaster) && !newData)
 {
   Wire.readBytes( (char *) frommaster, sizeof(frommaster));    // read 12 bytes into the array.
   newData = true;
 }
}

The receiveEvent() triggers once per transaction.

Your if() statement will do two things, It will prevent overwrites of prior data messages by dropping packets. And if the master does not sent the expected packet size it drops it.

Hopefully that is what you want.

SoftwareSerial uses a large amount of processor time. Emulating a UART takes a lot of code. So, while a SoftwareSerial.print() is executing you could miss multiple recieveEvent().

Chuck.

Yes, that could happen. The array of floats is only released if it has been processed in the loop() in my example code. It prevents the use of disabling the interrupts, and no extra buffers are needed.
I don't know how much the SoftwareSerial will interfere with an interrupt, that could be an extra problem.