Can't interrupt Arduino Uno's bootloader from C - arduino

I'm trying to get the Arduino into programming mode. I want to examine the flash to see if my software is already installed and then upload one of several binaries depending on its need. For testing, I have a simple sketch that does nothing in the loop but sends "In Regular Mode" over the serial port on setup.
Toggling DTR/RTS does indeed reset the Arduino but sending a sync request does nothing and the bootloader times out and passes control to the sketch.
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/io.h>
#include <sys/ioctl.h>
#include <termios.h>
int main()
{
static const uint8_t bSyncString [] = {0x30, 0x20}; // {CMD_STK_GET_SYNC, SYNC_CRC_EOP};
uint8_t bBuffer [256];
unsigned int ctl;
struct termios tty;
int iFd = open ("/dev/ttyACM0", O_RDWR | O_NOCTTY);
if (iFd >= 0)
{
// From STK500 spec: 115.2kbps, 8 data bits, 1stop bits, no parity
if (tcgetattr (iFd, &tty) == 0)
{
cfsetospeed(&tty, B115200);
cfsetispeed(&tty, B115200);
tty.c_cflag |= CS8|CSTOPB;
tty.c_cflag &= ~(PARENB|PARODD);
if (tcsetattr(iFd, TCSANOW|TCSADRAIN, &tty) == 0)
printf ("Attributes set\n");
}
if (ioctl (iFd, TIOCMGET, &ctl) >= 0) // Get current line states
{
ctl &= ~(TIOCM_DTR|TIOCM_RTS);
if (ioctl(iFd, TIOCMSET, &ctl) >= 0) // DTR and RTS low
{
usleep (50 * 1000);
ctl |= TIOCM_DTR|TIOCM_RTS;
if (ioctl(iFd, TIOCMSET, &ctl) >= 0) // DTR and RTS high
{
usleep (50 * 1000);
if (write (iFd, bSyncString, 2) == 2)
if (read (iFd, bBuffer, sizeof (bBuffer)) > 0)
printf ("Received %s\n", bBuffer);
}
}
}
close (iFd);
}
}

Got it. I took the source of avrdude, extracted the relevant bits and then cut them down to the bone, pasting functionality back and forth until it worked.
Some of my serial settings were off and the delay before sending the write was too short so a minimal setup is as follows:
int main()
{
static const uint8_t bSyncString [] = {0x30, 0x20}; // {CMD_STK_GET_SYNC, SYNC_CRC_EOP};
uint8_t bBuffer [256];
unsigned int ctl;
struct termios tty;
int iFd = open ("/dev/ttyACM0", O_RDWR | O_NOCTTY);
if (iFd >= 0)
{
// From STK500 spec: 115.2kbps, 8 data bits, 1stop bits, no parity
if (tcgetattr (iFd, &tty) == 0)
{
tty.c_iflag = IGNBRK;
tty.c_oflag = 0;
tty.c_lflag = 0;
tty.c_cflag = (CS8 | CREAD | CLOCAL);
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 0;
cfsetospeed(&tty, B115200);
cfsetispeed(&tty, B115200);
if (tcsetattr(iFd, TCSANOW, &tty) == 0)
printf ("Attributes set\n");
}
if (ioctl (iFd, TIOCMGET, &ctl) >= 0) // Get current line states
{
ctl &= ~(TIOCM_DTR|TIOCM_RTS);
if (ioctl(iFd, TIOCMSET, &ctl) >= 0) // DTR and RTS low
{
usleep (50 * 1000);
ctl |= TIOCM_DTR|TIOCM_RTS;
if (ioctl(iFd, TIOCMSET, &ctl) >= 0) // DTR and RTS high
usleep (250 * 1000);
}
}
if (write (iFd, bSyncString, 2) == 2)
{
int iRead = read (iFd, bBuffer, sizeof (bBuffer));
if (iRead > 0)
{
printf ("Received %s\n", bBuffer);
for (int i = 0; i < iRead; i++)
printf ("%02x ", bBuffer [i]);
printf ("\n");
}
}
close (iFd);
}
}

Related

How to send unprocessed output over linux serial port?

I did everything. I shutoff the bits to disable the output processing in the termios structure, properly set the baud rate and character size and disabled parity, flush the output and input buffers before sending. Even after all this linux serial still doesn't work the way I want it to. Canonical mode is not even on in the first place, everything is raw bytes. Btw I am using arch linux connected to an arduino nano with an usb cable which will receive the bytes from PC and display them on a lcd. When I send a byte from PC, e.g char 'A', it apears to get corrupted during the transmisson process, and arduino displays the corrupted byte. Everytime I send character 'A' it shows ascii value 254 on the lcd which is clearly wrong. How do I solve this problem?
My C code on pc:
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int serial_port = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);
getchar();
struct termios old_tty;
struct termios new_tty;
if (tcgetattr(serial_port, &new_tty) != 0) {
printf("Error %i from tcgetattr: %s\n", errno, strerror(errno));
return 1;
}
old_tty = new_tty;
new_tty.c_cflag &= ~(CSTOPB | CSIZE | PARENB);
new_tty.c_cflag |= CS8;
new_tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
new_tty.c_oflag &= ~OPOST;
new_tty.c_iflag &= ~(IXON | IXOFF | IXANY | INPCK | ISTRIP);
//new_tty.c_cc[VMIN] = 0;
//new_tty.c_cc[VTIME] = 0;
cfsetispeed(&new_tty, B9600);
cfsetospeed(&new_tty, B9600);
if (tcsetattr(serial_port, TCSANOW, &new_tty) != 0) {
printf("Error %i from tcsetattr: %s\n", errno, strerror(errno));
return 1;
}
tcflush(serial_port, TCIOFLUSH);
unsigned char val = 'A';
write(serial_port, &val, sizeof(val));
getchar();
tcsetattr(serial_port, TCSANOW | TCSADRAIN, &old_tty);
close(serial_port);
return 0;
}
Code on Arduino:
void setup() {
lcd.begin(16, 2); // begins connection to the LCD module
lcd.backlight(); // turns on the backlight
lcd.clear();
lcd.setCursor(0, 0);
Serial.begin(9600);
lcd.print("Init done");
}
void loop() {
if (Serial.available() > 0) {
uint8_t x = Serial.read();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("I received: ");
lcd.setCursor(0, 1);
lcd.print(x);
}
}

STM32F103xxxx In Application Programming Using Arduino

I am using Arduino_STM32 rogerclark's library.https://github.com/rogerclarkmelbourne/Arduino_STM32 .
Now I want to Develop an In Application Programming(IAP) like a bootloader. Take Code from SD card and Store in Controller flash at 0x8010000 and then jump to that location and run the loaded new application.
the code took from SD and stored into flash successfully done but after jump function called its printing null like this
13:29:04.933 [RX] - Starts............
13:29:07.970 [RX] - 20480 uploaded successfully.
NULNULNULNUL NULNUL
my Main IAP code is
Header file
#include <SPI.h>
#include <SD.h>
#include <EEPROM.h>
#include <stdint.h>
#include "libmaple/scb.h"
#include "usb_lib.h"
typedef void (*FuncPtr)(void);
#define SCS_BASE ((u32)0xE000E000)
#define NVIC_BASE (SCS_BASE + 0x0100)
#define SCB_BASE (SCS_BASE + 0x0D00)
#define SCS 0xE000E000
#define NVIC (SCS+0x100)
#define SCB (SCS+0xD00)
#define STK (SCS+0x10)
#define SCB_VTOR (SCB+0x08)
#define STK_CTRL (STK+0x00)
#define RCC ((u32)0x40021000)
#define RCC_CR RCC
#define RCC_CFGR (RCC + 0x04)
#define RCC_CIR (RCC + 0x08)
#define USB_LP_IRQ ((u8)0x14)
#define SET_REG(addr,val) do{ *(volatile uint32_t*)(addr)=val;} while(0)
#define GET_REG(addr) (*(vu32*)(addr))
#define pRCC ((rcc_reg_map *) RCC)
typedef struct {
u8 NVIC_IRQChannel;
u8 NVIC_IRQChannelPreemptionPriority;
u8 NVIC_IRQChannelSubPriority;
bool NVIC_IRQChannelCmd; /* TRUE for enable */
} NVIC_InitTypeDef;
#define RegBase (0x40005C00L)
#define CNTR ((volatile unsigned *)(RegBase + 0x40))
#define _SetCNTR(wRegValue) (*CNTR = (u16)wRegValue)
#define _GetCNTR() ((u16) *CNTR)
#define ISTR ((volatile unsigned *)(RegBase + 0x44))
#define _SetISTR(wRegValue) (*ISTR = (u16)wRegValue)
#define _GetISTR() ((u16) *ISTR)
void setupFLASH();
void usbDsbISR(void);
void nvicInit(NVIC_InitTypeDef *NVIC_InitStruct);
void nvicDisableInterrupts();
void setMspAndJump(u32 usrAddr);
void systemReset(void);
RESULT usbPowerOff(void);
void setupFLASH()
{
/* configure the HSI oscillator */
if ((pRCC->CR & 0x01) == 0x00)
{
u32 rwmVal = pRCC->CR;
rwmVal |= 0x01;
pRCC->CR = rwmVal;
}
/* wait for it to come on */
while ((pRCC->CR & 0x02) == 0x00) {}
}
void usbDsbISR(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USB_LP_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = FALSE;
nvicInit(&NVIC_InitStructure);
}
void nvicInit(NVIC_InitTypeDef *NVIC_InitStruct)
{
u32 tmppriority = 0x00;
u32 tmpreg = 0x00;
u32 tmpmask = 0x00;
u32 tmppre = 0;
u32 tmpsub = 0x0F;
scb_reg_map *rSCB = (scb_reg_map *) SCB_BASE;
nvic_reg_map *rNVIC = (nvic_reg_map *) NVIC_BASE;
/* Compute the Corresponding IRQ Priority --------------------------------*/
tmppriority = (0x700 - (rSCB->AIRCR & (u32)0x700)) >> 0x08;
tmppre = (0x4 - tmppriority);
tmpsub = tmpsub >> tmppriority;
tmppriority = (u32)NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << tmppre;
tmppriority |= NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub;
tmppriority = tmppriority << 0x04;
tmppriority = ((u32)tmppriority) << ((NVIC_InitStruct->NVIC_IRQChannel & (u8)0x03) * 0x08);
tmpreg = rNVIC->IP[(NVIC_InitStruct->NVIC_IRQChannel >> 0x02)];
tmpmask = (u32)0xFF << ((NVIC_InitStruct->NVIC_IRQChannel & (u8)0x03) * 0x08);
tmpreg &= ~tmpmask;
tmppriority &= tmpmask;
tmpreg |= tmppriority;
rNVIC->IP[(NVIC_InitStruct->NVIC_IRQChannel >> 0x02)] = tmpreg;
/* Enable the Selected IRQ Channels --------------------------------------*/
rNVIC->ISER[(NVIC_InitStruct->NVIC_IRQChannel >> 0x05)] =
(u32)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (u8)0x1F);
}
void nvicDisableInterrupts()
{
nvic_reg_map *rNVIC = (nvic_reg_map *) NVIC_BASE;
rNVIC->ICER[0] = 0xFFFFFFFF;
rNVIC->ICER[1] = 0xFFFFFFFF;
rNVIC->ICPR[0] = 0xFFFFFFFF;
rNVIC->ICPR[1] = 0xFFFFFFFF;
SET_REG(STK_CTRL, 0x04); /* disable the systick, which operates separately from nvic */
}
void usbDsbBus(void)
{
// setPin(USB_DISC_BANK,USB_DISC_PIN);
usbPowerOff();
// SET_REG(USB_DISC_CR,
// (GET_REG(USB_DISC_CR) & USB_DISC_CR_MASK) | USB_DISC_CR_OUTPUT);
// resetPin(USB_DISC_BANK, USB_DISC_PIN); /* Pull DP+ down */
// volatile unsigned x = 500000; do { ; }while(--x);
// SET_REG(USB_DISC_CR,
// (GET_REG(USB_DISC_CR) & USB_DISC_CR_MASK) | USB_DISC_CR_INPUT); //Sets the PA12 as floating
input
}
RESULT usbPowerOff(void)
{
#define CNTR_PDWN (0x0002) /* Power DoWN */
#define CNTR_FRES (0x0001) /* Force USB RESet */
_SetCNTR(CNTR_FRES);
_SetISTR(0);
_SetCNTR(CNTR_FRES + CNTR_PDWN);
/* note that all weve done here is powerdown the
usb peripheral. we have no disabled the clocks,
pulled the USB_DISC_PIN pin back up, or reset the
application state machines */
return USB_SUCCESS;
}
void systemReset(void)
{
SET_REG(RCC_CR, GET_REG(RCC_CR) | 0x00000001);
SET_REG(RCC_CFGR, GET_REG(RCC_CFGR) & 0xF8FF0000);
SET_REG(RCC_CR, GET_REG(RCC_CR) & 0xFEF6FFFF);
SET_REG(RCC_CR, GET_REG(RCC_CR) & 0xFFFBFFFF);
SET_REG(RCC_CFGR, GET_REG(RCC_CFGR) & 0xFF80FFFF);
SET_REG(RCC_CIR, 0x00000000); /* disable all RCC interrupts */
}
void setMspAndJump(u32 usrAddr)
{
// Dedicated function with no call to any function (appart the last call)
// This way, there is no manipulation of the stack here, ensuring that GGC
// didn't insert any pop from the SP after having set the MSP.
typedef void (*funcPtr)(void);
u32 jumpAddr = *(vu32 *)(usrAddr + 0x04); /* reset ptr in vector table */
funcPtr usrMain = (funcPtr) jumpAddr;
SET_REG(SCB_VTOR, (vu32) (usrAddr));
asm volatile("msr msp, %0"::"g"(*(volatile u32 *)usrAddr));
usrMain(); /* go! */
}
main code is
#include "core_test.h"
#define CS PB9
File myFile;
char Name[15] = "ASCII.bin";
uint32_t Count = 0;
uint32_t total = 0;
#define FLASH_FLAG_EOP ((uint32_t)0x00000020) /* FLASH End of Operation flag */
#define FLASH_FLAG_PGERR ((uint32_t)0x00000004) /* FLASH Program error flag */
#define FLASH_FLAG_WRPRTERR ((uint32_t)0x00000010) /* FLASH Write protected error flag */
#define myFLASH_APP_ADDR 0x08000000
#define FLASH_APP_ADDR 0x08010000 //The first application start address (stored in FLASH)
#define STM_PAGE_SIZE 2048 //Note: The FLASH page size of STM32F103ZET6 is 2K.
//****************************************************************************************************
// Global variable declaration
char buff[STM_PAGE_SIZE];
int res;
unsigned int br;
void Jump2App(uint32_t Addr)
{
if (((*(uint32_t*)Addr) & 0x2FFE0000) == 0x20000000) //Check if the top address of the stack is legal.
{
// FLASH_Lock();
usbDsbISR(); //Serial1.println("1");
nvicDisableInterrupts(); //Serial1.println("2");
usbDsbBus(); //Serial1.println("3");
// Does nothing, as PC12 is not connected on teh Maple mini according to the schemmatic setPin(GPIOC, 12); // disconnect usb from host. todo, macroize pin
systemReset(); // resets clocks and periphs, not core regs
//Serial1.println("4");
setMspAndJump(Addr);
}
}
void FirmwareUpdate(void)
{
int PageOffest = 0;
int ByteOffest;
if (! IsFileExists(Name)) return;
myFile = SD.open(Name);
while (1)
{
if (Read_data_from_File(buff))
{
FLASH_Unlock();
// FLASH_ClearFlag(((uint16_t)0x00000034));
// FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
FLASH_ErasePage(FLASH_APP_ADDR + PageOffest);
for (ByteOffest = 0; ByteOffest < STM_PAGE_SIZE; ByteOffest += 2)
{
total = total + 2;
FLASH_ProgramHalfWord(FLASH_APP_ADDR + PageOffest + ByteOffest, *(uint16_t*)(buff + ByteOffest));
}
FLASH_Lock();
PageOffest += STM_PAGE_SIZE;
// Serial1.println(PageOffest);
}
else if (myFile.size() <= total) break;
}
myFile.close();
Serial1.println(total);
//myFile.close();
}
void setup()
{
afio_cfg_debug_ports(AFIO_DEBUG_SW_ONLY);
Serial1.begin(9600);
if (!SD.begin(CS))
{
Serial1.println("No SD............");
Jump2App(FLASH_APP_ADDR);
}
delay(1000);
Serial1.println("Starts............"); delay(2000);
FirmwareUpdate();
Jump2App(FLASH_APP_ADDR);
while (1);
}
void loop()
{}
bool IsFileExists(char FileName[])
{
if (SD.exists(FileName)) return 1;
else return 0;
}
bool Read_data_from_File(char str[])
{
memset(str, 255, 2048);
uint16_t i = 0;
if (myFile.size() < total)
{
//memset(str, 255, 2048);
// Serial1.println("File Closed");
// Serial1.println(total);
return 0;
}
if (myFile)
{
while (i < 2048)
{
str[i++] = myFile.read();
Count = Count + 1;
if (myFile.size() < Count)
{
//memset(str, 255, 2048);
// Serial1.println("File Closed");
// Serial1.println(Count);
return 1;
}
}
}
else return 0;
}
my user Application code is ASCIItable example code which is given in arduino
before generation this ASCII.bin file
i have changed ROM location address 0x8000000 to 0x8010000 and compiled the file.
Is this process correct,
please help me where I am doing wrong

Termios transmitting user name before data

I am trying to use serial communication in Raspberry Pi. I found this link. I made only one change in the code and increase the buffer value to 30. Here my edited code:-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
int main(int argc, char* argv[]) {
struct termios serial;
char* str = "Hello";
char buffer[30];
if (argc == 1) {
printf("Usage: %s [device]\n\n", argv[0]);
return -1;
}
printf("Opening %s\n", argv[1]);
int fd = open(argv[1], O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1) {
perror(argv[1]);
return -1;
}
if (tcgetattr(fd, &serial) < 0) {
perror("Getting configuration");
return -1;
}
// Set up Serial Configuration
serial.c_iflag = 0;
serial.c_iflag = 0;
serial.c_oflag = 0;
serial.c_lflag = 0;
serial.c_cflag = 0;
serial.c_cc[VMIN] = 0;
serial.c_cc[VTIME] = 0;
serial.c_cflag = B115200 | CS8 | CREAD;
tcsetattr(fd, TCSANOW, &serial); // Apply configuration
// Attempt to send and receive
printf("Sending: %s\n", str);
//int wcount = write(fd, &str, strlen(str));
int wcount = write(fd, str, strlen(str));
if (wcount < 0) {
perror("Write");
return -1;
}
else {
printf("Sent %d characters\n", wcount);
}
// int rcount = read(fd, &buffer, sizeof(buffer));
int rcount = read(fd, buffer, sizeof(buffer));
if (rcount < 0) {
perror("Read");
return -1;
}
else {
printf("Received %d characters\n", rcount);
}
buffer[rcount] = '\0';
printf("Received: %s\n", buffer);
close(fd);
}
I short Rx and Tx pin and run this code. I should receive "Hello" but I am getting this:-
Received: pi#raspberrypi:~$ Hello
So, it is clear that I am receiving "Hello" but additionally I am automatically transmitting
pi#raspberrypi:~$
So, please tell me I to stop transmitting my user name.

Raspberry Pi UART program in C using termios receives garbage (Rx and Tx are connected directly)

I have a simple program written in C which uses termios to send a basic string to the Raspberry Pi UART and attempts to read and output the response. The Rx and Tx pins on the Raspberry Pi are connected with a jumper so whatever is sent should be immediately received.
Despite the program outputting that it successfully sent and received 5 characters for the chosen string ('Hello'), trying to print the contents of the buffer just produces one or two garbage characters.
The program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
int main(int argc, char* argv[]) {
struct termios serial;
char* str = "Hello";
char buffer[10];
if (argc == 1) {
printf("Usage: %s [device]\n\n", argv[0]);
return -1;
}
printf("Opening %s\n", argv[1]);
int fd = open(argv[1], O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1) {
perror(argv[1]);
return -1;
}
if (tcgetattr(fd, &serial) < 0) {
perror("Getting configuration");
return -1;
}
// Set up Serial Configuration
serial.c_iflag = 0;
serial.c_oflag = 0;
serial.c_lflag = 0;
serial.c_cflag = 0;
serial.c_cc[VMIN] = 0;
serial.c_cc[VTIME] = 0;
serial.c_cflag = B115200 | CS8 | CREAD;
tcsetattr(fd, TCSANOW, &serial); // Apply configuration
// Attempt to send and receive
printf("Sending: %s\n", str);
int wcount = write(fd, &str, strlen(str));
if (wcount < 0) {
perror("Write");
return -1;
}
else {
printf("Sent %d characters\n", wcount);
}
int rcount = read(fd, &buffer, sizeof(buffer));
if (rcount < 0) {
perror("Read");
return -1;
}
else {
printf("Received %d characters\n", rcount);
}
buffer[rcount] = '\0';
printf("Received: %s\n", buffer);
close(fd);
}
Outputs:
Opening /dev/ttyAMA0
Sending: Hello
Sent 5 characters
Received 5 characters
Received: [garbage]
I can't see any major problem with the code myself, but I might be wrong. I can successfully send and receive characters using PuTTY connected with the same settings, so it can't really be a hardware problem. Although I haven't tried it in PuTTY, trying to connect with anything less than 115200 baud with this program will result in nothing being received.
Where am I going wrong?
int wcount = write(fd, &str, strlen(str));
int rcount = read(fd, &buffer, sizeof(buffer));
In these lines, buffer/str are already pointers. You are passing a pointer to a pointer.
The lines should be:
int wcount = write(fd, str, strlen(str));
int rcount = read(fd, buffer, sizeof(buffer));

How to read a binary data over serial terminal in C program?

I read followed links and other sources, but didn't find answer for my question.
Binary data over serial terminal
Data gets corrupted during transmission over the serial port
I communicate with my embedded device through a serial port. By default, embedded Linux uses this port as a terminal. But I want to transfer also binary data (service packets) through the port. My /etc/inittab file has a "getty" call:
console::respawn:/sbin/getty 115200 ttyS0
I also have /etc/passwd file with string where "admin" user launch my "cli" application after log in:
admin:8Mt/Jtxcyg8AY:1000:0:admin:/tmp:/tmp/cli
My default ttyS0 settings before running the program is:
~ # stty -a
speed 115200 baud;stty: standard input
line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = ^J;
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon ixoff
-iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon -iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
-echoctl echoke
~ #
So, in my cli program I do the following:
main ()
{
...
system("stty erase ^H);
system("stty -F /dev/ttyS0 -icrnl -ixon -ixoff -opost -isig -icanon -echo"); // enter in non-canonical (raw) mode
// What function do I need to use here to retrieve binary data (also symbols that > 0x7F) from /dev/ttyS0?
system("stty -F /dev/ttyS0 icrnl ixon ixoff opost isig icanon echo"); // go back to canonical mode
...
exit(0);
}
I have attempted read() function (with unsigned char buffer) to get binary data, but failed to receive correct data. I also preliminarily open /dev/ttyS0 again to get file_descriptor & use read() func.
My program sends 3 bytes: 0xAA, 0x02, 0xFE.
But in syslog I always see that device receives incorrect symbols: 0x98, 0xE6, 0x18.
What is the matter? How to get correct binary data?
A whole code that I am testing at the moment.
#include "cli.h"
#include "glb_vars.h"
/******************************************
*** Definitions
******************************************/
#define APPLICATION_NAME "cli"
#define SERIALPORT_IS_CONSOLE
/******************************************
*** Constants
******************************************/
const char dev_name[] = DEV_NAME;
const char lineminstr[] = "\t--------------------------------------------------------\n";
/******************************************
*** Internal Function Declarations
******************************************/
CLI_RETVAL cliInit(void);
CLI_RETVAL cliClose(void);
void cliWorkLoop(Term_callback_t **term);
/******************************************
*** External Function Declarations
******************************************/
extern void Vectors_init(Term_callback_t **vec);
extern char** Menu_completion(const char * text, int start, int end);
/****************************************************************************/
int file_descr, max_fd;
struct termios tty, orig_tty;
fd_set work_set;
/****************************************************************************/
/*!
* \brief Init cli
*
* \return success or failure
* \retval CLI_SUCCESS, CLI_FAILURE
*
* \ingroup CLI
*/
/****************************************************************************/
CLI_RETVAL cliInit(void)
{
long spd;
signal(SIGINT, SIG_IGN);
signal(SIGHUP, SIG_IGN);
signal(SIGTERM, SIG_IGN);
signal(SIGABRT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
signal(SIGILL, SIG_IGN);
// system("stty -F /dev/ttyS0 -icrnl -ixon -ixoff -opost -isig -icanon -echo"); // enter in non-canonical mode
// system("stty -a");
// sleep(1);
#ifdef SERIALPORT_IS_CONSOLE
file_descr = STDIN_FILENO;
SYS_LOG_DEBUG("SERIALPORT IS CONSOLE");
#else
SYS_LOG_DEBUG("SERIALPORT IS NOT CONSOLE");
file_descr = open("/dev/ttyS0", O_RDWR | O_ASYNC | O_NDELAY);
if (file_descr == -1) {
// Could not open the port
perror("unable to open /dev/ttyS0");
exit(1);
}
#endif
if(tcgetattr(file_descr, &tty) < 0)
{
perror("unable to get tty attributes");
exit(1);
}
// backup tty, make it raw and apply changes
orig_tty = tty;
spd = B115200;
cfsetospeed(&tty, (speed_t)spd);
cfsetispeed(&tty, (speed_t)spd);
cfmakeraw(&tty);
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 10;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS; /* no HW flow control? */
tty.c_cflag |= CLOCAL | CREAD;
tcsetattr(file_descr, TCSANOW, &tty);
// // update local mode flags
// tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
//// // renew control mode flags
//// tty.c_cflag &= ~(CBAUD | CSIZE | CSTOPB | PARENB | PARODD);
//// tty.c_cflag |= (BAUD | DATABITS | STOPBITS | PARITYON | PARITY);
// // select 'raw' output mode
// tty.c_oflag &= ~OPOST;
// // disable mapping for input mode
// tty.c_iflag &= ~(INLCR | ICRNL);
//
//
// if(tcsetattr(file_descr, TCSAFLUSH, &tty) < 0)
// {
// perror("unable to set tty attributes");
// exit(1);
// }
//
// Setup fd_set
FD_ZERO(&work_set);
FD_SET(file_descr, &work_set);
max_fd = file_descr + 1;
/* Readline lib init */
// Define application name for readline library
rl_readline_name = APPLICATION_NAME;
// Update Pointer to alternative function to create matches.
rl_attempted_completion_function = Menu_completion;
// Start readline with reading /etc/inputrc file
using_history();
stifle_history(CLI_MAX_HISTORY_SIZE);
// Some other initialization code
// ...
// ...
return CLI_SUCCESS;
}
/****************************************************************************/
/*!
* \brief Close cli
*
* \return success or failure
* \retval CLI_SUCCESS, CLI_FAILURE
*
* \ingroup CLI
*/
/****************************************************************************/
CLI_RETVAL cliClose(void)
{
// system("stty -F /dev/ttyS0 icrnl ixon ixoff opost isig icanon echo"); // enter in canonical mode
tcsetattr(file_descr, TCSANOW, &orig_tty);
// if(tcsetattr(file_descr, TCSAFLUSH, &orig_tty) < 0)
// {
// perror("unable to set orig_tty attributes");
// exit(1);
// }
close(file_descr);
return CLI_SUCCESS;
}
/****************************************************************************/
/*!
* \brief Main cli processing loop
*
* \no return
*
* \ingroup CLI
*/
/****************************************************************************/
void cliWorkLoop(Term_callback_t **term)
{
Term_callback_t *cur_term;
int8 *commandString;
uint8 ret = CLI_REFRESH, no_prompt;
char prompt_str[20];
while (1) {
cur_term = *term;
global_cmd_compl_pointer = cur_term->cmd_list;
commandString = NULL;
sprintf(prompt_str, "%s:~> ", dev_name);
if(ret == CLI_REFRESH) {
CLEAR_SCR();
if(cur_term->out != NULL) {
cur_term->out(term, commandString, &ret);
no_prompt = ret;
}
CURSOR_DOWN();
}
int n;
struct timeval timeout;
uint8 tmpBuf[32];
while (1)
{
// Setup Timeout
timeout.tv_sec = 60;
timeout.tv_usec = 0;
// Wait for new connections
n = select(max_fd, &work_set, NULL, NULL, &timeout);
if (n < 0)
{
perror("select #2 failed");
break;
}
if (n > 0)
{
/* У нас есть ввод */
if (FD_ISSET(file_descr, &work_set))
{
if (read(file_descr, tmpBuf, 10) < 0) {
perror("cannot read");
exit(1);
}
else
{
SYS_LOG_DEBUG("READ first 4 chars: 0x%X,0x%X,0x%X,0x%X", tmpBuf[0], tmpBuf[1], tmpBuf[2], tmpBuf[3]);
}
}
break;
}
}
//
//
// n = read(file_descr, tmpBuf, 5);
// if (n > 0) {
// unsigned char *p = tmpBuf;
//
// while (n-- > 0)
// printf(" 0x%x", *p++);
// printf("\r\n");
// } else {
// printf("failed to read: %d\r\n", n);
// }
//
//
exit(0);
}
CLEAR_SCR();
return;
}
/****************************************************************************/
/*!
* \brief Main cli function
*
* \param[in] argc - argument number.
* \param[in,out] argv - argument values entered by user.
*
* \return success or failure
* \retval EXIT_SUCCESS, EXIT_FAILURE
*
*
* \ingroup CLI
*/
/****************************************************************************/
int main(int argc, char *argv[])
{
Term_callback_t *term;
char logname[16];
FILE *fp;
/* Set mask for file operation */
umask(0);
system("stty erase ^H");
openlog("cli", LOG_CONS, LOG_USER);
/* Write cli start log */
syslog(LOG_NOTICE, "Console startup. Software version: %s", VERSION);
/* Find login name */
strcpy(logname, "noname");
if ((fp = popen( "whoami", "r" )) == NULL)
{
SYS_LOG_ERR("Can't open process for \"whoami\" command.");
} else
{
fgets(logname, 16, fp);
pclose(fp);
}
SYS_LOG_INFO("Console is entered by \"%s\".", logname); //getenv("USER")
/* Console initialization */
if (cliInit() != CLI_SUCCESS) {
SYS_LOG_CRIT("CLI init failed");
return EXIT_FAILURE;
}
Vectors_init(&term);
/* Console work loop */
cliWorkLoop(&term);
cliClose();
/* Exiting from cli */
SYS_LOG_INFO("\"%s\" exited from console.", logname);
return EXIT_SUCCESS;
}
system("stty erase ^H);
system("stty -F /dev/ttyS0 -icrnl -ixon -ixoff -opost -isig -icanon -echo"); // enter into non-canonical (raw) mode
This would be insufficient code (and poor coding practice per POSIX conventions) to put the serial port into raw or non-canonical mode.
The easiest method in C and Linux is to use the function cfmakeraw() which is available in both the GNU libc and uClibc libraries. Use the man page to obtain the details on the termios structure members that are modified by cfmakeraw().
Beware that cfmakeraw() will setup the serial port in raw mode for a data length of 8 bits and no parity, for a total character frame of 10 bits (assuming one stop bit).
The preferred method is preserving a copy of the termios stucture (for restoration on program exit) and only modifying the required flag bits (rather than writing the complete structure members).
REVISION
Code that works on my ARM SoC is:
#include <stdio.h>
#include <stdlib.h>
#include <sys/un.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/syslog.h>
#include <termios.h>
#define SERIALPORT_IS_CONSOLE
main()
{
struct termios tty;
struct termios savetty;
speed_t spd;
unsigned int sfd;
unsigned char buf[80];
int reqlen = 79;
int rc;
int rdlen;
int pau = 0;
#ifdef SERIALPORT_IS_CONSOLE
sfd = STDIN_FILENO;
#else
sfd = open("/dev/ttyS1", O_RDWR | O_NOCTTY);
#endif
if (sfd < 0) {
syslog(LOG_DEBUG, "failed to open: %d, %s", sfd, strerror(errno));
exit (-1);
}
syslog(LOG_DEBUG, "opened sfd=%d for reading", sfd);
rc = tcgetattr(sfd, &tty);
if (rc < 0) {
syslog(LOG_DEBUG, "failed to get attr: %d, %s", rc, strerror(errno));
exit (-2);
}
savetty = tty; /* preserve original settings for restoration */
spd = B115200;
cfsetospeed(&tty, (speed_t)spd);
cfsetispeed(&tty, (speed_t)spd);
cfmakeraw(&tty);
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 10;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS; /* no HW flow control? */
tty.c_cflag |= CLOCAL | CREAD;
rc = tcsetattr(sfd, TCSANOW, &tty);
if (rc < 0) {
syslog(LOG_DEBUG, "failed to set attr: %d, %s", rc, strerror(errno));
exit (-3);
}
do {
unsigned char *p = buf;
rdlen = read(sfd, buf, reqlen);
if (rdlen > 0) {
if (*p == '\r')
pau = 1;
syslog(LOG_DEBUG, "read: %d, 0x%x 0x%x 0x%x", \
rdlen, *p, *(p + 1), *(p + 2));
} else {
syslog(LOG_DEBUG, "failed to read: %d, %s", rdlen, strerror(errno));
}
} while (!pau);
tcsetattr(sfd, TCSANOW, &savetty);
close(sfd);
exit (0);
}
The compiled program is loaded & executed on the target board.
From the host side of the serial comm link, the file seq.bin with the following contents is sent:
$ od -t x1 seq.bin
0000000 aa 02 fe
0000003
Then "ABC" is typed on the host (which is running the minicom terminal emulator program), followed by a carriage return.
The program terminates on the target, and the syslog is then examined:
# tail /var/log/messages
Sep xx xx:xx:42 atmel_soc user.info kernel: EXT3 FS on nvsram, internal journal
Sep xx xx:xx:42 atmel_soc user.info kernel: EXT3-fs: mounted filesystem with or.
Sep xx xx:xx:42 atmel_soc user.info kernel: kjournald starting. Commit intervas
Sep xx xx:xx:18 atmel_soc auth.info login[431]: root login on 'ttyS0'
Sep xx xx:xx:04 atmel_soc user.debug syslog: opened sfd=0 for reading
Sep xx xx:xx:14 atmel_soc user.debug syslog: read: 3, 0xaa 0x2 0xfe
Sep xx xx:xx:50 atmel_soc user.debug syslog: read: 1, 0x41 0x2 0xfe
Sep xx xx:xx:51 atmel_soc user.debug syslog: read: 1, 0x42 0x2 0xfe
Sep xx xx:xx:51 atmel_soc user.debug syslog: read: 1, 0x43 0x2 0xfe
Sep xx xx:xx:52 atmel_soc user.debug syslog: read: 1, 0xd 0x2 0xfe
#
The binary data has been received intact.
Note that since this is raw mode and the typed chars were entered relatively slowly, the read() returns "partial" data and the user program would be responsible for buffering/assembling the data into complete "messages". If the messages are of fixed length, then c_cc[VMIN]member could be set to the message length. But beware of message framing issues and complications when frame sync is lost!

Resources