Apologize for so many replies.  Found another bug.  I think I have it
actually right this time.  Previously fractional hours were not set
right, and the calculation for the timezone offset was all wrong when
when the timezone wasn't set.

Thanks,
Gus
diff --git a/openbsc/include/openbsc/gsm_data_shared.h b/openbsc/include/openbsc/gsm_data_shared.h
index f7a85a3..25e90ed 100644
--- a/openbsc/include/openbsc/gsm_data_shared.h
+++ b/openbsc/include/openbsc/gsm_data_shared.h
@@ -473,6 +473,11 @@ struct gsm_bts {
 	/* buffers where we put the pre-computed SI */
 	sysinfo_buf_t si_buf[_MAX_SYSINFO_TYPE];
 
+	/* TimeZone hours, mins, and bts specific */
+	int tzhr;
+	int tzmn;
+	int tz_bts_specific;
+
 	/* ip.accesss Unit ID's have Site/BTS/TRX layout */
 	union {
 		struct {
diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c
index 724486f..ed74397 100644
--- a/openbsc/src/libbsc/bsc_vty.c
+++ b/openbsc/src/libbsc/bsc_vty.c
@@ -448,6 +448,8 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
 		VTY_NEWLINE);
 	vty_out(vty, "  training_sequence_code %u%s", bts->tsc, VTY_NEWLINE);
 	vty_out(vty, "  base_station_id_code %u%s", bts->bsic, VTY_NEWLINE);
+	if (bts->tz_bts_specific != 0)
+		vty_out(vty, "  timezone %d %d%s", bts->tzhr, bts->tzmn, VTY_NEWLINE);
 	vty_out(vty, "  ms max power %u%s", bts->ms_max_power, VTY_NEWLINE);
 	vty_out(vty, "  cell reselection hysteresis %u%s",
 		bts->si_common.cell_sel_par.cell_resel_hyst*2, VTY_NEWLINE);
@@ -1495,6 +1497,31 @@ DEFUN(cfg_bts_bsic,
 	return CMD_SUCCESS;
 }
 
+DEFUN(cfg_bts_timezone,
+      cfg_bts_timezone_cmd,
+      "timezone <-19-19> (0|15|30|45)",
+      "Set the Timezone Offset of this BTS\n")
+{
+	struct gsm_bts *bts = vty->index;
+	int tzhr = atoi(argv[0]);
+	int tzmn = atoi(argv[1]);
+
+	bts->tzhr = tzhr;
+	bts->tzmn = tzmn;
+	bts->tz_bts_specific=1;
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_no_timezone,
+      cfg_bts_no_timezone_cmd,
+      "no timezone",
+      "disable bts specific timezone\n")
+{
+	struct gsm_bts *bts = vty->index;
+	bts->tz_bts_specific=0;
+	return CMD_SUCCESS;
+}
 
 DEFUN(cfg_bts_unit_id,
       cfg_bts_unit_id_cmd,
@@ -2691,6 +2718,8 @@ int bsc_vty_init(const struct log_info *cat)
 	install_element(BTS_NODE, &cfg_bts_tsc_cmd);
 	install_element(BTS_NODE, &cfg_bts_bsic_cmd);
 	install_element(BTS_NODE, &cfg_bts_unit_id_cmd);
+	install_element(BTS_NODE, &cfg_bts_timezone_cmd);
+	install_element(BTS_NODE, &cfg_bts_no_timezone_cmd);
 	install_element(BTS_NODE, &cfg_bts_serno_cmd);
 	install_element(BTS_NODE, &cfg_bts_nokia_site_skip_reset_cmd);
 	install_element(BTS_NODE, &cfg_bts_stream_id_cmd);
diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c
index 7bf62b7..7c0d628 100644
--- a/openbsc/src/libmsc/gsm_04_08.c
+++ b/openbsc/src/libmsc/gsm_04_08.c
@@ -610,12 +610,17 @@ static int mm_rx_loc_upd_req(struct gsm_subscriber_connection *conn, struct msgb
 	return gsm0408_authorize(conn, msg);
 }
 
-#if 0
-static uint8_t to_bcd8(uint8_t val)
+/* Turn int into semi-octet representation: 98 => 0x89 */
+static uint8_t bcdify(uint8_t value)
 {
-       return ((val / 10) << 4) | (val % 10);
+        uint8_t ret;
+
+        ret = value / 10;
+        ret |= (value % 10) << 4;
+
+        return ret;
 }
-#endif
+
 
 /* Section 9.2.15a */
 int gsm48_tx_mm_info(struct gsm_subscriber_connection *conn)
@@ -623,13 +628,14 @@ int gsm48_tx_mm_info(struct gsm_subscriber_connection *conn)
 	struct msgb *msg = gsm48_msgb_alloc();
 	struct gsm48_hdr *gh;
 	struct gsm_network *net = conn->bts->network;
+	struct gsm_bts *bts = conn->bts;
 	uint8_t *ptr8;
 	int name_len, name_pad;
-#if 0
+
 	time_t cur_t;
-	struct tm* cur_time;
-	int tz15min;
-#endif
+	struct tm* gmt_time;
+	struct tm* local_time;
+	int tzunits;
 
 	msg->lchan = conn->lchan;
 
@@ -696,24 +702,48 @@ int gsm48_tx_mm_info(struct gsm_subscriber_connection *conn)
 
 	}
 
-#if 0
 	/* Section 10.5.3.9 */
 	cur_t = time(NULL);
-	cur_time = gmtime(&cur_t);
+	gmt_time = gmtime(&cur_t);
+
 	ptr8 = msgb_put(msg, 8);
 	ptr8[0] = GSM48_IE_NET_TIME_TZ;
-	ptr8[1] = to_bcd8(cur_time->tm_year % 100);
-	ptr8[2] = to_bcd8(cur_time->tm_mon);
-	ptr8[3] = to_bcd8(cur_time->tm_mday);
-	ptr8[4] = to_bcd8(cur_time->tm_hour);
-	ptr8[5] = to_bcd8(cur_time->tm_min);
-	ptr8[6] = to_bcd8(cur_time->tm_sec);
-	/* 02.42: coded as BCD encoded signed value in units of 15 minutes */
-	tz15min = (cur_time->tm_gmtoff)/(60*15);
-	ptr8[7] = to_bcd8(tz15min);
-	if (tz15min < 0)
-		ptr8[7] |= 0x80;
-#endif
+	ptr8[1] = bcdify(gmt_time->tm_year % 100);
+	ptr8[2] = bcdify(gmt_time->tm_mon + 1);
+	ptr8[3] = bcdify(gmt_time->tm_mday);
+	ptr8[4] = bcdify(gmt_time->tm_hour);
+	ptr8[5] = bcdify(gmt_time->tm_min);
+	ptr8[6] = bcdify(gmt_time->tm_sec);
+
+	if (bts->tz_bts_specific) {
+		/* Convert tzhr and tzmn to units */
+		if (bts->tzhr < 0) {
+			tzunits = ((bts->tzhr/-1)*4);
+			tzunits = tzunits + (bts->tzmn/15);
+			ptr8[7] = bcdify(tzunits);
+			/* Set negative time */
+			ptr8[7] |= 0x08;
+		}
+		else {
+			tzunits = bts->tzhr*4;
+			tzunits = tzunits + (bts->tzmn/15);
+			ptr8[7] = bcdify(tzunits);
+		}
+	}
+	else {
+		/* Need to get GSM offset and convert into 15 min units */
+		/* This probably breaks if gmtoff returns a value not evenly divisible by 15? */
+		local_time = localtime(&cur_t);
+		tzunits = (local_time->tm_gmtoff/60)/15;
+		if (tzunits < 0) {
+			tzunits = tzunits/-1;
+			ptr8[7] = bcdify(tzunits);
+			/* Flip it to negative */
+			ptr8[7] |= 0x08;
+		}
+		else
+			ptr8[7] = bcdify(tzunits);
+	}
 
 	DEBUGP(DMM, "-> MM INFO\n");
 

Reply via email to