Logo Search packages:      
Sourcecode: nut version File versions  Download package

bcmxcp_ser.c

#include "main.h"
#include "bcmxcp.h"
#include "bcmxcp_io.h"
#include "serial.h"

#define PW_MAX_BAUD 5

#define SUBDRIVER_NAME  "RS-232 communication subdriver"
#define SUBDRIVER_VERSION     "0.18"

/* communication driver description structure */
upsdrv_info_t comm_upsdrv_info = {
      SUBDRIVER_NAME,
      SUBDRIVER_VERSION,
      NULL,
      0,
      { NULL }
};

00020 struct pw_baud_rate {
      int rate;
      int name;
} pw_baud_rates[] = {
      { B1200,  1200 },
      { B2400,  2400 },
      { B4800,  4800 },
      { B9600,  9600 },
      { B19200, 19200 },
};

unsigned char AUT[4] = {0xCF, 0x69, 0xE8, 0xD5};            /* Autorisation   command     */

static void send_command(unsigned char *command, int command_length)
{
      int         retry = 0, sent;
      unsigned char     sbuf[128];

      /* Prepare the send buffer */
      sbuf[0] = PW_COMMAND_START_BYTE;
      sbuf[1] = (unsigned char)(command_length);
      memcpy(sbuf+2, command, command_length);
      command_length += 2;

      /* Add checksum */
      sbuf[command_length] = calc_checksum(sbuf);
      command_length += 1;

      while (retry++ < PW_MAX_TRY) {

            if (retry == PW_MAX_TRY) {
                  ser_send_char(upsfd, 0x1d);   /* last retry is preceded by a ESC.*/
                  usleep(250000);
            }

            sent = ser_send_buf(upsfd, sbuf, command_length);

            if (sent == command_length) {
                  return;
            }
      }
}

void send_read_command(unsigned char command)
{
      send_command(&command, 1);
}

void send_write_command(unsigned char *command, int command_length)
{
      send_command(command, command_length);
}

/* get the answer of a command from the ups. And check that the answer is for this command */
int get_answer(unsigned char *data, unsigned char command)
{
      unsigned char     my_buf[128];      /* packet has a maximum length of 121+5 bytes */
      int         length, end_length = 0, res, endblock = 0, start = 0;
      unsigned char     block_number, sequence, pre_sequence = 0;

      while (endblock != 1){

            do {
                  /* Read PW_COMMAND_START_BYTE byte */
                  res = ser_get_char(upsfd, my_buf, 1, 0);

                  if (res != 1) {
                        upsdebugx(1,"Receive error (PW_COMMAND_START_BYTE): %d, cmd=%x!!!\n", res, command);
                        return -1;
                  }

                  start++;

            } while ((my_buf[0] != PW_COMMAND_START_BYTE) && (start < 128));
            
            if (start == 128) {
                  ser_comm_fail("Receive error (PW_COMMAND_START_BYTE): packet not on start!!%x\n", my_buf[0]);
                  return -1;
            }

            /* Read block number byte */
            res = ser_get_char(upsfd, my_buf+1, 1, 0);

            if (res != 1) {
                  ser_comm_fail("Receive error (Block number): %d!!!\n", res);
                  return -1;
            }

            block_number = (unsigned char)my_buf[1];

            if (command <= 0x43) {
                  if ((command - 0x30) != block_number){
                        ser_comm_fail("Receive error (Request command): %x!!!\n", block_number);
                        return -1;
                  }
            }

            if (command >= 0x89) {
                  if ((command == 0xA0) && (block_number != 0x01)){
                        ser_comm_fail("Receive error (Requested only mode command): %x!!!\n", block_number);
                        return -1;
                  }

                  if ((command != 0xA0) && (block_number != 0x09)){
                        ser_comm_fail("Receive error (Control command): %x!!!\n", block_number);
                        return -1;
                  }
            }

            /* Read data length byte */
            res = ser_get_char(upsfd, my_buf+2, 1, 0);

            if (res != 1) {
                  ser_comm_fail("Receive error (length): %d!!!\n", res);
                  return -1;
            }

            length = (unsigned char)my_buf[2];

            if (length < 1) {
                  ser_comm_fail("Receive error (length): packet length %x!!!\n", length);
                  return -1;
            }

            /* Read sequence byte */
            res = ser_get_char(upsfd, my_buf+3, 1, 0);

            if (res != 1) {
                  ser_comm_fail("Receive error (sequence): %d!!!\n", res);
                  return -1;
            }

            sequence = (unsigned char)my_buf[3];

            if ((sequence & 0x80) == 0x80) {
                  endblock = 1;
            }

            if ((sequence & 0x07) != (pre_sequence + 1)) {
                  ser_comm_fail("Not the right sequence received %x!!!\n", sequence);
                  return -1;
            }

            pre_sequence = sequence;

            /* Try to read all the remainig bytes */
            res = ser_get_buf_len(upsfd, my_buf+4, length, 1, 0);

            if (res != length) {
                  ser_comm_fail("Receive error (data): got %d bytes instead of %d!!!\n", res, length);
                  return -1;
            }

            /* Get the checksum byte */
            res = ser_get_char(upsfd, my_buf+(4+length), 1, 0);

            if (res != 1) {
                  ser_comm_fail("Receive error (checksum): %x!!!\n", res);
                  return -1;
            }

            /* now we have the whole answer from the ups, we can checksum it */
            if (!checksum_test(my_buf)) {
                  ser_comm_fail("checksum error! ");
                  return -1;
            }

            memcpy(data+end_length, my_buf+4, length);
            end_length += length;

      }

      ser_comm_good();

      return end_length;
}

static int command_sequence(unsigned char *command, int command_length, unsigned char *answer)
{
      int   bytes_read, retry = 0;
      
      while (retry++ < PW_MAX_TRY) {

            if (retry == PW_MAX_TRY) {
                  ser_flush_in(upsfd, "", 0);
            }

            send_write_command(command, command_length);

            bytes_read = get_answer(answer, *command);

            if (bytes_read > 0) {
                  return bytes_read;
            }
      }

      return -1;
}

/* Sends a single command (length=1). and get the answer */
int command_read_sequence(unsigned char command, unsigned char *answer)
{
      int   bytes_read;

      bytes_read = command_sequence(&command, 1, answer);

      if (bytes_read < 1) {
            ser_comm_fail("Error executing command");
      }

      return bytes_read;
}

/* Sends a setup command (length > 1) */
int command_write_sequence(unsigned char *command, int command_length, unsigned     char *answer)
{
      int   bytes_read;

      bytes_read = command_sequence(command, command_length, answer);

      if (bytes_read < 1) {
            ser_comm_fail("Error executing command");
      }

      return bytes_read;
}

void upsdrv_comm_good()
{
      ser_comm_good();
}

void pw_comm_setup(const char *port)
{
      unsigned char     command = PW_SET_REQ_ONLY_MODE;
      unsigned char     id_command = PW_ID_BLOCK_REQ;
      unsigned char     answer[256];
      int         i = 0, baud, mybaud = 0, ret = -1;

      if (getval("baud_rate") != NULL)
      {
            baud = atoi(getval("baud_rate"));
            
            for(i = 0; i < PW_MAX_BAUD; i++) {
                  if (baud == pw_baud_rates[i].name) {
                        mybaud = pw_baud_rates[i].rate;
                        break;
                  }
            }

            if (mybaud == 0) {
                  fatalx(EXIT_FAILURE, "Specified baudrate \"%s\" is invalid!", getval("baud_rate"));
            }

            ser_set_speed(upsfd, device_path, mybaud);
            ser_send_char(upsfd, 0x1d);   /* send ESC to take it out of menu */
            usleep(90000);
            send_write_command(AUT, 4);
            usleep(500000);
            ret = command_sequence(&command, 1, answer);
            if (ret <= 0) {
                  usleep(500000);
                  ret = command_sequence(&id_command, 1, answer);
            }

            if (ret > 0) {
                  upslogx(LOG_INFO, "Connected to UPS on %s with baudrate %d", port, baud);
                  return;
            }

            upslogx(LOG_ERR, "No response from UPS on %s with baudrate %d", port, baud);
      }

      upslogx(LOG_INFO, "Attempting to autodect baudrate");

      for (i=0; i<PW_MAX_BAUD; i++) {

            ser_set_speed(upsfd, device_path, pw_baud_rates[i].rate);
            ser_send_char(upsfd, 0x1d);   /* send ESC to take it out of menu */
            usleep(90000);
            send_write_command(AUT, 4);
            usleep(500000);
            ret = command_sequence(&command, 1, answer);
            if (ret <= 0) {
                  usleep(500000);
                  ret = command_sequence(&id_command, 1, answer);
            }

            if (ret > 0) {
                  upslogx(LOG_INFO, "Connected to UPS on %s with baudrate %d", port, pw_baud_rates[i].name);
                  return;
            }

            upsdebugx(2, "No response from UPS on %s with baudrate %d", port, pw_baud_rates[i].name);
      }

      fatalx(EXIT_FAILURE, "Can't connect to the UPS on port %s!\n", port);
}

void upsdrv_initups(void)
{
      upsfd = ser_open(device_path);
      pw_comm_setup(device_path);
}

void upsdrv_cleanup(void)
{
      /* free(dynamic_mem); */
      ser_close(upsfd, device_path);
}

void upsdrv_reconnect(void)
{
}

Generated by  Doxygen 1.6.0   Back to index