blob: 1141393cd270cff18325da29d84a4f283cccb89c [file] [log] [blame]
/*
Based on:
File: SerialPortSample.c
Abstract: Command line tool that demonstrates how to use IOKitLib to find all serial ports on OS X. Also shows how to open, write to, read from, and close a serial port.
Version: 1.5
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
Inc. ("Apple") in consideration of your agreement to the following
terms, and your use, installation, modification or redistribution of
this Apple software constitutes acceptance of these terms. If you do
not agree with these terms, please do not use, install, modify or
redistribute this Apple software.
In consideration of your agreement to abide by the following terms, and
subject to these terms, Apple grants you a personal, non-exclusive
license, under Apple's copyrights in this original Apple software (the
"Apple Software"), to use, reproduce, modify and redistribute the Apple
Software, with or without modifications, in source and/or binary forms;
provided that if you redistribute the Apple Software in its entirety and
without modifications, you must retain this notice and the following
text and disclaimers in all such redistributions of the Apple Software.
Neither the name, trademarks, service marks or logos of Apple Inc. may
be used to endorse or promote products derived from the Apple Software
without specific prior written permission from Apple. Except as
expressly stated in this notice, no other rights or licenses, express or
implied, are granted by Apple herein, including but not limited to any
patent rights that may be infringed by your derivative works or by other
works in which the Apple Software may be incorporated.
The Apple Software is provided by Apple on an "AS IS" basis. APPLE
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
Copyright (C) 2013 Apple Inc. All Rights Reserved.
Copyright (C) 2018-2020 NXP. All Rights Reserved.
*/
#include <stdio.h>
/*TODO Review */
#include "smComSerial.h"
#include <stdlib.h>
#include <stdio.h>
#include "string.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <paths.h>
#include <termios.h>
#include <sysexits.h>
#include <sys/param.h>
#include <sys/select.h>
#include <sys/time.h>
#include <time.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/serial/IOSerialKeys.h>
#include <IOKit/serial/ioss.h>
#include <IOKit/IOBSD.h>
#include "sm_printf.h"
#include "smComSocket.h"
#include "nxLog_smCom.h"
#include "inttypes.h"
#include "nxEnsure.h"
#define REMOTE_JC_SHELL_HEADER_LEN (4)
#define REMOTE_JC_SHELL_MSG_TYPE_APDU_DATA (0x01)
#include "sm_apdu.h"
#define MAX_BUF_SIZE (MAX_APDU_BUF_LENGTH)
// Hold the original termios attributes so we can reset them
static struct termios gOriginalTTYAttrs;
static int fileDescriptor = -1;
U32 smComVCom_Open(void** vcom_ctx, const char *bsdPath)
{
//int handshake;
struct termios options;
if (bsdPath == NULL) {
LOG_E("Need Serail port name");
goto error;
}
// Open the serial port read/write, with no controlling terminal, and don't wait for a connection.
// The O_NONBLOCK flag also causes subsequent I/O on the device to be non-blocking.
// See open(2) <x-man-page://2/open> for details.
fileDescriptor = open(bsdPath, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fileDescriptor == -1) {
printf("Error opening serial port %s - %s(%d).\n", bsdPath, strerror(errno), errno);
goto error;
}
// Note that open() follows POSIX semantics: multiple open() calls to the same file will succeed
// unless the TIOCEXCL ioctl is issued. This will prevent additional opens except by root-owned
// processes.
// See tty(4) <x-man-page//4/tty> and ioctl(2) <x-man-page//2/ioctl> for details.
if (ioctl(fileDescriptor, TIOCEXCL) == -1) {
printf("Error setting TIOCEXCL on %s - %s(%d).\n", bsdPath, strerror(errno), errno);
goto error;
}
// Now that the device is open, clear the O_NONBLOCK flag so subsequent I/O will block.
// See fcntl(2) <x-man-page//2/fcntl> for details.
if (fcntl(fileDescriptor, F_SETFL, 0) == -1) {
printf("Error clearing O_NONBLOCK %s - %s(%d).\n", bsdPath, strerror(errno), errno);
goto error;
}
// Get the current options and save them so we can restore the default settings later.
if (tcgetattr(fileDescriptor, &gOriginalTTYAttrs) == -1) {
printf("Error getting tty attributes %s - %s(%d).\n", bsdPath, strerror(errno), errno);
goto error;
}
// The serial port attributes such as timeouts and baud rate are set by modifying the termios
// structure and then calling tcsetattr() to cause the changes to take effect. Note that the
// changes will not become effective without the tcsetattr() call.
// See tcsetattr(4) <x-man-page://4/tcsetattr> for details.
options = gOriginalTTYAttrs;
// Print the current input and output baud rates.
// See tcsetattr(4) <x-man-page://4/tcsetattr> for details.
// printf("Current input baud rate is %d\n", (int) cfgetispeed(&options));
// printf("Current output baud rate is %d\n", (int) cfgetospeed(&options));
// Set raw input (non-canonical) mode, with reads blocking until either a single character
// has been received or a one second timeout expires.
// See tcsetattr(4) <x-man-page://4/tcsetattr> and termios(4) <x-man-page://4/termios> for details.
cfmakeraw(&options);
options.c_cc[VMIN] = 1;
options.c_cc[VTIME] = 10;
// The baud rate, word length, and handshake options can be set as follows:
cfsetspeed(&options, B115200); // Set baud
options.c_cflag = CS8 | CREAD | CLOCAL;
options.c_iflag = 0;
options.c_oflag = ONOEOT;
//options.c_oflag &= ~ONLCR;
// options.c_cflag |= (CS7 | // Use 7 bit words
// PARENB | // Parity enable (even parity if PARODD not also set)
// CCTS_OFLOW | // CTS flow control of output
// CRTS_IFLOW); // RTS flow control of input
// The IOSSIOSPEED ioctl can be used to set arbitrary baud rates
// other than those specified by POSIX. The driver for the underlying serial hardware
// ultimately determines which baud rates can be used. This ioctl sets both the input
// and output speed.
// Cause the new options to take effect immediately.
if (tcsetattr(fileDescriptor, TCSANOW, &options) == -1) {
printf("Error setting tty attributes %s - %s(%d).\n", bsdPath, strerror(errno), errno);
goto error;
}
speed_t speed = B115200; // Set 14400 baud
if (ioctl(fileDescriptor, IOSSIOSPEED, &speed) == -1) {
printf("Error calling ioctl(..., IOSSIOSPEED, ...) %s - %s(%d).\n", bsdPath, strerror(errno), errno);
}
// Print the new input and output baud rates. Note that the IOSSIOSPEED ioctl interacts with the serial driver
// directly bypassing the termios struct. This means that the following two calls will not be able to read
// the current baud rate if the IOSSIOSPEED ioctl was used but will instead return the speed set by the last call
// to cfsetspeed.
LOG_D("Input baud rate changed to %d\n", (int)cfgetispeed(&options));
LOG_D("Output baud rate changed to %d\n", (int)cfgetospeed(&options));
// To set the modem handshake lines, use the following ioctls.
// See tty(4) <x-man-page//4/tty> and ioctl(2) <x-man-page//2/ioctl> for details.
// // Assert Data Terminal Ready (DTR)
// if (ioctl(fileDescriptor, TIOCSDTR) == -1) {
// printf("Error asserting DTR %s - %s(%d).\n",
// bsdPath, strerror(errno), errno);
// }
//
// // sleep(1);
//
// // // Clear Data Terminal Ready (DTR)
// if (ioctl(fileDescriptor, TIOCCDTR) == -1) {
// printf("Error clearing DTR %s - %s(%d).\n",
// bsdPath, strerror(errno), errno);
// }
// sleep(1);
// // // Set the modem lines depending on the bits set in handshake
// handshake = 0;//TIOCM_DTR | TIOCM_RTS | TIOCM_CTS | TIOCM_DSR;
// if (ioctl(fileDescriptor, TIOCMSET, &handshake) == -1) {
// printf("Error setting handshake lines %s - %s(%d).\n",
// bsdPath, strerror(errno), errno);
// }
// // To read the state of the modem lines, use the following ioctl.
// // See tty(4) <x-man-page//4/tty> and ioctl(2) <x-man-page//2/ioctl> for details.
// // Store the state of the modem lines in handshake
// if (ioctl(fileDescriptor, TIOCMGET, &handshake) == -1) {
// printf("Error getting handshake lines %s - %s(%d).\n",
// bsdPath, strerror(errno), errno);
// }
// printf("Handshake lines currently set to %d\n", handshake);
// unsigned long mics = 1UL;
// // Set the receive latency in microseconds. Serial drivers use this value to determine how often to
// // dequeue characters received by the hardware. Most applications don't need to set this value: if an
// // app reads lines of characters, the app can't do anything until the line termination character has been
// // received anyway. The most common applications which are sensitive to read latency are MIDI and IrDA
// // applications.
// if (ioctl(fileDescriptor, IOSSDATALAT, &mics) == -1) {
// // set latency to 1 microsecond
// printf("Error setting read latency %s - %s(%d).\n",
// bsdPath, strerror(errno), errno);
// goto error;
// }
smCom_Init(&smComVCom_Transceive, &smComVCom_TransceiveRaw);
// Success
return 0;
// Failure path
error:
if (fileDescriptor != -1) {
close(fileDescriptor);
}
return (U32)-1;
}
U32 smComVCom_Close(void* conn_ctx)
{
U32 status = 0;
smComSocket_CloseFD(fileDescriptor);
return status;
}
U32 smComVCom_GetATR(void* conn_ctx, U8 *pAtr, U16 *atrLen)
{
return smComSocket_GetATRFD(fileDescriptor, pAtr, atrLen);
}
U32 smComVCom_Transceive(void* conn_ctx, apdu_t *pApdu)
{
return smComSocket_TransceiveFD(fileDescriptor, pApdu);
}
U32 smComVCom_TransceiveRaw(void* conn_ctx, U8 *pTx, U16 txLen, U8 *pRx, U32 *pRxLen)
{
return smComSocket_TransceiveRawFD(fileDescriptor, pTx, txLen, pRx, pRxLen);
}