* Fix BS11 software download routines in abis_nm.c
* Introduce user-configurable delay when sending serial msgs from bs11_config
This commit is contained in:
parent
071f34d7c6
commit
3b8ba215b9
|
@ -296,6 +296,7 @@ enum abis_nm_attr {
|
||||||
|
|
||||||
NM_ATT_BS11_PASSWORD = 0xfd,
|
NM_ATT_BS11_PASSWORD = 0xfd,
|
||||||
};
|
};
|
||||||
|
#define NM_ATT_BS11_FILE_DATA NM_ATT_EVENT_TYPE
|
||||||
|
|
||||||
/* Section 9.4.4: Administrative State */
|
/* Section 9.4.4: Administrative State */
|
||||||
enum abis_nm_adm_state {
|
enum abis_nm_adm_state {
|
||||||
|
|
|
@ -339,26 +339,34 @@ static int sw_load_segment(struct abis_nm_sw *sw)
|
||||||
struct msgb *msg = nm_msgb_alloc();
|
struct msgb *msg = nm_msgb_alloc();
|
||||||
char seg_buf[256];
|
char seg_buf[256];
|
||||||
char *line_buf = seg_buf+2;
|
char *line_buf = seg_buf+2;
|
||||||
|
unsigned char *tlv;
|
||||||
u_int8_t len;
|
u_int8_t len;
|
||||||
int rc;
|
|
||||||
|
|
||||||
oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
|
oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
|
||||||
/* FIXME: this is BS11 specific format */
|
|
||||||
rc = fscanf(sw->stream, "%s\r\n", line_buf);
|
switch (sw->bts->type) {
|
||||||
if (rc < 1) {
|
case GSM_BTS_TYPE_BS11:
|
||||||
perror("fscanf reading segment");
|
if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
|
||||||
return -EINVAL;
|
perror("fgets reading segment");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
seg_buf[0] = 0x00;
|
||||||
|
seg_buf[1] = 1 + sw->seg_in_window++;
|
||||||
|
|
||||||
|
len = strlen(line_buf) + 2;
|
||||||
|
tlv = msgb_put(msg, TLV_GROSS_LEN(len));
|
||||||
|
tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
|
||||||
|
/* BS11 wants CR + LF in excess of the TLV length !?! */
|
||||||
|
tlv[1] -= 2;
|
||||||
|
|
||||||
|
/* we only now know the exact length for the OM hdr */
|
||||||
|
len = strlen(line_buf)+2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* FIXME: Other BTS types */
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
seg_buf[0] = 0x00;
|
|
||||||
seg_buf[1] = sw->seg_in_window++;
|
|
||||||
|
|
||||||
msgb_tlv_put(msg, NM_ATT_FILE_DATA, 2+strlen(line_buf),
|
|
||||||
(u_int8_t *)seg_buf);
|
|
||||||
/* BS11 wants CR + LF in excess of the TLV length !?! */
|
|
||||||
msgb_tv_put(msg, 0x0d, 0x0a);
|
|
||||||
|
|
||||||
/* we only now know the exact length for the OM hdr */
|
|
||||||
len = 2+strlen(line_buf)+2;
|
|
||||||
fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
|
fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
|
||||||
sw->obj_instance[0], sw->obj_instance[1],
|
sw->obj_instance[0], sw->obj_instance[1],
|
||||||
sw->obj_instance[2]);
|
sw->obj_instance[2]);
|
||||||
|
@ -423,7 +431,7 @@ static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* read first line and parse file ID and VERSION */
|
/* read first line and parse file ID and VERSION */
|
||||||
rc = fscanf(sw->stream, "@(@)%12s:%80s\r\n",
|
rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
|
||||||
file_id, file_version);
|
file_id, file_version);
|
||||||
if (rc != 2) {
|
if (rc != 2) {
|
||||||
perror("parsing header line of software file");
|
perror("parsing header line of software file");
|
||||||
|
@ -434,7 +442,7 @@ static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
|
||||||
strcpy((char *)sw->file_version, file_version);
|
strcpy((char *)sw->file_version, file_version);
|
||||||
sw->file_version_len = strlen(file_version);
|
sw->file_version_len = strlen(file_version);
|
||||||
/* rewind to start of file */
|
/* rewind to start of file */
|
||||||
fseek(sw->stream, 0, SEEK_SET);
|
rewind(sw->stream);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* We don't know how to treat them yet */
|
/* We don't know how to treat them yet */
|
||||||
|
|
|
@ -40,6 +40,15 @@
|
||||||
#include <openbsc/tlv.h>
|
#include <openbsc/tlv.h>
|
||||||
#include <openbsc/debug.h>
|
#include <openbsc/debug.h>
|
||||||
|
|
||||||
|
/* state of our bs11_config application */
|
||||||
|
enum bs11cfg_state {
|
||||||
|
STATE_NONE,
|
||||||
|
STATE_LOGON_WAIT,
|
||||||
|
STATE_LOGON_ACK,
|
||||||
|
STATE_SWLOAD,
|
||||||
|
};
|
||||||
|
static enum bs11cfg_state bs11cfg_state = STATE_NONE;
|
||||||
|
|
||||||
static const u_int8_t obj_li_attr[] = {
|
static const u_int8_t obj_li_attr[] = {
|
||||||
0xa0, 0x09, 0x00,
|
0xa0, 0x09, 0x00,
|
||||||
0xab, 0x00,
|
0xab, 0x00,
|
||||||
|
@ -55,6 +64,8 @@ static const u_int8_t obj_pa0_attr[] = {
|
||||||
static const char *trx1_password = "1111111111";
|
static const char *trx1_password = "1111111111";
|
||||||
#define TEI_OML 25
|
#define TEI_OML 25
|
||||||
|
|
||||||
|
static const u_int8_t too_fast[] = { 0x12, 0x80, 0x00, 0x00, 0x02, 0x02 };
|
||||||
|
|
||||||
/* create all objects for an initial configuration */
|
/* create all objects for an initial configuration */
|
||||||
static int create_objects(struct gsm_bts *bts, int trx1)
|
static int create_objects(struct gsm_bts *bts, int trx1)
|
||||||
{
|
{
|
||||||
|
@ -104,6 +115,7 @@ static int create_objects(struct gsm_bts *bts, int trx1)
|
||||||
static char *serial_port = "/dev/ttyUSB0";
|
static char *serial_port = "/dev/ttyUSB0";
|
||||||
static char *fname_safety = "BTSBMC76.SWI";
|
static char *fname_safety = "BTSBMC76.SWI";
|
||||||
static char *fname_software = "HS011106.SWL";
|
static char *fname_software = "HS011106.SWL";
|
||||||
|
static int delay_ms = 100;
|
||||||
static int serial_fd = -1;
|
static int serial_fd = -1;
|
||||||
static int have_trx1 = 0;
|
static int have_trx1 = 0;
|
||||||
static struct gsm_bts *g_bts;
|
static struct gsm_bts *g_bts;
|
||||||
|
@ -146,6 +158,7 @@ int _abis_nm_sendmsg(struct msgb *msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
msgb_free(msg);
|
msgb_free(msg);
|
||||||
|
usleep(delay_ms*1000);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -161,6 +174,8 @@ static struct msgb *serial_read_msg(void)
|
||||||
if (!msg)
|
if (!msg)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
msg->l2h = NULL;
|
||||||
|
|
||||||
/* first read two byes to obtain length */
|
/* first read two byes to obtain length */
|
||||||
while (msg->len < 2) {
|
while (msg->len < 2) {
|
||||||
rc = read(serial_fd, msg->tail, 2 - msg->len);
|
rc = read(serial_fd, msg->tail, 2 - msg->len);
|
||||||
|
@ -176,9 +191,8 @@ static struct msgb *serial_read_msg(void)
|
||||||
msg->data[0]);
|
msg->data[0]);
|
||||||
|
|
||||||
/* second byte is LAPD payload length */
|
/* second byte is LAPD payload length */
|
||||||
if (msg->data[1] < LAPD_HDR_LEN + sizeof(struct abis_om_fom_hdr) +
|
if (msg->data[1] + 2 < LAPD_HDR_LEN)
|
||||||
sizeof(struct abis_om_hdr))
|
fprintf(stderr, "Invalid header byte 1(len): %u\n",
|
||||||
fprintf(stderr, "Invalied header byte 1(len): %u\n",
|
|
||||||
msg->data[1]);
|
msg->data[1]);
|
||||||
|
|
||||||
while (msg->len < 2 + msg->data[1]) {
|
while (msg->len < 2 + msg->data[1]) {
|
||||||
|
@ -191,10 +205,11 @@ static struct msgb *serial_read_msg(void)
|
||||||
msgb_put(msg, rc);
|
msgb_put(msg, rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
msg->l2h = msg->data + LAPD_HDR_LEN;
|
if (msg->len > LAPD_HDR_LEN)
|
||||||
|
msg->l2h = msg->data + LAPD_HDR_LEN;
|
||||||
|
|
||||||
fprintf(stdout, "RX: ");
|
fprintf(stdout, "RX: ");
|
||||||
hexdump(msg->l2h, msg->len - (msg->l2h - msg->data));
|
hexdump(msg->data, msg->len);
|
||||||
|
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
@ -217,7 +232,10 @@ static int file_is_readable(const char *fname)
|
||||||
|
|
||||||
static int handle_state_resp(u_int8_t state)
|
static int handle_state_resp(u_int8_t state)
|
||||||
{
|
{
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
printf("STATE: ");
|
printf("STATE: ");
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case BS11_STATE_WARM_UP:
|
case BS11_STATE_WARM_UP:
|
||||||
printf("Warm Up...\n");
|
printf("Warm Up...\n");
|
||||||
|
@ -229,9 +247,10 @@ static int handle_state_resp(u_int8_t state)
|
||||||
break;
|
break;
|
||||||
case BS11_STATE_SOFTWARE_RQD:
|
case BS11_STATE_SOFTWARE_RQD:
|
||||||
printf("Software required...\n");
|
printf("Software required...\n");
|
||||||
|
bs11cfg_state = STATE_SWLOAD;
|
||||||
/* send safety load */
|
/* send safety load */
|
||||||
if (file_is_readable(fname_safety))
|
if (file_is_readable(fname_safety))
|
||||||
abis_nm_software_load(g_bts, fname_safety, 8);
|
rc = abis_nm_software_load(g_bts, fname_safety, 8);
|
||||||
else
|
else
|
||||||
fprintf(stderr, "No valid Safety Load file \"%s\"\n",
|
fprintf(stderr, "No valid Safety Load file \"%s\"\n",
|
||||||
fname_safety);
|
fname_safety);
|
||||||
|
@ -239,13 +258,15 @@ static int handle_state_resp(u_int8_t state)
|
||||||
case BS11_STATE_WAIT_MIN_CFG:
|
case BS11_STATE_WAIT_MIN_CFG:
|
||||||
case BS11_STATE_WAIT_MIN_CFG_2:
|
case BS11_STATE_WAIT_MIN_CFG_2:
|
||||||
printf("Wait minimal config...\n");
|
printf("Wait minimal config...\n");
|
||||||
create_objects(g_bts, have_trx1);
|
bs11cfg_state = STATE_SWLOAD;
|
||||||
|
rc = create_objects(g_bts, have_trx1);
|
||||||
break;
|
break;
|
||||||
case BS11_STATE_MAINTENANCE:
|
case BS11_STATE_MAINTENANCE:
|
||||||
printf("Maintenance...\n");
|
printf("Maintenance...\n");
|
||||||
|
bs11cfg_state = STATE_SWLOAD;
|
||||||
/* send software (FIXME: over A-bis?) */
|
/* send software (FIXME: over A-bis?) */
|
||||||
if (file_is_readable(fname_software))
|
if (file_is_readable(fname_software))
|
||||||
abis_nm_software_load(g_bts, fname_software, 8);
|
rc = abis_nm_software_load(g_bts, fname_software, 8);
|
||||||
else
|
else
|
||||||
fprintf(stderr, "No valid Software file \"%s\"\n",
|
fprintf(stderr, "No valid Software file \"%s\"\n",
|
||||||
fname_software);
|
fname_software);
|
||||||
|
@ -258,7 +279,7 @@ static int handle_state_resp(u_int8_t state)
|
||||||
sleep(5);
|
sleep(5);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 0;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_banner(void)
|
static void print_banner(void)
|
||||||
|
@ -274,7 +295,7 @@ static void print_help(void)
|
||||||
printf("\t--port /dev/ttyXXX\t-p\tSpecify serial port\n");
|
printf("\t--port /dev/ttyXXX\t-p\tSpecify serial port\n");
|
||||||
printf("\t--with-trx1\t\t-t\tAssume the BS-11 has 2 TRX\n");
|
printf("\t--with-trx1\t\t-t\tAssume the BS-11 has 2 TRX\n");
|
||||||
printf("\t--software file\t\t-s\tSpecify Software file\n");
|
printf("\t--software file\t\t-s\tSpecify Software file\n");
|
||||||
printf("\t--safety file\t\t-s\tSpecify Safety Load file\n");
|
printf("\t--safety file\t\t-S\tSpecify Safety Load file\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_options(int argc, char **argv)
|
static void handle_options(int argc, char **argv)
|
||||||
|
@ -289,6 +310,7 @@ static void handle_options(int argc, char **argv)
|
||||||
{ "with-trx1", 0, 0, 't' },
|
{ "with-trx1", 0, 0, 't' },
|
||||||
{ "software", 1, 0, 's' },
|
{ "software", 1, 0, 's' },
|
||||||
{ "safety", 1, 0, 'S' },
|
{ "safety", 1, 0, 'S' },
|
||||||
|
{ "delay", 1, 0, 'd' },
|
||||||
};
|
};
|
||||||
|
|
||||||
c = getopt_long(argc, argv, "hp:s:S:t",
|
c = getopt_long(argc, argv, "hp:s:S:t",
|
||||||
|
@ -313,24 +335,19 @@ static void handle_options(int argc, char **argv)
|
||||||
case 'S':
|
case 'S':
|
||||||
fname_safety = optarg;
|
fname_safety = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 'd':
|
||||||
|
delay_ms = atoi(optarg);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum bs11_state {
|
|
||||||
STATE_NONE,
|
|
||||||
STATE_LOGON_WAIT,
|
|
||||||
STATE_LOGON_ACK,
|
|
||||||
STATE_SWLOAD,
|
|
||||||
};
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct gsm_network *gsmnet;
|
struct gsm_network *gsmnet;
|
||||||
struct termios tio;
|
struct termios tio;
|
||||||
enum bs11_state state = STATE_NONE;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
handle_options(argc, argv);
|
handle_options(argc, argv);
|
||||||
|
@ -377,13 +394,28 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
rx_msg = serial_read_msg();
|
rx_msg = serial_read_msg();
|
||||||
|
|
||||||
|
if (rx_msg->len < LAPD_HDR_LEN
|
||||||
|
+ sizeof(struct abis_om_fom_hdr)
|
||||||
|
+ sizeof(struct abis_om_hdr)) {
|
||||||
|
if (!memcmp(rx_msg->data + 2, too_fast,
|
||||||
|
sizeof(too_fast))) {
|
||||||
|
fprintf(stderr, "BS11 tells us we're too "
|
||||||
|
"fast, try --delay bigger than %u\n",
|
||||||
|
delay_ms);
|
||||||
|
break;
|
||||||
|
} else
|
||||||
|
fprintf(stderr, "unknown BS11 message\n");
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
oh = (struct abis_om_hdr *) msgb_l2(rx_msg);
|
oh = (struct abis_om_hdr *) msgb_l2(rx_msg);
|
||||||
foh = (struct abis_om_fom_hdr *) oh->data;
|
foh = (struct abis_om_fom_hdr *) oh->data;
|
||||||
switch (foh->msg_type) {
|
switch (foh->msg_type) {
|
||||||
case NM_MT_BS11_FACTORY_LOGON_ACK:
|
case NM_MT_BS11_FACTORY_LOGON_ACK:
|
||||||
printf("FACTORY LOGON: ACK\n");
|
printf("FACTORY LOGON: ACK\n");
|
||||||
if (state == STATE_NONE)
|
if (bs11cfg_state == STATE_NONE)
|
||||||
state = STATE_LOGON_ACK;
|
bs11cfg_state = STATE_LOGON_ACK;
|
||||||
rc = 0;
|
rc = 0;
|
||||||
break;
|
break;
|
||||||
case NM_MT_BS11_GET_STATE_ACK:
|
case NM_MT_BS11_GET_STATE_ACK:
|
||||||
|
@ -394,12 +426,12 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
perror("in main loop");
|
perror("in main loop");
|
||||||
break;
|
//break;
|
||||||
}
|
}
|
||||||
if (rc == 1)
|
if (rc == 1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
switch (state) {
|
switch (bs11cfg_state) {
|
||||||
case STATE_NONE:
|
case STATE_NONE:
|
||||||
abis_nm_bs11_factory_logon(g_bts, 1);
|
abis_nm_bs11_factory_logon(g_bts, 1);
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue