I need to determine what iPad version my app is running on before setting up an openGl surface.
If it's running on the old iPad 1, it is way too slow to enable antialiasing, while on iPad 2+3 there should be no performance issues, so I need to detect this first.
Any ideas on how to detect the iPad generation using Monotouch?
Thanks Joachim, your hint led me to the following solution, which I have tested on physical 1 - 3 generation iPads, and it should also be able to detect other Apple devices:
public enum HardwareVersion
{
iPhone2G,
iPhone3G,
iPhone3Gs,
iPhone4,
iPod1G,
iPod2G,
iPod3G,
Simulator,
iPad1G,
iPad2G,
iPad3G,
Unknown
}
[DllImport(MonoTouch.Constants.SystemLibrary)]
static internal extern int sysctlbyname ([MarshalAs(UnmanagedType.LPStr)] string property, IntPtr output, IntPtr oldLen, IntPtr newp, uint newlen);
public static HardwareVersion getHardwareVersion()
{
string HardwareProperty = "hw.machine";
// get the length of the string that will be returned
var pLen = Marshal.AllocHGlobal (sizeof(int));
sysctlbyname (HardwareProperty, IntPtr.Zero, pLen, IntPtr.Zero, 0);
var length = Marshal.ReadInt32 (pLen);
// check to see if we got a length
if (length == 0) {
Marshal.FreeHGlobal (pLen);
return HardwareVersion.Unknown;
}
// get the hardware string
var pStr = Marshal.AllocHGlobal (length);
sysctlbyname (HardwareProperty, pStr, pLen, IntPtr.Zero, 0);
// convert the native string into a C# string
var hardwareStr = Marshal.PtrToStringAnsi (pStr);
var ret = HardwareVersion.Unknown;
// determine which hardware we are running
if (hardwareStr == "iPhone1,1")
ret = HardwareVersion.iPhone2G;
else if (hardwareStr == "iPhone1,2")
ret = HardwareVersion.iPhone3G;
else if (hardwareStr == "iPhone2,1")
ret = HardwareVersion.iPhone3Gs;
else if (hardwareStr == "iPhone3,1")
ret = HardwareVersion.iPhone4;
else if (hardwareStr == "iPod1,1")
ret = HardwareVersion.iPod1G;
else if (hardwareStr == "iPod2,1")
ret = HardwareVersion.iPod2G;
else if (hardwareStr == "iPod3,1")
ret = HardwareVersion.iPod3G;
else if (hardwareStr == "iPad1,1")
ret = HardwareVersion.iPad1G;
else if (hardwareStr == "iPad2,1")
ret = HardwareVersion.iPad2G;
else if (hardwareStr == "iPad3,1")
ret = HardwareVersion.iPad3G;
else if (hardwareStr == "i386" || hardwareStr == "x86_64" || hardwareStr == "x86_32" )
ret = HardwareVersion.Simulator;
// cleanup
Marshal.FreeHGlobal (pLen);
Marshal.FreeHGlobal (pStr);
return ret;
}
You can find the hardware version using P/Invoke to sysctlbyname.
It's slightly complex though, so I'd recommend you use the code available at Xamarin's Wiki and extend it with iPad2 (iPad2,1) and above yourself. Perhaps also update the wiki with your changes :)
Related
I am new to the world of STM32 MCU's so please bear with me.
I am following a tutorial on Udemy and trying to write a GPIO interrupt code from scratch. I have done all register configurations and config is working fine as seen through SFR view in debug mode but when I run the code it seems like the interrupt is not enabled. The code never comes in the handler function.
/*
* 003button_interrupt.c
*/
#include <string.h>
#include "stm32f746xx.h"
void delay(void){
for(uint32_t i=0; i<100000; i++);
}
int main(){
GPIO_PeriClockControl(GPIOC,ENABLE);
GPIO_PeriClockControl(GPIOB,ENABLE);
GPIO_Handle_t LED, BTN;
memset(&LED, 0, sizeof(LED));
memset(&BTN, 0, sizeof(BTN));
LED.pGPIOx = GPIOB;
LED.GPIO_PinConfig.GPIO_PinNumber = GPIO_PIN_NO_14;
LED.GPIO_PinConfig.GPIO_PinMode = GPIO_MODE_OUT;
LED.GPIO_PinConfig.GPIO_PinOPType = GPIO_OP_TYPE_PP;
LED.GPIO_PinConfig.GPIO_PinSpeed = GPIO_SPEED_VERY_HIGH;
LED.GPIO_PinConfig.GPIO_PinPuPdControl = GPIO_NO_PUPD;
GPIO_Init(&LED);
LED.pGPIOx = GPIOB;
LED.GPIO_PinConfig.GPIO_PinNumber = GPIO_PIN_NO_7;
LED.GPIO_PinConfig.GPIO_PinMode = GPIO_MODE_OUT;
LED.GPIO_PinConfig.GPIO_PinOPType = GPIO_OP_TYPE_PP;
LED.GPIO_PinConfig.GPIO_PinSpeed = GPIO_SPEED_VERY_HIGH;
LED.GPIO_PinConfig.GPIO_PinPuPdControl = GPIO_NO_PUPD;
GPIO_Init(&LED);
BTN.pGPIOx = GPIOC;
BTN.GPIO_PinConfig.GPIO_PinNumber = GPIO_PIN_NO_13;
BTN.GPIO_PinConfig.GPIO_PinMode = GPIO_MODE_IT_FT;
BTN.GPIO_PinConfig.GPIO_PinSpeed = GPIO_SPEED_VERY_HIGH;
BTN.GPIO_PinConfig.GPIO_PinPuPdControl = GPIO_PIN_PU;
GPIO_Init(&BTN);
//IRQ interrupt and priority configuration
GPIO_IRQPriorityConfig(IRQ_NO_EXTI10_15,NVIC_IRQ_PRIO_15);
GPIO_IRQIntConfig(IRQ_NO_EXTI10_15,ENABLE);
while(1);
}
void EXTI15_10_IRQHandler(void){
delay();
GPIO_IRQHandling(GPIO_PIN_NO_13);
GPIO_ToggleOutputPin(GPIOB,GPIO_PIN_NO_14);
GPIO_ToggleOutputPin(GPIOB,GPIO_PIN_NO_7);
}
/*
* stm32f746xx_gpio_driver.c
*/
#include "stm32f746xx_gpio_driver.h"
/*
* peripheral clock setup
*/
void GPIO_PeriClockControl(GPIO_RegDef_t *pGPIOx, uint8_t EnOrDis){
if(EnOrDis == ENABLE){
if(pGPIOx == GPIOA){
GPIOA_PCLK_EN();
}else if(pGPIOx == GPIOB){
GPIOB_PCLK_EN();
}else if(pGPIOx == GPIOC){
GPIOC_PCLK_EN();
}else if(pGPIOx == GPIOD){
GPIOD_PCLK_EN();
}else if(pGPIOx == GPIOE){
GPIOE_PCLK_EN();
}else if(pGPIOx == GPIOF){
GPIOF_PCLK_EN();
}else if(pGPIOx == GPIOG){
GPIOG_PCLK_EN();
}else if(pGPIOx == GPIOH){
GPIOH_PCLK_EN();
}else if(pGPIOx == GPIOI){
GPIOI_PCLK_EN();
}else if(pGPIOx == GPIOJ){
GPIOJ_PCLK_EN();
}else if(pGPIOx == GPIOK){
GPIOK_PCLK_EN();
}
} else {
if(pGPIOx == GPIOA){
GPIOA_PCLK_DIS();
}else if(pGPIOx == GPIOB){
GPIOB_PCLK_DIS();
}else if(pGPIOx == GPIOC){
GPIOC_PCLK_DIS();
}else if(pGPIOx == GPIOD){
GPIOD_PCLK_DIS();
}else if(pGPIOx == GPIOE){
GPIOE_PCLK_DIS();
}else if(pGPIOx == GPIOF){
GPIOF_PCLK_DIS();
}else if(pGPIOx == GPIOG){
GPIOG_PCLK_DIS();
}else if(pGPIOx == GPIOH){
GPIOH_PCLK_DIS();
}else if(pGPIOx == GPIOI){
GPIOI_PCLK_DIS();
}else if(pGPIOx == GPIOJ){
GPIOJ_PCLK_DIS();
}else if(pGPIOx == GPIOK){
GPIOK_PCLK_DIS();
}
}
}
/*
* init and deInit
*/
void GPIO_Init(GPIO_Handle_t *pGPIOHandle){
uint32_t temp = 0;
if(pGPIOHandle->GPIO_PinConfig.GPIO_PinMode <= GPIO_MODE_ANALOG){
temp = (pGPIOHandle->GPIO_PinConfig.GPIO_PinMode << (2* pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber));
pGPIOHandle->pGPIOx->MODER &= ~(0x03 << pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber); // clearing ; always clear before setting
pGPIOHandle->pGPIOx->MODER |= temp; // setting
} else {
// 1. configure RTSR / FTSR
if(pGPIOHandle->GPIO_PinConfig.GPIO_PinMode == GPIO_MODE_IT_FT){
(*EXTI).FTSR |= (1<<pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber);
(*EXTI).RTSR &= ~(1<<pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber); // coz we only want FT, clear the corresponding RTSR bit; just to be safe if it is not already cleared for some reason
} else if(pGPIOHandle->GPIO_PinConfig.GPIO_PinMode == GPIO_MODE_IT_RT){
(*EXTI).RTSR |= (1<<pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber);
(*EXTI).FTSR &= ~(1<<pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber);
} else if(pGPIOHandle->GPIO_PinConfig.GPIO_PinMode == GPIO_MODE_IT_RFT){
(*EXTI).RTSR |= (1<<pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber);
(*EXTI).FTSR |= (1<<pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber);
}
// 2. config the gpio port selection in SYSCFG_EXTICR
uint8_t temp1 = pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber / 4;
uint8_t temp2 = pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber % 4;
uint8_t portcode = GPIO_BASEADDR_TO_CODE(pGPIOHandle->pGPIOx);
SYSCFG_PCLK_EN();
(*SYSCFG).EXTICR[temp1] = portcode << (temp2 * 4);
// 3. enable the exti interrupt delivery using IMR
(*EXTI).IMR |= (1<<pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber);
}
temp = 0;
temp = (pGPIOHandle->GPIO_PinConfig.GPIO_PinSpeed << (2* pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber));
pGPIOHandle->pGPIOx->OSPEEDR &= ~(0x03 << pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber); // clearing
pGPIOHandle->pGPIOx->OSPEEDR |= temp; // setting
temp = 0;
temp = (pGPIOHandle->GPIO_PinConfig.GPIO_PinPuPdControl << (2* pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber));
pGPIOHandle->pGPIOx->PUPDR &= ~(0x03 << pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber); // clearing
pGPIOHandle->pGPIOx->PUPDR |= temp; // setting
temp = 0;
temp = (pGPIOHandle->GPIO_PinConfig.GPIO_PinOPType << (pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber));
pGPIOHandle->pGPIOx->OTYPER &= ~(0x01 << pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber); // clearing
pGPIOHandle->pGPIOx->OTYPER |= temp; // setting
temp = 0;
if(pGPIOHandle->GPIO_PinConfig.GPIO_PinMode == GPIO_MODE_ALTFN){
uint8_t temp1 = pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber / 8;
uint8_t temp2 = pGPIOHandle->GPIO_PinConfig.GPIO_PinNumber % 8;
pGPIOHandle->pGPIOx->AFR[temp1] &= ~(0x0f << (4* temp2)); // clearing
pGPIOHandle->pGPIOx->AFR[temp1] |= pGPIOHandle->GPIO_PinConfig.GPIO_PinAltFunMode << (4* temp2); // setting
}
}
void GPIO_DeInit (GPIO_RegDef_t *pGPIOx){
if(pGPIOx == GPIOA){
GPIOA_REG_RESET();
}else if(pGPIOx == GPIOB){
GPIOB_REG_RESET();
}else if(pGPIOx == GPIOC){
GPIOC_REG_RESET();
}else if(pGPIOx == GPIOD){
GPIOD_REG_RESET();
}else if(pGPIOx == GPIOE){
GPIOE_REG_RESET();
}else if(pGPIOx == GPIOF){
GPIOF_REG_RESET();
}else if(pGPIOx == GPIOG){
GPIOG_REG_RESET();
}else if(pGPIOx == GPIOH){
GPIOH_REG_RESET();
}else if(pGPIOx == GPIOI){
GPIOI_REG_RESET();
}else if(pGPIOx == GPIOJ){
GPIOJ_REG_RESET();
}else if(pGPIOx == GPIOK){
GPIOK_REG_RESET();
}
}
/*
* data read and write
*/
uint8_t GPIO_ReadFromInputPin(GPIO_RegDef_t *pGPIOx, uint8_t PinNumber){
uint8_t value;
value = (uint8_t)((pGPIOx->IDR >> PinNumber) & 0x00000001);
return value;
}
uint16_t GPIO_ReadFromInputPort(GPIO_RegDef_t *pGPIOx){
uint16_t value;
value = pGPIOx->IDR;
return value;
}
void GPIO_WriteToOutputPin(GPIO_RegDef_t *pGPIOx, uint8_t PinNumber, uint8_t value){
if(value == GPIO_PIN_SET){
pGPIOx->ODR |= (1 << PinNumber);
} else if(value == GPIO_PIN_CLEAR || value == GPIO_PIN_RESET){
pGPIOx->ODR &= ~(1 << PinNumber);
}
}
void GPIO_WriteToOutputPort(GPIO_RegDef_t *pGPIOx, uint16_t value){
pGPIOx->ODR = value;
}
void GPIO_ToggleOutputPin(GPIO_RegDef_t *pGPIOx, uint8_t PinNumber){
pGPIOx->ODR ^= (1 << PinNumber);
}
/*
* IRQ configuration and ISR handling
*/
// IRQConfig is for config in processor side
void GPIO_IRQIntConfig(uint16_t IRQNumber, uint8_t EnOrDis){
if(EnOrDis == ENABLE){
// *(NVIC_ISER0 + (((uint32_t)(int32_t)IRQNumber) >> 5UL)) = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQNumber) & 0x1FUL));
if(IRQNumber <= 31){
(*NVIC_ISER0) |= (1<<IRQNumber);
} else if((IRQNumber > 31) && (IRQNumber <= 63)){
(*NVIC_ISER1) |= (1<<(IRQNumber%32));
} else if((IRQNumber > 63) && (IRQNumber <= 95)){
(*NVIC_ISER2) |= (1<<(IRQNumber%64));
} else if(IRQNumber > 95){
(*NVIC_ISER3) |= (1<<(IRQNumber%96));
}
} else if (EnOrDis == DISABLE){
if(IRQNumber <= 31){
(*NVIC_ICER0) |= (1<<IRQNumber);
} else if((IRQNumber > 31) && (IRQNumber <= 63)){
(*NVIC_ICER1) |= (1<<(IRQNumber%32));
} else if((IRQNumber > 63) && (IRQNumber <= 95)){
(*NVIC_ICER2) |= (1<<(IRQNumber%64));
} else if(IRQNumber > 95){
(*NVIC_ICER3) |= (1<<(IRQNumber%96));
}
}
}
void GPIO_IRQPriorityConfig(uint16_t IRQNumber, uint16_t IRQPriority){
// 1. find the ipr register and section
uint32_t iprx = IRQNumber / 4;
uint32_t iprx_section = IRQNumber % 4;
// 2. store the value
uint8_t shift_value = (8*iprx_section) + (8-NO_IPR_BITS_IMPLEMENTED); // need to move more by (8-NO_IPR_BITS_IMPLEMENTED) bits, since not all of 8 bits are used..
uint16_t temp = (IRQPriority << shift_value);
*(NVIC_IPR_BASEADDR + iprx) |= temp; // iprx is multiplied by 4 because each address jump is of 4 bytes..
}
void GPIO_IRQHandling(uint8_t PinNumber){
// clear the exti pr register bit corresponding to the pin number
if((*EXTI).PR & (1<<PinNumber)){
(*EXTI).PR |= ( 1 << PinNumber );
}
}
Please help me find the issue.
Thanks!
The code is barely readable. And it uses some really wild stuff for a beginner. Honestly, I don't think this is a good course as a starting point, it feels unnesessarily complicated for being an intro. I hate to admit it, but I also used one course to get basic general feeling of things before I figured out how to figure things out using documentation - the most important skill (and the course helped with just that; it was also a Udemy course - but hey, information is information, no matter where it comes from).
Back to the topic. It's hard to make head or tails of your code, especially if an error is in some detail. Please, indicate clearly what code you just copy-pasted from some source and what code is your own creation. If there is copied code, the problem is more likely to be in your own code, since you're probably not the first person to use that code. At first glance, the code mentions all parts there are to mention:
You set up GPIO properties.
You set up EXTI peripheral, where you select what pins you want to trigger interrupts.
You set up SYSCFG, where you tell what port that EXTI pin refers to (that pin 14 means GPIOB 14 and not GPIOC 14).
You enable NVIC
If your interrupt is not firing, then looking at SFR absolutely MUST show something. Since you already know how to operate debug mode, it must be something you overlooked there.
I have noticed you're not activating clock for SYSCFG, which binds GPIO ports to EXTI interrupt pins. You can check if SYSCFG is running using two things:
Open SFR in debug mode. If all registers of SYSCFG are 0x00, it's sus. Probably its clock is not running.
Open SFR in debug mode. Open RCC -> APB2ENR, bit SYSCFGEN must be set.
In order to set that bit, do RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; next to GPIO clock activation (or find how to set that bit with the library you have)
Developing UEFI Based application for enabling pre-boot authentication using
Feitian Auto ePass 2003 FIPS USB Token. I'm still in the initial stage of the development process.
Now I'm able to fetch Manufacturer, Product Code of the token by using UsbIo->UsbGetDeviceDescriptor protocol. But when I try to find serial number it's throwing an error.
Is there any other way to find the serial number of the USB Token? Please help me on this..
This is my sample code for finding serial number
EFI_USB_DEVICE_DESCRIPTOR DevDesc;
EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
EFI_USB_CONFIG_DESCRIPTOR ConfigDescriptor;
EFI_USB_IO_PROTOCOL *UsbIo;
EFI_STATUS Status;
EFI_HANDLE *HandleBuffer = NULL;
BOOLEAN LangFound;
UINTN HandleCount;
UINT8 EndpointNumber;
CHAR16* ManufacturerString = NULL;
CHAR16* ProductString = NULL;
CHAR16* SerialNumber = NULL;
UINT16* LangIDTable;
UINT16 TableSize;
INTN Index;
int index;
unsigned char* device_descriptor, * ccid_descriptor;
EFI_USB_DEVICE_REQUEST DevReq;
UINT32 Status_uint;
Status = gBS->LocateHandleBuffer( ByProtocol,
&gEfiUsbIoProtocolGuid,
NULL,
&HandleCount,
&HandleBuffer );
if (EFI_ERROR(Status)) {
Print(L"ERROR: LocateHandleBuffer.\n");
goto ErrorExit;
}
UINT8 usbIndex;
for (usbIndex = 0; usbIndex < HandleCount; usbIndex++) {
Status = gBS->HandleProtocol( HandleBuffer[usbIndex],
&gEfiUsbIoProtocolGuid,
(VOID**)&UsbIo );
if (EFI_ERROR(Status)) {
Print(L"ERROR: Open UsbIo.\n");
goto ErrorExit;
}
Status = UsbIo->UsbGetDeviceDescriptor( UsbIo, &DevDesc );
if (EFI_ERROR(Status)) {
Print(L"ERROR: UsbGetDeviceDescriptor.\n");
goto ErrorExit;
}
Status = UsbIo->UsbGetConfigDescriptor( UsbIo, &ConfigDescriptor );
if (EFI_ERROR (Status))
{
Print(L"UsbGetConfigDescriptor %d", Status);
goto ErrorExit;
}
Status = UsbIo->UsbGetInterfaceDescriptor( UsbIo, &InterfaceDescriptor );
if (EFI_ERROR (Status)) {
Print(L"ERROR: UsbGetInterfaceDescriptor.\n");
goto ErrorExit;
}
if (InterfaceDescriptor.InterfaceClass != CLASS_CCID) {
continue;
}
Print(L":::::::::::::::::::::: CCID ::::::::::::::::::::::\n");
//
// Get all supported languages.
//
TableSize = 0;
LangIDTable = NULL;
Status = UsbIo->UsbGetSupportedLanguages(UsbIo, &LangIDTable, &TableSize);
if (EFI_ERROR(Status)) {
Print(L"ERROR: UsbGetSupportedLanguages.\n");
return Status;
}
/* Get Manufacturer string */
for (Index = 0; Index < TableSize / sizeof(LangIDTable[0]); Index++) {
ManufacturerString = NULL;
Status = UsbIo->UsbGetStringDescriptor(UsbIo,
LangIDTable[Index],
DevDesc.StrManufacturer,
&ManufacturerString);
if (EFI_ERROR(Status) || (ManufacturerString == NULL)) {
continue;
}
Print(L"StrManufacturer ::%s\n", ManufacturerString);
FreePool(ManufacturerString);
break;
}
/* Get Product string */
for (Index = 0; Index < TableSize / sizeof(LangIDTable[0]); Index++) {
ProductString = NULL;
Status = UsbIo->UsbGetStringDescriptor(UsbIo,
LangIDTable[Index],
DevDesc.StrProduct,
&ProductString);
if (EFI_ERROR(Status) || (ProductString == NULL)) {
continue;
}
Print(L"StrProduct ::%s\n", ProductString);
FreePool(ProductString);
break;
}
/* Get Serial string */
for (Index = 0; Index < TableSize / sizeof(LangIDTable[0]); Index++) {
SerialNumber = NULL;
Status = UsbIo->UsbGetStringDescriptor(UsbIo,
LangIDTable[Index],
DevDesc.StrSerialNumber,
&SerialNumber);
if (EFI_ERROR(Status) || (SerialNumber == NULL)) {
Print(L"Error in finding SerialNumber \n");
continue;
}
Print(L"SerialNumber :: %s\n", SerialNumber);
FreePool(SerialNumber);
break;
}
Print(L"usbIndex ::%d\n", usbIndex);
Print(L"IdVendor ::%d\n", DevDesc.IdVendor);
Print(L"IdProduct ::%d\n", DevDesc.IdProduct);
}
Print(L"\n");
FreePool(HandleBuffer);
return Status;
From what I have read, the Feitian Technologies ePass2003 uses an Infineon M7893 or SLE 78CUFX5000PH (M7893-B) security chip.
As you have found out, the serial number for the ePass2003 is not stored in the USB device descriptor but in the security chip.
To obtain chip global data such as OEM information, algorithm support, FIPS mode indicator, RAM size and serial number, the GetData primitive is used. See the M7893 programming guide. if you can obtain access to it.
The driver for ePass2003 in OpenSC is called “epass2003”. The source code is currently available at https://github.com/OpenSC/OpenSC/blob/master/src/libopensc/card-epass2003.c. It has dependencies on OpenSSL and ASN.1 and some non-EDK2 headers, but these are easily worked around.
If all you are looking for is the serial number, it should be fairly easy to write a UEFI application (or driver) to get that information either by studying how the OpenSC ePass2003 driver does it (hint - look at epass2003_get_serialnr or studying the ePass2003 SDK which is available for free from Feitain and elsewhere.
The UEFI 2.5 specification released in April 2015 detailed 2 protocols relating to smart cards, i.e. Smart Card Reader and Smart Card Edge.
typedef struct _EFI_SMART_CARD_READER_PROTOCOL {
EFI_SMART_CARD_READER_CONNECT SCardConnect;
EFI_SMART_CARD_READER_DISCONNECT SCardDisconnect;
EFI_SMART_CARD_READER_STATUS SCardStatus;
EFI_SMART_CARD_READER_TRANSMIT SCardTransmit;
EFI_SMART_CARD_READER_CONTROL SCardControl;
EFI_SMART_CARD_READER_GET_ATTRIB SCardGetAttrib;
} EFI_SMART_CARD_READER_PROTOCOL;
typedef struct _EFI_SMART_CARD_EDGE_PROTOCOL {
EFI_SMART_CARD_EDGE_GET_CONTEXT GetContext;
EFI_SMART_CARD_EDGE_CONNECT Connect;
EFI_SMART_CARD_EDGE_DISCONNECT Disconnect;
EFI_SMART_CARD_EDGE_GET_CSN GetCsn;
EFI_SMART_CARD_EDGE_GET_READER_NAME GetReaderName;
EFI_SMART_CARD_EDGE_VERIFY_PIN VerifyPin;
EFI_SMART_CARD_EDGE_GET_PIN_REMAINING GetPinRemaining;
EFI_SMART_CARD_EDGE_GET_DATA GetData;
EFI_SMART_CARD_EDGE_GET_CREDENTIAL GetCredential;
EFI_SMART_CARD_EDGE_SIGN_DATA SignData;
EFI_SMART_CARD_EDGE_DECRYPT_DATA DecryptData;
EFI_SMART_CARD_EDGE_BUILD_DH_AGREEMENT BuildDHAgreement;
} EFI_SMART_CARD_EDGE_PROTOCOL;
EDK2 does not contain a sample implementation at present. However, you may be interested in the GPL2-licensed sample implementation by Ludovic Rousseau which is available at https://github.com/LudovicRousseau/edk2/tree/SmartCard. The implementation code, which is circa 5 years old and which I have not tested, is at MdeModulePkg/Library/SmartCardReader. Read his blog (https://ludovicrousseau.blogspot.com/) also as he provides useful sample applications also.
I have absolutely no experience in programming serial communication and since I'm stuck with my code I'd really appreciate your help! Thank you already!
So now to my problem:
I got a generator on which are several different sensors who communicate over CAN with a microcontroller. This mc itself communicates with a device from USBTin again over CAN. On the USBTin, a little board, is mainly a CAN controller and a microcontroller which are precoded from its developer.
So my task now is to open my COM Port, send the right messages to the USBTin (those are "S5" for the baudrate and 'O' for Open CAN) and then receive the data.
First of all the functions and my problem:
The problem is that in my output textfield stands something like "PPPPPPPPPP,Râö". There are always these 10 P's and some random characters. I have no idea where the P's or these additional "Râö" comes from. The actual output string shoud be something like "T1E18001F8". I tested that with hTerm, which is a terminal programm for serial communication.
OPEN:
long Serial::Open()
{
if (IsOpened()) return 0;
#ifdef UNICODE
wstring wtext(port.begin(),port.end());
#else
string wtext = port;
#endif
hComm = CreateFile(wtext.c_str(),
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
0);
if (hComm == INVALID_HANDLE_VALUE) {return 1;}
if (PurgeComm(hComm, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR |
PURGE_RXCLEAR) == 0) {return 2;}//purge
//get initial state
DCB dcbOri;
bool fSuccess;
fSuccess = GetCommState(hComm, &dcbOri);
if (!fSuccess) {return 3;}
DCB dcb1 = dcbOri;
dcb1.BaudRate = baud;
if (parity == 'E') dcb1.Parity = EVENPARITY;
else if (parity == 'O') dcb1.Parity = ODDPARITY;
else if (parity == 'M') dcb1.Parity = MARKPARITY;
else if (parity == 'S') dcb1.Parity = SPACEPARITY;
else if (parity == 'N') dcb1.Parity = NOPARITY;
dcb1.ByteSize = (BYTE)dsize;
if(stopbits==2) dcb1.StopBits = TWOSTOPBITS;
else if (stopbits == 1.5) dcb1.StopBits = ONE5STOPBITS;
else if (stopbits == 1) dcb1.StopBits = ONE5STOPBITS;
dcb1.fOutxCtsFlow = false;
dcb1.fOutxDsrFlow = false;
dcb1.fOutX = false;
dcb1.fDtrControl = DTR_CONTROL_DISABLE;
dcb1.fRtsControl = RTS_CONTROL_DISABLE;
fSuccess = SetCommState(hComm, &dcb1);
delay(60);
if (!fSuccess) {return 4;}
fSuccess = GetCommState(hComm, &dcb1);
if (!fSuccess) {return 5;}
osReader = { 0 };// Create the overlapped event. Must be closed before
exiting to avoid a handle leak.
osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (osReader.hEvent == NULL) {return 6;}// Error creating overlapped event;
abort.
fWaitingOnRead = FALSE;
osWrite = { 0 };
osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (osWrite.hEvent == NULL) {return 7;}
if (!GetCommTimeouts(hComm, &timeouts_ori)) { return 8; } // Error getting
time-outs.
COMMTIMEOUTS timeouts;
timeouts.ReadIntervalTimeout = 20;
timeouts.ReadTotalTimeoutMultiplier = 15;
timeouts.ReadTotalTimeoutConstant = 100;
timeouts.WriteTotalTimeoutMultiplier = 15;
timeouts.WriteTotalTimeoutConstant = 100;
if (!SetCommTimeouts(hComm, &timeouts)) { return 9;} // Error setting time-
outs.
return 0;
}
WRITE:
bool Serial::Write(char *data)
{
if (!IsOpened()) {
return false;
}
BOOL fRes;
DWORD dwWritten;
long n = strlen(data);
if (n < 0) n = 0;
else if(n > 1024) n = 1024;
// Issue write.
if (!WriteFile(hComm, data, n, &dwWritten, &osWrite)) {
if (GetLastError() != ERROR_IO_PENDING) {fRes = FALSE;}// WriteFile
failed, but it isn't delayed. Report error and abort.
else {// Write is pending.
if (!GetOverlappedResult(hComm, &osWrite, &dwWritten, TRUE))
fRes = FALSE;
else fRes = TRUE;// Write operation completed successfully.
}
}
else fRes = TRUE;// WriteFile completed immediately.
return fRes;
}
READCHAR:
char Serial::ReadChar(bool& success)
{
success = false;
if (!IsOpened()) {return 0;}
DWORD dwRead;
DWORD length=1;
BYTE* data = (BYTE*)(&rxchar);
//the creation of the overlapped read operation
if (!fWaitingOnRead) {
// Issue read operation.
if (!ReadFile(hComm, data, length, &dwRead, &osReader)) {
if (GetLastError() != ERROR_IO_PENDING) { /*Error*/}
else { fWaitingOnRead = TRUE; /*Waiting*/}
}
else {if(dwRead==length) success = true;}//success
}
//detection of the completion of an overlapped read operation
DWORD dwRes;
if (fWaitingOnRead) {
dwRes = WaitForSingleObject(osReader.hEvent, READ_TIMEOUT);
switch (dwRes)
{
// Read completed.
case WAIT_OBJECT_0:
if (!GetOverlappedResult(hComm, &osReader, &dwRead, FALSE))
{/*Error*/ }
else {
if (dwRead == length) success = true;
fWaitingOnRead = FALSE;// Reset flag so that another
opertion
can be issued.
}// Read completed successfully.
break;
case WAIT_TIMEOUT:
// Operation isn't complete yet.
break;
default:
// Error in the WaitForSingleObject;
break;
}
}
return rxchar;
}
And Finally the excerpt of the main in wxWidgets to display the received data:
void GUI_1_2Frame::OnConnectButtonClick(wxCommandEvent& (event))
{
char tempString[10] = {0};
bool ReadChar_success = true;
char temp_Char;
/* Preset Serial Port setting */
Serial com(com_x, 115200, 8, NOPARITY, 1);
char* buffer;
if(connection_flag)
{
/* Port was connected, Disconnect Button unsed*/
com.Close();
wxMessageBox(_("Port closed"),_("Info!"),wxICON_INFORMATION);
connection_flag = 0;
ConnectButton->SetLabel("Connect");
TextCtrl1->SetValue("");
}
else
{
/* If open() == true -> INVALID HANDLE */
if(com.Open())
{
wxMessageBox(_("Port not available"),_("ERROR!"),wxICON_ERROR);
}
else /* Port Opened */
{
TextCtrl1->SetValue(com.GetPort());
ConnectButton->SetLabel("Disconnect");
connection_flag = 1;
}
if(com.Write("S5"))
{
TextCtrl1->SetValue("Baudrate sent!\n");
delay(100);
if(com.WriteChar('O'))
{
TextCtrl1->SetValue("Baudrate & Open Command sent!");
int i =0;
while(i<10)
{
temp_Char = com.ReadChar(ReadChar_success);
tempString[i] = temp_Char;
i++;
}
com.WriteChar('C');
com.Close();
//com.readSerialPort(data, MAX_DATA_LENGTH);
TextCtrl2->SetValue(tempString);
//wxMessageOutput::Get()->Printf("%s", tempString);
}
else
{
TextCtrl1->SetValue("Open Command Error!"); }
}
else
{
TextCtrl1->SetValue("Error!");
}
}
}
Since I am not native speaking englisch I say sorry for my language mistakes.
Thank everybody a lot and again I really appreciate every single hint!
Greetings,
MSol
I've recently purchased this: http://redbearlab.com/bleshield/
I've connected it to my Arduino and I'm trying to run the very first test program that they tell me to run which is the BLE Controller sketch. I've connected it and resolved some original compile errors that I initially got, and now it will upload. When I upload it, my iPhone is unresponsive to the shield. I'm trying to figure out if the problem is in the code or if it's a problem with the shield itself. If it's the code, how could I fix the code? I'm relatively new to Arduino and completely new to making it work with Bluetooth. Here's the entire sketch that the guide told me to download from Github.
BLEControllerSketch.ino
/*
Copyright (c) 2012, 2013 RedBearLab
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <Servo.h>
#include <SPI.h>
#include <EEPROM.h>
#include <boards.h>
#include <RBL_nRF8001.h>
#include "Boards.h"
#define PROTOCOL_MAJOR_VERSION 0 //
#define PROTOCOL_MINOR_VERSION 0 //
#define PROTOCOL_BUGFIX_VERSION 2 // bugfix
#define PIN_CAPABILITY_NONE 0x00
#define PIN_CAPABILITY_DIGITAL 0x01
#define PIN_CAPABILITY_ANALOG 0x02
#define PIN_CAPABILITY_PWM 0x04
#define PIN_CAPABILITY_SERVO 0x08
#define PIN_CAPABILITY_I2C 0x10
// pin modes
//#define INPUT 0x00 // defined in wiring.h
//#define OUTPUT 0x01 // defined in wiring.h
#define ANALOG 0x02 // analog pin in analogInput mode
#define PWM 0x03 // digital pin in PWM output mode
#define SERVO 0x04 // digital pin in Servo output mode
byte pin_mode[TOTAL_PINS];
byte pin_state[TOTAL_PINS];
byte pin_pwm[TOTAL_PINS];
byte pin_servo[TOTAL_PINS];
Servo servos[MAX_SERVOS];
void setup()
{
Serial.begin(57600);
Serial.println("BLE Arduino Slave");
/* Default all to digital input */
for (int pin = 0; pin < TOTAL_PINS; pin++)
{
// Set pin to input with internal pull up
pinMode(pin, INPUT);
digitalWrite(pin, HIGH);
// Save pin mode and state
pin_mode[pin] = INPUT;
pin_state[pin] = LOW;
}
// Default pins set to 9 and 8 for REQN and RDYN
// Set your REQN and RDYN here before ble_begin() if you need
//ble_set_pins(3, 2);
// Set your BLE Shield name here, max. length 10
//ble_set_name("My Name");
// Init. and start BLE library.
ble_begin();
}
static byte buf_len = 0;
void ble_write_string(byte *bytes, uint8_t len)
{
if (buf_len + len > 20)
{
for (int j = 0; j < 15000; j++)
ble_do_events();
buf_len = 0;
}
for (int j = 0; j < len; j++)
{
ble_write(bytes[j]);
buf_len++;
}
if (buf_len == 20)
{
for (int j = 0; j < 15000; j++)
ble_do_events();
buf_len = 0;
}
}
byte reportDigitalInput()
{
if (!ble_connected())
return 0;
static byte pin = 0;
byte report = 0;
if (!IS_PIN_DIGITAL(pin))
{
pin++;
if (pin >= TOTAL_PINS)
pin = 0;
return 0;
}
if (pin_mode[pin] == INPUT)
{
byte current_state = digitalRead(pin);
if (pin_state[pin] != current_state)
{
pin_state[pin] = current_state;
byte buf[] = {'G', pin, INPUT, current_state};
ble_write_string(buf, 4);
report = 1;
}
}
pin++;
if (pin >= TOTAL_PINS)
pin = 0;
return report;
}
void reportPinCapability(byte pin)
{
byte buf[] = {'P', pin, 0x00};
byte pin_cap = 0;
if (IS_PIN_DIGITAL(pin))
pin_cap |= PIN_CAPABILITY_DIGITAL;
if (IS_PIN_ANALOG(pin))
pin_cap |= PIN_CAPABILITY_ANALOG;
if (IS_PIN_PWM(pin))
pin_cap |= PIN_CAPABILITY_PWM;
if (IS_PIN_SERVO(pin))
pin_cap |= PIN_CAPABILITY_SERVO;
buf[2] = pin_cap;
ble_write_string(buf, 3);
}
void reportPinServoData(byte pin)
{
// if (IS_PIN_SERVO(pin))
// servos[PIN_TO_SERVO(pin)].write(value);
// pin_servo[pin] = value;
byte value = pin_servo[pin];
byte mode = pin_mode[pin];
byte buf[] = {'G', pin, mode, value};
ble_write_string(buf, 4);
}
byte reportPinAnalogData()
{
if (!ble_connected())
return 0;
static byte pin = 0;
byte report = 0;
if (!IS_PIN_DIGITAL(pin))
{
pin++;
if (pin >= TOTAL_PINS)
pin = 0;
return 0;
}
if (pin_mode[pin] == ANALOG)
{
uint16_t value = analogRead(pin);
byte value_lo = value;
byte value_hi = value>>8;
byte mode = pin_mode[pin];
mode = (value_hi << 4) | mode;
byte buf[] = {'G', pin, mode, value_lo};
ble_write_string(buf, 4);
}
pin++;
if (pin >= TOTAL_PINS)
pin = 0;
return report;
}
void reportPinDigitalData(byte pin)
{
byte state = digitalRead(pin);
byte mode = pin_mode[pin];
byte buf[] = {'G', pin, mode, state};
ble_write_string(buf, 4);
}
void reportPinPWMData(byte pin)
{
byte value = pin_pwm[pin];
byte mode = pin_mode[pin];
byte buf[] = {'G', pin, mode, value};
ble_write_string(buf, 4);
}
void sendCustomData(uint8_t *buf, uint8_t len)
{
uint8_t data[20] = "Z";
memcpy(&data[1], buf, len);
ble_write_string(data, len+1);
}
byte queryDone = false;
void loop()
{
while(ble_available())
{
byte cmd;
cmd = ble_read();
Serial.write(cmd);
// Parse data here
switch (cmd)
{
case 'V': // query protocol version
{
byte buf[] = {'V', 0x00, 0x00, 0x01};
ble_write_string(buf, 4);
}
break;
case 'C': // query board total pin count
{
byte buf[2];
buf[0] = 'C';
buf[1] = TOTAL_PINS;
ble_write_string(buf, 2);
}
break;
case 'M': // query pin mode
{
byte pin = ble_read();
byte buf[] = {'M', pin, pin_mode[pin]}; // report pin mode
ble_write_string(buf, 3);
}
break;
case 'S': // set pin mode
{
byte pin = ble_read();
byte mode = ble_read();
if (IS_PIN_SERVO(pin) && mode != SERVO && servos[PIN_TO_SERVO(pin)].attached())
servos[PIN_TO_SERVO(pin)].detach();
/* ToDo: check the mode is in its capability or not */
/* assume always ok */
if (mode != pin_mode[pin])
{
pinMode(pin, mode);
pin_mode[pin] = mode;
if (mode == OUTPUT)
{
digitalWrite(pin, LOW);
pin_state[pin] = LOW;
}
else if (mode == INPUT)
{
digitalWrite(pin, HIGH);
pin_state[pin] = HIGH;
}
else if (mode == ANALOG)
{
if (IS_PIN_ANALOG(pin)) {
if (IS_PIN_DIGITAL(pin)) {
pinMode(PIN_TO_DIGITAL(pin), LOW);
}
}
}
else if (mode == PWM)
{
if (IS_PIN_PWM(pin))
{
pinMode(PIN_TO_PWM(pin), OUTPUT);
analogWrite(PIN_TO_PWM(pin), 0);
pin_pwm[pin] = 0;
pin_mode[pin] = PWM;
}
}
else if (mode == SERVO)
{
if (IS_PIN_SERVO(pin))
{
pin_servo[pin] = 0;
pin_mode[pin] = SERVO;
if (!servos[PIN_TO_SERVO(pin)].attached())
servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin));
}
}
}
// if (mode == ANALOG)
// reportPinAnalogData(pin);
if ( (mode == INPUT) || (mode == OUTPUT) )
reportPinDigitalData(pin);
else if (mode == PWM)
reportPinPWMData(pin);
else if (mode == SERVO)
reportPinServoData(pin);
}
break;
case 'G': // query pin data
{
byte pin = ble_read();
reportPinDigitalData(pin);
}
break;
case 'T': // set pin digital state
{
byte pin = ble_read();
byte state = ble_read();
digitalWrite(pin, state);
reportPinDigitalData(pin);
}
break;
case 'N': // set PWM
{
byte pin = ble_read();
byte value = ble_read();
analogWrite(PIN_TO_PWM(pin), value);
pin_pwm[pin] = value;
reportPinPWMData(pin);
}
break;
case 'O': // set Servo
{
byte pin = ble_read();
byte value = ble_read();
if (IS_PIN_SERVO(pin))
servos[PIN_TO_SERVO(pin)].write(value);
pin_servo[pin] = value;
reportPinServoData(pin);
}
break;
case 'A': // query all pin status
for (int pin = 0; pin < TOTAL_PINS; pin++)
{
reportPinCapability(pin);
if ( (pin_mode[pin] == INPUT) || (pin_mode[pin] == OUTPUT) )
reportPinDigitalData(pin);
else if (pin_mode[pin] == PWM)
reportPinPWMData(pin);
else if (pin_mode[pin] == SERVO)
reportPinServoData(pin);
}
queryDone = true;
{
uint8_t str[] = "ABC";
sendCustomData(str, 3);
}
break;
case 'P': // query pin capability
{
byte pin = ble_read();
reportPinCapability(pin);
}
break;
case 'Z':
{
byte len = ble_read();
byte buf[len];
for (int i=0;i<len;i++)
buf[i] = ble_read();
Serial.println("->");
Serial.print("Received: ");
Serial.print(len);
Serial.println(" byte(s)");
Serial.print(" Hex: ");
for (int i=0;i<len;i++)
Serial.print(buf[i], HEX);
Serial.println();
}
}
// send out any outstanding data
ble_do_events();
buf_len = 0;
return; // only do this task in this loop
}
// process text data
if (Serial.available())
{
byte d = 'Z';
ble_write(d);
delay(5);
while(Serial.available())
{
d = Serial.read();
ble_write(d);
}
ble_do_events();
buf_len = 0;
return;
}
// No input data, no commands, process analog data
if (!ble_connected())
queryDone = false; // reset query state
if (queryDone) // only report data after the query state
{
byte input_data_pending = reportDigitalInput();
if (input_data_pending)
{
ble_do_events();
buf_len = 0;
return; // only do this task in this loop
}
reportPinAnalogData();
ble_do_events();
buf_len = 0;
return;
}
ble_do_events();
buf_len = 0;
}
Any and all help is greatly appreciated.
I've been working with these quite a bit in the last 8 months, so I'll do what I can to help. I don't have the reputation to comment and ask for clarification on specific things, so I'm just gonna try to cover everything I can.
Let's first lay out a few things:
Because your sketch uploaded I'm assuming that you have added all of the necessary libraries to Arduino. If you haven't, I don't know why it is uploading, but be sure to do that.
The problem almost certainly won't be with the Arduino code. I ran the code you provided, as well as the sketch provided by RBL (Red Bear Lab) that is on my computer. I was able to connect to my iPhone using both sketches.
I'm going to lay out everything I think could potentially be the source of the problem:
Make sure that all of your header pins (you should have a bunch of headers sticking out of the board in rows of 3 next to the digital pins) are connected correctly, as RBL shows in their instructions. If you want me to provide a picture of mine I can do that.
Make sure that the white power light is on on your shield. If it isn't, power isn't getting to the shield itself.
Be sure that you actually have bluetooth enabled on your phone.
You didn't mention that you downloaded the app. Be sure to do that (it is called "BLE Controller" by RedBear), as you cannot connect to the iPhone without the app (Apple's bluetooth menu will not show the BLE shield).
If you have downloaded the app, be sure that you have selected the correct setting from the choices using the button on the top left of the screen (3 lines on top of each other). For the sketch you provided, you should select BLE Controller.
If you have tried everything and nothing else is working, try one of the other sketches provided by RBL, such as SimpleChat. This uses the serial monitor on Arduino to communicate back and forth with the iPhone. If this doesn't work, upload a picture of your specific shield (the top of it) so I can take a look at it. Best of luck.
When using zlib 1.25 in an iOS project, I've noticed in my profiler (Instruments) that the function zError is being called repeatedly, and is occupying 50% of the overall inflate time.
Does anyone know why zError would be getting invoked like this? I don't call it anywhere in my own code, which is a pretty boilerplate inflate function, pasted below:
int UPNExtractorGZInflate(const void *src, int srcLen, void *dst, int dstLen) {
z_stream strm = {0};
strm.total_in = strm.avail_in = srcLen;
strm.total_out = strm.avail_out = dstLen;
strm.next_in = (Bytef *) src;
strm.next_out = (Bytef *) dst;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
int err = -1;
int ret = -1;
err = inflateInit2(&strm, (15 + 16)); //15 window bits, and the +16 tells zlib to decode gzip
if (err == Z_OK) {
err = inflate(&strm, Z_FINISH);
if (err == Z_STREAM_END) {
ret = strm.total_out;
}
else {
inflateEnd(&strm);
return err;
}
}
else {
inflateEnd(&strm);
return err;
}
inflateEnd(&strm);
return ret;
}
And here is the relevant profiler output (notice zError taking 50% of the overall inflate time):
zError isn't called by any zlib function. If you're not calling it, then your profiler is misidentifying the function taking that time.