BOOL net_sms_handle_reset(char *caller, char *command, char *arguments)
{
    char *p;

    net_state_enter(NET_STATE_HARDSTOP);
    return FALSE;
}
// GPRS <APN> <username> <password>
BOOL net_sms_handle_gprs(char *caller, char *command, char *arguments)
{
    BOOL gprsq_result;

    par_set(PARAM_GPRSAPN, arguments);
    arguments = net_sms_nextarg(arguments);
    if (arguments != NULL)
    {
        if ((arguments[0]=='-')&&(arguments[1]==0))
            par_set(PARAM_GPRSUSER, arguments+1);
        else
            par_set(PARAM_GPRSUSER, arguments);
        arguments = net_sms_nextarg(arguments);
        if (arguments != NULL)
        {
            if ((arguments[0]=='-')&&(arguments[1]==0))
                par_set(PARAM_GPRSPASS, arguments+1);
            else
                par_set(PARAM_GPRSPASS, arguments);
        }
    }
    gprsq_result = net_sms_handle_gprsq(caller, command, arguments);

    if (net_state != NET_STATE_DIAGMODE)
    {
        net_state_vint = NET_GPRS_RETRIES;
        net_state_enter(NET_STATE_NETINITP);
    }

    return gprsq_result;
}
// SERVER <serverip> <serverpassword> <paranoidmode>
BOOL net_sms_handle_server(char *caller, char *command, char *arguments)
{
    BOOL serverq_result;

    par_set(PARAM_SERVERIP, arguments);
    arguments = net_sms_nextarg(arguments);
    if (arguments != NULL)
    {
        par_set(PARAM_SERVERPASS, arguments);
        arguments = net_sms_nextarg(arguments);
        if (arguments != NULL)
        {
            par_set(PARAM_PARANOID, arguments);
        }
    }
    serverq_result = net_sms_handle_serverq(caller, command, arguments);

    if (net_state != NET_STATE_DIAGMODE)
    {
        net_state_vint = NET_GPRS_RETRIES;
        net_state_enter(NET_STATE_NETINITP);
    }

    return serverq_result;
}
// MODULE <vehicleid> <units> <notifications>
BOOL net_sms_handle_module(char *caller, char *command, char *arguments)
{
    BOOL moduleq_result;

    par_set(PARAM_VEHICLEID, arguments);
    arguments = net_sms_nextarg(arguments);
    if (arguments != NULL)
    {
        par_set(PARAM_MILESKM, arguments);
        arguments = net_sms_nextarg(arguments);
        if (arguments != NULL)
        {
            par_set(PARAM_NOTIFIES, arguments);
            arguments = net_sms_nextarg(arguments);
            if (arguments != NULL)
            {
                par_set(PARAM_VEHICLETYPE, arguments);
            }
        }
    }
    moduleq_result = net_sms_handle_moduleq(caller, command, arguments);
    vehicle_initialise();

    if (net_state != NET_STATE_DIAGMODE)
    {
        net_state_vint = NET_GPRS_RETRIES;
        net_state_enter(NET_STATE_NETINITP);
    }

    return moduleq_result;
}
예제 #5
0
////////////////////////////////////////////////////////////////////////
// net_initialise()
// This function is an entry point from the main() program loop, and
// gives the NET framework an opportunity to initialise itself.
//
void net_initialise(void)
  {
  // I/O configuration PORT C
  TRISC = 0x80; // Port C RC0-6 output, RC7 input
  PORTBbits.RB0 = 1;
  UARTIntInit();

  led_net(0);
  net_reg = 0;
  net_state_enter(NET_STATE_START);
  }
// VEHICLE <vehicletype>
BOOL net_sms_handle_vehicle(char *caller, char *command, char *arguments)
  {
  BOOL vehicleq_result;

  if (arguments[0]=='-') arguments[0]=0;
  par_set(PARAM_VEHICLETYPE, arguments);

  vehicleq_result = net_sms_handle_vehicleq(caller, command, arguments);
  vehicle_initialise();

  if (net_state != NET_STATE_DIAGMODE)
    net_state_enter(NET_STATE_DONETINIT);

  return vehicleq_result;
  }
BOOL net_sms_handle_ap(char *caller, char *command, char *arguments)
{
    unsigned char d = 0;
    char *p = par_get(PARAM_MODULEPASS);

    while ((d < PARAM_MAX)&&(arguments != NULL))
    {
        if ((arguments[0]=='-')&&(arguments[1]==0))
            par_set(d++, arguments+1);
        else
            par_set(d++, arguments);
        arguments = net_sms_nextarg(arguments);
    }

    if (net_state != NET_STATE_DIAGMODE)
        net_state_enter(NET_STATE_FIRSTRUN);

    return FALSE;
}
// GSMLOCK <provider>
BOOL net_sms_handle_gsmlock(char *caller, char *command, char *arguments)
  {
  BOOL gsmlockq_result;

  if (arguments == NULL)
    {
    char e[1] = "";
    par_set(PARAM_GSMLOCK, e);
    }
  else
    {
    par_set(PARAM_GSMLOCK, arguments);
    }

  gsmlockq_result = net_sms_handle_gsmlockq(caller, command, arguments);

  if (net_state != NET_STATE_DIAGMODE)
    net_state_enter(NET_STATE_DONETINIT);

  return gsmlockq_result;
  }
예제 #9
0
////////////////////////////////////////////////////////////////////////
// net_ticker()
// This function is an entry point from the main() program loop, and
// gives the NET framework a ticker call approximately once per second.
// It is used to internally generate the other net_state_ticker*() calls.
//
void net_ticker(void)
  {
  // This ticker is called once every second
  net_granular_tick++;
  if ((net_timeout_goto > 0)&&(net_timeout_ticks-- == 0))
    {
    net_state_enter(net_timeout_goto);
    }
  else
    {
    net_state_ticker1();
    }
  if ((net_granular_tick % 60)==0)
    net_state_ticker60();
  if ((net_granular_tick % 300)==0)
    net_state_ticker300();
  if ((net_granular_tick % 600)==0)
    {
    net_state_ticker600();
    net_granular_tick -= 600;
    }
  }
BOOL net_sms_handle_params(char *caller, char *command, char *arguments)
{
    unsigned char d = PARAM_MILESKM;

    while ((d < PARAM_MAX)&&(arguments != NULL))
    {
        if ((arguments[0]=='-')&&(arguments[1]==0))
            par_set(d++, arguments+1);
        else
            par_set(d++, arguments);
        arguments = net_sms_nextarg(arguments);
    }

    net_send_sms_start(caller);
    net_puts_rom(NET_MSG_PARAMS);
    net_send_sms_finish();

    vehicle_initialise();

    if (net_state != NET_STATE_DIAGMODE)
        net_state_enter(NET_STATE_DONETINIT);

    return FALSE;
}
// Receive a NET msg from the OVMS server
void net_msg_in(char* msg)
  {
  int k;

  if (net_msg_serverok == 0)
    {
    if (memcmppgm2ram(msg, (char const rom far*)"MP-S 0 ", 7) == 0)
      {
      net_msg_server_welcome(msg+7);
      }
    return; // otherwise ignore it
    }

  // Ok, we've got an encrypted message waiting for work.
  // The following is a nasty hack because base64decode doesn't like incoming
  // messages of length divisible by 4, and is really expecting a CRLF
  // terminated string, so we give it one...
  strcatpgm2ram(msg,(char const rom far*)"\r\n");
  k = base64decode(msg,net_scratchpad);
  RC4_crypt(&rx_crypto1, &rx_crypto2, net_scratchpad, k);
  if (memcmppgm2ram(net_scratchpad, (char const rom far*)"MP-0 ", 5) == 0)
    {
    msg = net_scratchpad+5;
    switch (*msg)
      {
      case 'A': // PING
        strcpypgm2ram(net_scratchpad,(char const rom far*)"MP-0 a");
        if (net_msg_sendpending==0)
          {
          net_msg_start();
          net_msg_encode_puts();
          net_msg_send();
          }
        break;
      case 'Z': // PEER connection
        if (msg[1] != '0')
          {
          net_apps_connected = 1;
          if (net_msg_sendpending==0)
            {
            net_msg_start();
            net_msg_stat();
            net_msg_gps();
            net_msg_tpms();
            net_msg_firmware();
            net_msg_environment();
            net_msg_send();
            }
          }
        else
          {
          net_apps_connected = 0;
          }
        break;
      }
    }
  else  // we lost sync, and can not decrypt, reconnect
    {
      //net_msg_disconnected();
      net_state_enter(NET_STATE_DONETINIT);
    }
  }
void net_sms_in(char *caller, char *buf, unsigned char pos)
  {
  // The buf contains an SMS command
  // and caller contains the caller telephone number
  char *p;

  // Convert SMS command (first word) to upper-case
  for (p=buf; ((*p!=0)&&(*p!=' ')); p++)
  	if ((*p > 0x60) && (*p < 0x7b)) *p=*p-0x20;

  // Command parsing...
  if (memcmppgm2ram(buf, (char const rom far*)"REGISTER ", 9) == 0)
    { // Register phone
    p = par_get(PARAM_REGPASS);
    if (strncmp(p,buf+9,strlen(p))==0)
      {
      par_set(PARAM_REGPHONE, caller);
      net_send_sms_rom(caller,NET_MSG_REGISTERED);
      }
    else
      {
#ifndef OVMS_SUPPRESS_ACCESSDENIED_SMS
        net_send_sms_rom(caller,NET_MSG_DENIED);
#endif
      }
    }
  else if (memcmppgm2ram(buf, (char const rom far*)"PASS ", 5) == 0)
    {
    p = par_get(PARAM_REGPHONE);
    if (strncmp(p,caller,strlen(p)) == 0)
      {
      par_set(PARAM_REGPASS, buf+5);
      net_send_sms_rom(caller,NET_MSG_PASSWORD);
      }
    else
      {
#ifndef OVMS_SUPPRESS_ACCESSDENIED_SMS
      net_send_sms_rom(caller,NET_MSG_DENIED);
#endif
      }
    }
  else if (memcmppgm2ram(buf, (char const rom far*)"GPS ", 4) == 0)
    {
    p = par_get(PARAM_REGPASS);
    if (strncmp(p,buf+4,strlen(p))==0)
      net_sms_gps(caller);
    else
      {
#ifndef OVMS_SUPPRESS_ACCESSDENIED_SMS
      net_send_sms_rom(caller,NET_MSG_DENIED);
#endif
      }
    }
  else if (memcmppgm2ram(buf, (char const rom far*)"GPS", 3) == 0)
    {
    p = par_get(PARAM_REGPHONE);
    if (strncmp(p,caller,strlen(p)) == 0)
      net_sms_gps(caller);
    else
      {
#ifndef OVMS_SUPPRESS_ACCESSDENIED_SMS
      net_send_sms_rom(caller,NET_MSG_DENIED);
#endif
      }
    }
  else if (memcmppgm2ram(buf, (char const rom far*)"STAT ", 5) == 0)
    {
    p = par_get(PARAM_REGPASS);
    if (strncmp(p,buf+5,strlen(p))==0)
      net_sms_stat(caller);
    else
      {
#ifndef OVMS_SUPPRESS_ACCESSDENIED_SMS
      net_send_sms_rom(caller,NET_MSG_DENIED);
#endif
      }
    }
  else if (memcmppgm2ram(buf, (char const rom far*)"STAT", 4) == 0)
    {
    p = par_get(PARAM_REGPHONE);
    if (strncmp(p,caller,strlen(p)) == 0)
      net_sms_stat(caller);
    else
      {
#ifndef OVMS_SUPPRESS_ACCESSDENIED_SMS
      net_send_sms_rom(caller,NET_MSG_DENIED);
#endif
      }
    }
  else if (memcmppgm2ram(buf, (char const rom far*)"PARAMS?", 7) == 0)
    {
    p = par_get(PARAM_REGPHONE);
    if (strncmp(p,caller,strlen(p)) == 0)
      net_sms_params(caller);
    else
      {
#ifndef OVMS_SUPPRESS_ACCESSDENIED_SMS
      net_send_sms_rom(caller,NET_MSG_DENIED);
#endif
      }
    }
  else if (memcmppgm2ram(buf, (char const rom far*)"PARAMS ", 7) == 0)
    {
    p = par_get(PARAM_REGPHONE);
    if (strncmp(p,caller,strlen(p)) == 0)
      {
      unsigned char d = PARAM_MILESKM;
      unsigned char x = 7;
      unsigned char y = x;
      while ((y<=(pos+1))&&(d < PARAM_MAX))
        {
        if ((buf[y] == ' ')||(buf[y] == '\0'))
          {
          buf[y] = '\0';
          if ((buf[x]=='-')&&(buf[x+1]=='\0'))
            buf[x] = '\0'; // Special case '-' is empty value
          par_set(d++, buf+x);
          x=++y;
          }
        else
          y++;
        }
      net_send_sms_rom(caller,NET_MSG_PARAMS);
      net_state_enter(NET_STATE_SOFTRESET);
      }
    else
      {
#ifndef OVMS_SUPPRESS_ACCESSDENIED_SMS
      net_send_sms_rom(caller,NET_MSG_DENIED);
#endif
      }
    }
  else if (memcmppgm2ram(buf, (char const rom far*)"FEATURE ", 8) == 0)
    {
    p = par_get(PARAM_REGPHONE);
    if (strncmp(p,caller,strlen(p)) == 0)
      {
      unsigned char y = 8;
      unsigned int f;
      while (y<=(pos+1))
        {
        if ((buf[y] == ' ')||(buf[y] == '\0'))
          {
          buf[y] = '\0';
          f = atoi(buf+8);
          if ((f>=0)&&(f<FEATURES_MAX))
            sys_features[f] = atoi(buf+y+1);
          break; // Exit the while loop, as we are done
          }
        else
          y++;
        }
      }
    else
      {
#ifndef OVMS_SUPPRESS_ACCESSDENIED_SMS
      net_send_sms_rom(caller,NET_MSG_DENIED);
#endif
      }
    }
  else if (memcmppgm2ram(buf, (char const rom far*)"RESET", 5) == 0)
    {
    p = par_get(PARAM_REGPHONE);
    if (strncmp(p,caller,strlen(p)) == 0)
      {
      net_state_enter(NET_STATE_HARDRESET);
      }
    else
      {
#ifndef OVMS_SUPPRESS_ACCESSDENIED_SMS
      net_send_sms_rom(caller,NET_MSG_DENIED);
#endif
      }
    }
  else // SMS didn't match any command pattern, forward to user via net msg
    {
    net_msg_forward_sms(caller, buf);
    }
  }
void net_sms_in(char *caller, char *buf, unsigned char pos)
  {
  // The buf contains an SMS command
  // and caller contains the caller telephone number
  char *p;

  // Convert SMS command (first word) to upper-case
  for (p=buf; ((*p!=0)&&(*p!=' ')); p++)
  	if ((*p > 0x60) && (*p < 0x7b)) *p=*p-0x20;

  // Command parsing...
  if (memcmppgm2ram(buf, (char const rom far*)"REGISTER ", 9) == 0)
    { // Register phone
    p = par_get(PARAM_REGPASS);
    if (strncmp(p,buf+9,strlen(p))==0)
      {
      par_set(PARAM_REGPHONE, caller);
      net_send_sms_rom(caller,NET_MSG_REGISTERED);
      }
    else
      net_send_sms_rom(caller,NET_MSG_DENIED);
    }
  else if (memcmppgm2ram(buf, (char const rom far*)"PASS ", 5) == 0)
    {
    p = par_get(PARAM_REGPHONE);
    if (strncmp(p,caller,strlen(p)) == 0)
      {
      par_set(PARAM_REGPASS, buf+5);
      net_send_sms_rom(caller,NET_MSG_PASSWORD);
      }
    else
      net_send_sms_rom(caller,NET_MSG_DENIED);
    }
  else if (memcmppgm2ram(buf, (char const rom far*)"GPS ", 4) == 0)
    {
    p = par_get(PARAM_REGPASS);
    if (strncmp(p,buf+4,strlen(p))==0)
      net_sms_gps(caller);
    else
      net_send_sms_rom(caller,NET_MSG_DENIED);
    }
  else if (memcmppgm2ram(buf, (char const rom far*)"GPS", 3) == 0)
    {
    p = par_get(PARAM_REGPHONE);
    if (strncmp(p,caller,strlen(p)) == 0)
      net_sms_gps(caller);
    else
      net_send_sms_rom(caller,NET_MSG_DENIED);
    }
  else if (memcmppgm2ram(buf, (char const rom far*)"STAT ", 5) == 0)
    {
    p = par_get(PARAM_REGPASS);
    if (strncmp(p,buf+5,strlen(p))==0)
      net_sms_stat(caller);
    else
      net_send_sms_rom(caller,NET_MSG_DENIED);
    }
  else if (memcmppgm2ram(buf, (char const rom far*)"STAT", 4) == 0)
    {
    p = par_get(PARAM_REGPHONE);
    if (strncmp(p,caller,strlen(p)) == 0)
      net_sms_stat(caller);
    else
      net_send_sms_rom(caller,NET_MSG_DENIED);
    }
  else if (memcmppgm2ram(buf, (char const rom far*)"PARAMS?", 7) == 0)
    {
    p = par_get(PARAM_REGPHONE);
    if (strncmp(p,caller,strlen(p)) == 0)
      net_sms_params(caller);
    else
      net_send_sms_rom(caller,NET_MSG_DENIED);
    }
  else if (memcmppgm2ram(buf, (char const rom far*)"PARAMS ", 7) == 0)
    {
    p = par_get(PARAM_REGPHONE);
    if (strncmp(p,caller,strlen(p)) == 0)
      {
      unsigned char d = PARAM_MILESKM;
      unsigned char x = 7;
      unsigned char y = x;
      while ((y<=(pos+1))&&(d < PARAM_MAX))
        {
        if ((buf[y] == ' ')||(buf[y] == '\0'))
          {
          buf[y] = '\0';
          if ((buf[x]=='-')&&(buf[x+1]=='\0'))
            buf[x] = '\0'; // Special case '-' is empty value
          par_set(d++, buf+x);
          x=++y;
          }
        else
          y++;
        }
      net_send_sms_rom(caller,NET_MSG_PARAMS);
      net_state_enter(NET_STATE_SOFTRESET);
      }
    else
      net_send_sms_rom(caller,NET_MSG_DENIED);
    }
  }
예제 #14
0
////////////////////////////////////////////////////////////////////////
// net_state_ticker1()
// State Model: Per-second ticker
// This function is called approximately once per second, and gives
// the state a timeslice for activity.
//
void net_state_ticker1(void)
  {
  char *p;

  switch (net_state)
    {
    case NET_STATE_START:
      net_state_vchar = net_state_vchar ^ 1; // Toggle LED on/off
      led_act(net_state_vchar);
      break;
    case NET_STATE_DOINIT:
      if ((net_timeout_ticks==10)&&(net_timeout_ticks==20))
        net_puts_rom(NET_INIT); // Try again...
      break;   
    case NET_STATE_COPS:
      net_state_vchar = net_state_vchar ^ 1; // Toggle LED on/off
      led_net(net_state_vchar);
      led_act(net_state_vchar^1);
      break;
    case NET_STATE_SOFTRESET:
      net_state_enter(NET_STATE_START);
      break;
    case NET_STATE_READY:
      if (net_watchdog > 0)
        {
        if (--net_watchdog == 0)
          {
          net_state_enter(NET_STATE_COPS); // Reset network connection
          return;
          }
        }
      if (net_msg_sendpending>0)
        {
        net_msg_sendpending++;
        if (net_msg_sendpending>60)
          {
          // Pending for more than 60 seconds..
          net_state_enter(NET_STATE_DONETINIT); // Reset GPRS link
          return;
          }
        }
      if ((net_reg == 0x01)||(net_reg == 0x05))
        {
        if ((net_msg_notify==1)&&(net_msg_serverok==1))
          {
          net_msg_notify = 0;
          delay100(10);
          net_msg_alert();
          return;
          }
        if (net_sms_notify==1)
          {
          net_sms_notify = 0;
          delay100(10);
          p = par_get(PARAM_REGPHONE);
          net_sms_stat(p);
          return;
          }
        if ((net_msg_notifyenvironment==1)&&
            (net_msg_serverok==1)&&
            (net_apps_connected>0)&&
            (net_msg_sendpending==0))
          {
          net_msg_notifyenvironment = 0;
          delay100(10);
          net_msg_start();
          net_msg_environment();
          net_msg_send();
          }
        }
      break;
    }
  }
예제 #15
0
////////////////////////////////////////////////////////////////////////
// net_state_activity()
// State Model: Some async data has been received
// This is called to indicate to the state that a complete piece of async
// data has been received in net_buf (with length net_buf_pos, and mode
// net_buf_mode), and the data should be completely handled before
// returning.
//
void net_state_activity()
  {
  if (net_buf_mode == NET_BUF_SMS)
    {
    // An SMS has arrived, and net_caller has been primed
    if ((net_reg != 0x01)&&(net_reg != 0x05))
      { // Treat this as a network registration
      net_watchdog=0; // Disable watchdog, as we have connectivity
      net_reg = 0x05;
      led_net(1);
      }
    net_sms_in(net_caller,net_buf,net_buf_pos);
    return;
    }
  else if (net_buf_mode != NET_BUF_CRLF)
    {
    // An IP data message has arrived
    net_msg_in(net_buf);
    return;
    }

  switch (net_state)
    {
    case NET_STATE_DOINIT:
      if ((net_buf_pos >= 2)&&(net_buf[0] == 'O')&&(net_buf[1] == 'K'))
        {
        net_state_enter(NET_STATE_COPS);
        }
      break;
    case NET_STATE_COPS:
      if ((net_buf_pos >= 2)&&(net_buf[0] == 'O')&&(net_buf[1] == 'K'))
        net_state_enter(NET_STATE_DONETINIT); // COPS reconnect was OK
      else if ((net_buf_pos >= 5)&&(net_buf[0] == 'E')&&(net_buf[1] == 'R'))
        net_state_enter(NET_STATE_SOFTRESET); // Reset the entire async
      break;
    case NET_STATE_DONETINIT:
      if ((net_buf_pos >= 2)&&
               (net_buf[0] == 'E')&&
               (net_buf[1] == 'R')&&
               (net_state_vchar == 5)) // ERROR response to AT+CIFSR
        {
        // This is a nasty case. The GPRS has locked up.
        // The only solution I can find is a hard reset of the modem
        led_act(0);
        net_state_enter(NET_STATE_HARDRESET);
        }
      else if ((net_buf_pos >= 2)&&
          (((net_buf[0] == 'O')&&(net_buf[1] == 'K')))|| // OK
          (((net_buf[0] == 'S')&&(net_buf[1] == 'H')))||  // SHUT OK
          (net_state_vchar == 5)) // Local IP address
        {
        net_buf_pos = 0;
        net_timeout_ticks = 60;
        net_link = 0;
        delay100(1);
        switch (++net_state_vchar)
          {
          case 1:
            net_puts_rom("AT+CGDCONT=1,\"IP\",\"");
            net_puts_ram(par_get(PARAM_GPRSAPN));
            net_puts_rom("\"\r");
            break;
          case 2:
            net_puts_rom("AT+CSTT=\"");
            net_puts_ram(par_get(PARAM_GPRSAPN));
            net_puts_rom("\",\"");
            net_puts_ram(par_get(PARAM_GPRSUSER));
            net_puts_rom("\",\"");
            net_puts_ram(par_get(PARAM_GPRSPASS));
            net_puts_rom("\"\r");
            break;
          case 3:
            net_puts_rom("AT+CIICR\r");
            break;
          case 4:
            net_puts_rom("AT+CIPHEAD=1\r");
            break;
          case 5:
            net_puts_rom("AT+CIFSR\r");
            break;
          case 6:
            net_puts_rom("AT+CLPORT=\"TCP\",\"6867\"\r");
            break;
          case 7:
            net_puts_rom("AT+CIPSTART=\"TCP\",\"");
            net_puts_ram(par_get(PARAM_SERVERIP));
            net_puts_rom("\",\"6867\"\r");
            break;
          case 8:
            net_state_enter(NET_STATE_READY);
            break;
          }
        }
      else if ((net_buf_pos>=7)&&
               (memcmppgm2ram(net_buf, (char const rom far*)"+CREG: 0", 8) == 0))
        { // Lost network connectivity during NETINIT
        net_state_enter(NET_STATE_SOFTRESET);
        }
      else if (memcmppgm2ram(net_buf, (char const rom far*)"+PDP: DEACT", 11) == 0)
        { // PDP couldn't be activated - try again...
        net_state_enter(NET_STATE_SOFTRESET);
        }
      break;
    case NET_STATE_READY:
      if (memcmppgm2ram(net_buf, (char const rom far*)"+CREG", 5) == 0)
        { // "+CREG" Network registration
        if (net_buf[8]==',')
          net_reg = net_buf[9]&0x07; // +CREG: 1,x
        else
          net_reg = net_buf[7]&0x07; // +CREG: x
        if ((net_reg == 0x01)||(net_reg == 0x05)) // Registered to network?
          {
          net_watchdog=0; // Disable watchdog, as we have connectivity
          led_net(1);
          }
        else if (net_watchdog == 0)
          {
          net_watchdog = 120; // We need connectivity within 120 seconds
          led_net(0);
          }
        }
      else if (memcmppgm2ram(net_buf, (char const rom far*)"+CLIP", 5) == 0)
        { // Incoming CALL
        if ((net_reg != 0x01)&&(net_reg != 0x05))
          { // Treat this as a network registration
          net_watchdog=0; // Disable watchdog, as we have connectivity
          net_reg = 0x05;
          led_net(1);
          }
        delay100(1);
        net_puts_rom(NET_HANGUP);
        net_notify_status();
        }
      else if (memcmppgm2ram(net_buf, (char const rom far*)"CONNECT OK", 10) == 0)
        {
        if (net_link == 0)
          {
          net_msg_start();
          net_msg_register();
          net_msg_send();
          }
        net_link = 1;
        }
      else if (memcmppgm2ram(net_buf, (char const rom far*)"STATE: ", 7) == 0)
        { // Incoming CIPSTATUS
        if (memcmppgm2ram(net_buf, (char const rom far*)"STATE: CONNECT OK", 17) == 0)
          {
          if (net_link == 0)
            {
            net_msg_start();
            net_msg_register();
            net_msg_send();
            }
          net_link = 1;
          }
        else
          {
          net_link = 0;
          if ((net_reg == 0x01)||(net_reg == 0x05))
            {
            // We have a GSM network, but CIPSTATUS is not up
            net_msg_disconnected();
            net_state_enter(NET_STATE_DONETINIT);
            }
          }
        }
      else if (memcmppgm2ram(net_buf, (char const rom far*)"SEND OK", 7) == 0)
        {
        net_msg_sendpending = 0;
        }
      else if ( (memcmppgm2ram(net_buf, (char const rom far*)"SEND FAIL", 9) == 0)||
                (memcmppgm2ram(net_buf, (char const rom far*)"CLOSED", 6) == 0)||
                (memcmppgm2ram(net_buf, (char const rom far*)"+CME ERROR", 10) == 0)||
                (memcmppgm2ram(net_buf, (char const rom far*)"+PDP: DEACT", 11) == 0) )
        { // Various GPRS error results
        // Re-initialize GPRS network and TCP socket
        net_msg_disconnected();
        net_state_enter(NET_STATE_DONETINIT);
        }
      break;
    }
  }
// Receive a NET msg from the OVMS server
void net_msg_in(char* msg)
  {
  int k;
  char s;

  if (net_msg_serverok == 0)
    {
    if (memcmppgm2ram(msg, (char const rom far*)"MP-S 0 ", 7) == 0)
      {
      net_msg_server_welcome(msg+7);
      net_granular_tick = 3590; // Nasty hack to force a status transmission in 10 seconds
      }
    return; // otherwise ignore it
    }

  // Ok, we've got an encrypted message waiting for work.
  // The following is a nasty hack because base64decode doesn't like incoming
  // messages of length divisible by 4, and is really expecting a CRLF
  // terminated string, so we give it one...
  CHECKPOINT(0x40)
  if (((strlen(msg)*4)/3) >= (NET_BUF_MAX-3))
    {
    // Quick exit to reset link if incoming message is too big
    net_state_enter(NET_STATE_DONETINIT);
    return;
    }
  strcatpgm2ram(msg,(char const rom far*)"\r\n");
  k = base64decode(msg,net_scratchpad);
  CHECKPOINT(0x41)
  RC4_crypt(&rx_crypto1, &rx_crypto2, net_scratchpad, k);
  if (memcmppgm2ram(net_scratchpad, (char const rom far*)"MP-0 ", 5) != 0)
    {
    net_state_enter(NET_STATE_DONETINIT);
    return;
    }
  msg = net_scratchpad+5;

  if ((*msg == 'E')&&(msg[1]=='M'))
    {
    // A paranoid-mode message from the server (or, more specifically, app)
    // The following is a nasty hack because base64decode doesn't like incoming
    // messages of length divisible by 4, and is really expecting a CRLF
    // terminated string, so we give it one...
    msg += 2; // Now pointing to the code just before encrypted paranoid message
    strcatpgm2ram(msg,(char const rom far*)"\r\n");
    k = base64decode(msg+1,net_msg_scratchpad+1);
    RC4_setup(&pm_crypto1, &pm_crypto2, pdigest, MD5_SIZE);
    for (k=0;k<1024;k++)
      {
      net_scratchpad[0] = 0;
      RC4_crypt(&pm_crypto1, &pm_crypto2, net_scratchpad, 1);
      }
    RC4_crypt(&pm_crypto1, &pm_crypto2, net_msg_scratchpad+1, k);
    net_msg_scratchpad[0] = *msg; // The code
    // The message is now out of paranoid mode...
    msg = net_msg_scratchpad;
    }

  CHECKPOINT(0x42)
  switch (*msg)
    {
    case 'A': // PING
      strcpypgm2ram(net_scratchpad,(char const rom far*)"MP-0 a");
      if (net_msg_sendpending==0)
        {
        net_msg_start();
        net_msg_encode_puts();
        net_msg_send();
        }
      break;
    case 'Z': // PEER connection
      if (msg[1] != '0')
        {
        net_apps_connected = 1;
        if (net_msg_sendpending==0)
          {
          net_msg_start();
          net_msgp_stat(0);
          net_msgp_gps(0);
          net_msgp_tpms(0);
          net_msgp_firmware(0);
          net_msgp_environment(0);
          net_msg_send();
          }
        }
      else
        {
        net_apps_connected = 0;
        }
      break;
    case 'h': // Historical data acknowledgement
#ifdef OVMS_LOGGINGMODULE
      logging_ack(atoi(msg+1));
#endif // #ifdef OVMS_LOGGINGMODULE
      break;
    case 'C': // COMMAND
      net_msg_cmd_in(msg+1);
      if (net_msg_sendpending==0) net_msg_cmd_do();
      break;
    }
  }
BOOL net_msg_cmd_exec(void)
  {
  int k;
  char *p, *s;

  delay100(2);

  CHECKPOINT(0x43)

  switch (net_msg_cmd_code)
    {
    case 1: // Request feature list (params unused)
      for (k=0;k<FEATURES_MAX;k++)
        {
          s = stp_i(net_scratchpad, "MP-0 c1,0,", k);
          s = stp_i(s, ",", FEATURES_MAX);
          s = stp_i(s, ",", sys_features[k]);
          net_msg_encode_puts();
        }
      break;

    case 2: // Set feature (params: feature number, value)
      for (p=net_msg_cmd_msg;(*p != 0)&&(*p != ',');p++) ;
      // check if a value exists and is separated by a comma
      if (*p == ',')
        {
        *p++ = 0;
        // At this point, <net_msg_cmd_msg> points to the command, and <p> to the param value
        k = atoi(net_msg_cmd_msg);
        if ((k>=0)&&(k<FEATURES_MAX))
          {
          sys_features[k] = atoi(p);
          if (k>=FEATURES_MAP_PARAM) // Top N features are persistent
            par_set(PARAM_FEATURE_S+(k-FEATURES_MAP_PARAM), p);
          if (k == FEATURE_CANWRITE) vehicle_initialise();
          STP_OK(net_scratchpad, net_msg_cmd_code);
          }
        else
          {
          STP_INVALIDRANGE(net_scratchpad, net_msg_cmd_code);
          }
        }
      else
        {
        STP_INVALIDSYNTAX(net_scratchpad, net_msg_cmd_code);
        }
      net_msg_encode_puts();
      break;

    case 3: // Request parameter list (params unused)
      for (k=0;k<PARAM_MAX;k++)
        {
          p = par_get(k);
          if (k==PARAM_SERVERPASS) *p=0; // Don't show netpass1
          s = stp_i(net_scratchpad, "MP-0 c3,0,", k);
          s = stp_i(s, ",", PARAM_MAX);
          s = stp_s(s, ",", p);
          net_msg_encode_puts();
        }
      break;

    case 4: // Set parameter (params: param number, value)
      for (p=net_msg_cmd_msg;(*p != 0)&&(*p != ',');p++) ;
      // check if a value exists and is separated by a comma
      if (*p == ',')
        {
        *p++ = 0;
        // At this point, <net_msg_cmd_msg> points to the command, and <p> to the param value
        k = atoi(net_msg_cmd_msg);
        if ((k>=0)&&(k<PARAM_FEATURE_S))
          {
          par_set(k, p);
          STP_OK(net_scratchpad, net_msg_cmd_code);
          if ((k==PARAM_MILESKM) || (k==PARAM_VEHICLETYPE)) vehicle_initialise();
          }
        else
          {
          STP_INVALIDRANGE(net_scratchpad, net_msg_cmd_code);
          }
        }
      else
        {
        STP_INVALIDSYNTAX(net_scratchpad, net_msg_cmd_code);
        }
      net_msg_encode_puts();
      break;

    case 5: // Reboot (params unused)
      STP_OK(net_scratchpad, net_msg_cmd_code);
      net_msg_encode_puts();
      net_state_enter(NET_STATE_HARDSTOP);
      break;

    case 6: // CHARGE ALERT (params unused)
      net_msg_alert();
      net_msg_encode_puts();
      break;

    case 40: // Send SMS (params: phone number, SMS message)
      for (p=net_msg_cmd_msg;(*p != 0)&&(*p != ',');p++) ;
      // check if a value exists and is separated by a comma
      if (*p == ',')
        {
        *p++ = 0;
        // At this point, <net_msg_cmd_msg> points to the phone number, and <p> to the SMS message
        net_send_sms_start(net_msg_cmd_msg);
        net_puts_ram(p);
        net_puts_rom("\x1a");
        delay100(5);
        net_msg_start();
        STP_OK(net_scratchpad, net_msg_cmd_code);
        }
      else
        {
        net_msg_start();
        STP_INVALIDSYNTAX(net_scratchpad, net_msg_cmd_code);
        }
      net_msg_encode_puts();
      delay100(2);
      break;

    case 41: // Send MMI/USSD Codes (param: USSD_CODE)
      net_puts_rom("AT+CUSD=1,\"");
      net_puts_ram(net_msg_cmd_msg);
      net_puts_rom("\",15\r");
      // cmd reply #1 to acknowledge command:
      delay100(5);
      net_msg_start();
      STP_OK(net_scratchpad, net_msg_cmd_code);
      net_msg_encode_puts();
      delay100(2);
      // cmd reply #2 sent on USSD response, see net_msg_reply_ussd()
      break;
      
    case 49: // Send raw AT command (param: raw AT command)
      net_puts_ram(net_msg_cmd_msg);
      net_puts_rom("\r");
      delay100(5);
      net_msg_start();
      STP_OK(net_scratchpad, net_msg_cmd_code);
      net_msg_encode_puts();
      delay100(2);
      break;
    default:
      return FALSE;
    }

  return TRUE;
  }
BOOL net_msg_cmd_exec(void)
  {
  int k;
  char *p, *s;

  delay100(2);

  CHECKPOINT(0x43)

  switch (net_msg_cmd_code)
    {
    case 1: // Request feature list (params unused)
      for (k=0;k<FEATURES_MAX;k++)
        {
          s = stp_i(net_scratchpad, "MP-0 c1,0,", k);
          s = stp_i(s, ",", FEATURES_MAX);
          s = stp_i(s, ",", sys_features[k]);
          net_msg_encode_puts();
        }
      break;

    case 2: // Set feature (params: feature number, value)
      for (p=net_msg_cmd_msg;(*p != 0)&&(*p != ',');p++) ;
      // check if a value exists and is separated by a comma
      if (*p == ',')
        {
        *p++ = 0;
        // At this point, <net_msg_cmd_msg> points to the command, and <p> to the param value
        k = atoi(net_msg_cmd_msg);
        if ((k>=0)&&(k<FEATURES_MAX))
          {
          sys_features[k] = atoi(p);
          if (k>=FEATURES_MAP_PARAM) // Top N features are persistent
            par_set(PARAM_FEATURE_S+(k-FEATURES_MAP_PARAM), p);
          if (k == FEATURE_CANWRITE) vehicle_initialise();
          STP_OK(net_scratchpad, net_msg_cmd_code);
          }
        else
          {
          STP_INVALIDRANGE(net_scratchpad, net_msg_cmd_code);
          }
        }
      else
        {
        STP_INVALIDSYNTAX(net_scratchpad, net_msg_cmd_code);
        }
      net_msg_encode_puts();
      break;

    case 3: // Request parameter list (params unused)
      for (k=0;k<PARAM_MAX;k++)
        {
          p = par_get(k);
          if (k==PARAM_SERVERPASS) *p=0; // Don't show netpass1
          s = stp_i(net_scratchpad, "MP-0 c3,0,", k);
          s = stp_i(s, ",", PARAM_MAX);
          s = stp_s(s, ",", p);
          net_msg_encode_puts();
        }
      break;

    case 4: // Set parameter (params: param number, value)
      for (p=net_msg_cmd_msg;(*p != 0)&&(*p != ',');p++) ;
      // check if a value exists and is separated by a comma
      if (*p == ',')
        {
        *p++ = 0;
        // At this point, <net_msg_cmd_msg> points to the command, and <p> to the param value
        k = atoi(net_msg_cmd_msg);
        if ((k>=0)&&(k<PARAM_FEATURE_S))
          {
          par_set(k, p);
          STP_OK(net_scratchpad, net_msg_cmd_code);
          if ((k==PARAM_MILESKM) || (k==PARAM_VEHICLETYPE)) vehicle_initialise();
#ifdef OVMS_ACCMODULE
          // Reset the ACC state it an ACC parameter is changed
          if ((k>=PARAM_ACC_S)&&(k<(PARAM_ACC_S+PARAM_ACC_COUNT)))
            acc_state_enter(ACC_STATE_FIRSTRUN);
#endif
          }
        else
          {
          STP_INVALIDRANGE(net_scratchpad, net_msg_cmd_code);
          }
        }
      else
        {
        STP_INVALIDSYNTAX(net_scratchpad, net_msg_cmd_code);
        }
      net_msg_encode_puts();
      break;

    case 5: // Reboot (params unused)
      STP_OK(net_scratchpad, net_msg_cmd_code);
      net_msg_encode_puts();
      net_state_enter(NET_STATE_HARDSTOP);
      break;

    case 6: // CHARGE ALERT (params unused)
      net_msg_alert();
      net_msg_encode_puts();
      break;

    case 7: // SMS command wrapper

      // process command:
      net_msg_bufpos = net_msg_scratchpad;
      k = net_sms_in(par_get(PARAM_REGPHONE), net_msg_cmd_msg);
      net_msg_bufpos = NULL;
      // output is now in net_msg_scratchpad

      // create return string:
      s = stp_i(net_scratchpad, NET_MSG_CMDRESP, net_msg_cmd_code);
      s = stp_i(s, ",", 1-k); // 0=ok 1=error
      if (k)
        {
        *s++ = ',';
        for (p = net_msg_scratchpad; *p; p++)
          {
            if (*p == '\n')
              *s++ = '\r'; // translate LF to CR
            else if (*p == ',')
              *s++ = ';'; // translate , to ;
            else
              *s++ = *p;
          }
        *s = 0;
        }

      // send return string:
      net_msg_encode_puts();
      break;

    case 40: // Send SMS (params: phone number, SMS message)
      for (p=net_msg_cmd_msg;(*p != 0)&&(*p != ',');p++) ;
      // check if a value exists and is separated by a comma
      if (*p == ',')
        {
        *p++ = 0;
        // At this point, <net_msg_cmd_msg> points to the phone number, and <p> to the SMS message
        net_send_sms_start(net_msg_cmd_msg);
        net_puts_ram(p);
        net_puts_rom("\x1a");
        delay100(5);
        net_msg_start();
        STP_OK(net_scratchpad, net_msg_cmd_code);
        }
      else
        {
        net_msg_start();
        STP_INVALIDSYNTAX(net_scratchpad, net_msg_cmd_code);
        }
      net_msg_encode_puts();
      delay100(2);
      break;

    case 41: // Send MMI/USSD Codes (param: USSD_CODE)
      net_puts_rom("AT+CUSD=1,\"");
      net_puts_ram(net_msg_cmd_msg);
      net_puts_rom("\",15\r");
      // cmd reply #1 to acknowledge command:
      delay100(5);
      net_msg_start();
      STP_OK(net_scratchpad, net_msg_cmd_code);
      net_msg_encode_puts();
      delay100(2);
      // cmd reply #2 sent on USSD response, see net_msg_reply_ussd()
      break;
      
    case 49: // Send raw AT command (param: raw AT command)
      net_puts_ram(net_msg_cmd_msg);
      net_puts_rom("\r");
      delay100(5);
      net_msg_start();
      STP_OK(net_scratchpad, net_msg_cmd_code);
      net_msg_encode_puts();
      delay100(2);
      break;

  default:
      return FALSE;
    }

  return TRUE;
  }