390 lines
9.0 KiB
C
390 lines
9.0 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <arpa/inet.h>
|
|
#include <unistd.h>
|
|
|
|
#include <osmocom/core/select.h>
|
|
#include <osmocom/core/talloc.h>
|
|
#include <osmocom/core/msgb.h>
|
|
#include <osmocom/core/logging.h>
|
|
#include <osmocom/core/application.h>
|
|
#include <osmocom/core/endian.h>
|
|
|
|
#include <osmocom/netif/rs232.h>
|
|
|
|
#define DRS232TEST 0
|
|
|
|
struct log_info_cat osmo_rs232_test_cat[] = {
|
|
[DRS232TEST] = {
|
|
.name = "DRS232TEST",
|
|
.description = "rs232 test",
|
|
.color = "\033[1;35m",
|
|
.enabled = 1, .loglevel = LOGL_DEBUG,
|
|
},
|
|
};
|
|
|
|
const struct log_info osmo_rs232_test_log_info = {
|
|
.filter_fn = NULL,
|
|
.cat = osmo_rs232_test_cat,
|
|
.num_cat = ARRAY_SIZE(osmo_rs232_test_cat),
|
|
};
|
|
|
|
static struct osmo_rs232 *r;
|
|
|
|
void sighandler(int foo)
|
|
{
|
|
LOGP(DRS232TEST, LOGL_NOTICE, "closing rs232.\n");
|
|
osmo_rs232_close(r);
|
|
osmo_rs232_destroy(r);
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
|
|
static int read_cb(struct osmo_rs232 *r)
|
|
{
|
|
struct msgb *msg;
|
|
|
|
LOGP(DRS232TEST, LOGL_DEBUG, "received data from rs232\n");
|
|
|
|
msg = msgb_alloc(1024, "rs232/test");
|
|
if (msg == NULL) {
|
|
LOGP(DRS232TEST, LOGL_ERROR, "cannot allocate message\n");
|
|
return 0;
|
|
}
|
|
if (osmo_rs232_read(r, msg) < 0) {
|
|
LOGP(DRS232TEST, LOGL_ERROR, "cannot receive message\n");
|
|
return 0;
|
|
}
|
|
LOGP(DRS232TEST, LOGL_DEBUG, "received %d bytes\n", msg->len);
|
|
|
|
printf("received %d bytes ", msg->len);
|
|
|
|
int i;
|
|
printf("(");
|
|
for (i=0; i<msg->len; i++)
|
|
printf("\\x%.2x", 0xff & msg->data[i]);
|
|
printf(") %s\n", msg->data);
|
|
|
|
msgb_free(msg);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void *tall_test;
|
|
|
|
/* u-blox6_ReceiverDescriptionProtocolSpec_(GPS.G6-SW-10018).pdf */
|
|
|
|
/* See Sect 23. */
|
|
struct ubx_hdr {
|
|
uint8_t sync_char1; /* 0xb5 */
|
|
uint8_t sync_char2; /* 0x62 */
|
|
uint8_t class;
|
|
uint8_t id;
|
|
} __attribute__((packed));
|
|
|
|
static void ubx_header(struct msgb *msg, uint8_t class, uint8_t id)
|
|
{
|
|
/* See Sect. 31.24 */
|
|
struct ubx_hdr ubxhdr = {
|
|
.sync_char1 = 0xb5,
|
|
.sync_char2 = 0x62,
|
|
.class = class,
|
|
.id = id,
|
|
};
|
|
memcpy(msg->data, &ubxhdr, sizeof(struct ubx_hdr));
|
|
msgb_put(msg, sizeof(struct ubx_hdr));
|
|
}
|
|
|
|
/* See Sect 26. */
|
|
static void ubx_checksum(struct msgb *msg, uint8_t *ck)
|
|
{
|
|
struct ubx_hdr *ubxhdr = (struct ubx_hdr *)msg->data;
|
|
/* skip sync chars in checksum calculation. */
|
|
uint8_t *buf = ((uint8_t *)ubxhdr) + 2;
|
|
int i;
|
|
|
|
memset(ck, 0, sizeof(uint16_t));
|
|
|
|
for (i=0; i<msg->len-2; i++) {
|
|
ck[0] += buf[i];
|
|
ck[1] += ck[0];
|
|
}
|
|
}
|
|
|
|
# if OSMO_IS_LITTLE_ENDIAN
|
|
# define utohl(x) (x)
|
|
# define utohs(x) (x)
|
|
# define htoul(x) (x)
|
|
# define htous(x) (x)
|
|
# else
|
|
# if OSMO_IS_BIG_ENDIAN
|
|
# define utohl(x) __bswap_32 (x)
|
|
# define utohs(x) __bswap_16 (x)
|
|
# define htoul(x) __bswap_32 (x)
|
|
# define htous(x) __bswap_16 (x)
|
|
# endif
|
|
# endif
|
|
|
|
static void ubx_payload_start(struct msgb *msg)
|
|
{
|
|
uint16_t len = 0;
|
|
/* make room for payload length. */
|
|
memcpy(msg->data + msg->len, &len, sizeof(len));
|
|
msgb_put(msg, sizeof(len));
|
|
}
|
|
|
|
static void ubx_payload_put_u8(struct msgb *msg, uint8_t data)
|
|
{
|
|
memcpy(msg->data + msg->len, &data, sizeof(data));
|
|
msgb_put(msg, sizeof(data));
|
|
}
|
|
|
|
static void ubx_payload_put_le16(struct msgb *msg, uint16_t data)
|
|
{
|
|
uint16_t le_data = htous(data);
|
|
memcpy(msg->data + msg->len, &le_data, sizeof(data));
|
|
msgb_put(msg, sizeof(data));
|
|
}
|
|
|
|
static void ubx_payload_put_le32(struct msgb *msg, uint32_t data)
|
|
{
|
|
uint32_t le_data = htoul(data);
|
|
memcpy(msg->data + msg->len, &le_data, sizeof(data));
|
|
msgb_put(msg, sizeof(data));
|
|
}
|
|
|
|
static void ubx_payload_stop(struct msgb *msg)
|
|
{
|
|
uint16_t *length = (uint16_t *) &(msg->data[4]);
|
|
uint8_t checksum[2];
|
|
|
|
/* length does not includes the header, ID, length.
|
|
* note that checksum has not been yet added.
|
|
*/
|
|
*length = htous(msg->len - 6);
|
|
|
|
ubx_checksum(msg, checksum);
|
|
memcpy(msg->data + msg->len, checksum, sizeof(checksum));
|
|
msgb_put(msg, sizeof(checksum));
|
|
}
|
|
|
|
static void cfg_prt(void)
|
|
{
|
|
struct msgb *msg;
|
|
|
|
msg = msgb_alloc(512, "CFG-PRT for USB");
|
|
if (msg == NULL)
|
|
exit(EXIT_FAILURE);
|
|
|
|
ubx_header(msg, 0x06, 0x00); /* CFG-PRT */
|
|
|
|
ubx_payload_start(msg);
|
|
ubx_payload_put_u8(msg, 0x03); /* Port ID is (=3 USB). */
|
|
ubx_payload_put_u8(msg, 0x00); /* Reserved. */
|
|
ubx_payload_put_le16(msg, 0x0000); /* TX ready. */
|
|
ubx_payload_put_le32(msg, 0x00000000); /* Reserved. */
|
|
ubx_payload_put_le32(msg, 0x00000000); /* Reserved. */
|
|
ubx_payload_put_le16(msg, 0x0003); /* InProtoMask (NMEA+UBX). */
|
|
ubx_payload_put_le16(msg, 0x0001); /* OutProtoMask (UBX). */
|
|
ubx_payload_put_le16(msg, 0x0000); /* Flags. */
|
|
ubx_payload_put_le16(msg, 0x0000); /* Reserved. */
|
|
ubx_payload_stop(msg);
|
|
|
|
int i;
|
|
for (i=0; i<msg->len; i++)
|
|
printf("\\x%.2x", 0xff & msg->data[i]);
|
|
printf("\n");
|
|
|
|
if (osmo_rs232_write(r, msg) < 0) {
|
|
LOGP(DRS232TEST, LOGL_ERROR, "cannot write to rs232\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
static int nmea_checksum(char *nmea_cmd, uint8_t *checksum)
|
|
{
|
|
int i, ret = 0;
|
|
uint8_t from, to;
|
|
char *start, *end;
|
|
|
|
/* find starting $ */
|
|
start = strtok(nmea_cmd, "$");
|
|
if (start == NULL)
|
|
return -1;
|
|
|
|
from = start - nmea_cmd;
|
|
|
|
end = strtok(start+1, "*");
|
|
if (end == NULL)
|
|
return -1;
|
|
|
|
to = end - nmea_cmd;
|
|
|
|
ret = (uint8_t)nmea_cmd[0];
|
|
for (i=from+1; i<to; i++)
|
|
ret ^= (uint8_t)nmea_cmd[i];
|
|
|
|
*checksum = ret;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void send_pubx(void)
|
|
{
|
|
struct msgb *msg;
|
|
|
|
/* See 21.8: UBX,41.
|
|
*
|
|
* $PUBX,41,portId,inProto,outProto,baudrate,autobauding*cs
|
|
*
|
|
* [in|out]Proto: bit = 0 (ubx), bit = 1 (nmea)
|
|
*
|
|
* Sect 4. Serial Communication Ports Description
|
|
*
|
|
* 0 DDC
|
|
* 1 UART1
|
|
* 2 UART2
|
|
* 3 USB
|
|
* 4 SPI
|
|
* 5 reserved
|
|
*
|
|
* The NMEA command below comes without the checksum calculated.
|
|
*/
|
|
char nmea_cmd[128] = "$PUBX,41,3,0001,0001,9600,0*";
|
|
uint8_t checksum;
|
|
|
|
if (nmea_checksum(nmea_cmd, &checksum) < 0) {
|
|
LOGP(DRS232TEST, LOGL_ERROR, "error calculating checksum\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
sprintf(nmea_cmd + strlen(nmea_cmd), "%u\r\n", checksum);
|
|
|
|
msg = msgb_alloc(300, "rs232/test");
|
|
if (msg == NULL) {
|
|
LOGP(DRS232TEST, LOGL_ERROR, "cannot allocate message\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
memcpy(msg->data, nmea_cmd, strlen(nmea_cmd));
|
|
msgb_put(msg, strlen(nmea_cmd));
|
|
|
|
if (osmo_rs232_write(r, msg) < 0) {
|
|
LOGP(DRS232TEST, LOGL_ERROR, "cannot write to rs232\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
static void cfg_tp5(void)
|
|
{
|
|
struct msgb *msg;
|
|
|
|
msg = msgb_alloc(512, "CFG-TP5 for USB");
|
|
if (msg == NULL)
|
|
exit(EXIT_FAILURE);
|
|
|
|
ubx_header(msg, 0x06, 0x31); /* CFG-TP5 */
|
|
|
|
ubx_payload_start(msg);
|
|
ubx_payload_put_u8(msg, 0x01); /* TIMEPULSE2 (=1) */
|
|
ubx_payload_put_u8(msg, 0x00); /* Reserved. */
|
|
ubx_payload_put_le16(msg, 0x0000); /* Reserved. */
|
|
ubx_payload_put_le16(msg, 0); /* Antenna Delay (ns) */
|
|
ubx_payload_put_le16(msg, 0); /* RF Group Delay (ns) */
|
|
ubx_payload_put_le32(msg, 8192000); /* freqPeriod (Hz/us) */
|
|
ubx_payload_put_le32(msg, 8192000); /* freqPeriodLoc (Hz/us) */
|
|
ubx_payload_put_le32(msg, 0x80000000); /* pulseLenRation:
|
|
1/2^-32 (us() */
|
|
ubx_payload_put_le32(msg, 0x80000000); /* pulseLenRationLock:
|
|
1/2^-32 (us() */
|
|
ubx_payload_put_le32(msg, 0); /* userConfigDelay (ns) */
|
|
ubx_payload_put_le32(msg, (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3));
|
|
/* flags: bits 0, 1 and 3. */
|
|
ubx_payload_stop(msg);
|
|
|
|
int i;
|
|
for (i=0; i<msg->len; i++)
|
|
printf("\\x%.2x", 0xff & msg->data[i]);
|
|
printf("\n");
|
|
|
|
if (osmo_rs232_write(r, msg) < 0) {
|
|
LOGP(DRS232TEST, LOGL_ERROR, "cannot write to rs232\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
static int kbd_cb(struct osmo_fd *fd, unsigned int what)
|
|
{
|
|
char buf[1024];
|
|
int ret, val;
|
|
|
|
ret = read(STDIN_FILENO, buf, sizeof(buf));
|
|
if (ret < 0) {
|
|
LOGP(DRS232TEST, LOGL_ERROR, "cannot write to read from "
|
|
"keyboard\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
val = atoi(buf);
|
|
switch(val) {
|
|
case 1:
|
|
printf("sending command PUBX to switch to UBX mode\n");
|
|
send_pubx();
|
|
break;
|
|
case 2:
|
|
printf("sending command TP5\n");
|
|
cfg_tp5();
|
|
break;
|
|
case 3:
|
|
printf("sending command CFG-PRT\n");
|
|
cfg_prt();
|
|
break;
|
|
default:
|
|
printf("wrong option: select 1, 2 or 3\n");
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
struct osmo_fd *kbd_ofd;
|
|
int rc;
|
|
|
|
tall_test = talloc_named_const(NULL, 1, "osmo_rs232_test");
|
|
msgb_talloc_ctx_init(tall_test, 0);
|
|
osmo_init_logging2(tall_test, &osmo_rs232_test_log_info);
|
|
log_set_log_level(osmo_stderr_target, LOGL_NOTICE);
|
|
|
|
r = osmo_rs232_create(tall_test);
|
|
if (r == NULL) {
|
|
LOGP(DRS232TEST, LOGL_ERROR, "cannot create rs232 object\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
osmo_rs232_set_serial_port(r, "/dev/ttyACM0");
|
|
osmo_rs232_set_baudrate(r, 9600);
|
|
osmo_rs232_set_delay_us(r, 3330);
|
|
osmo_rs232_set_read_cb(r, read_cb);
|
|
|
|
if (osmo_rs232_open(r) < 0) {
|
|
LOGP(DRS232TEST, LOGL_ERROR, "cannot open rs232\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
LOGP(DRS232TEST, LOGL_NOTICE, "Entering main loop\n");
|
|
|
|
kbd_ofd = talloc_zero(tall_test, struct osmo_fd);
|
|
if (!kbd_ofd) {
|
|
LOGP(DRS232TEST, LOGL_ERROR, "OOM\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
osmo_fd_setup(kbd_ofd, STDIN_FILENO, OSMO_FD_READ, kbd_cb, NULL, 0);
|
|
rc = osmo_fd_register(kbd_ofd);
|
|
if (rc < 0) {
|
|
LOGP(DRS232TEST, LOGL_ERROR, "FD Register\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
while(1) {
|
|
osmo_select_main(0);
|
|
}
|
|
}
|