I am trying to use FT4232 ports for SPI communication.
For this, I am using the ADBUS for SPI using the usual SPI configuration (AD0 -> SCK, AD1 -> MOSI, AD2 -> MISO, AD3 -> CS).
Now I have to use SPI available in BDBUS. As I understand, the FT4232 allows SPI in BDBUS. So far, I am stuck about using BDBUS.
The code using ADBUS is as follow
/********* SPI INIT AND CONFIG **********/
void SPI_Init()
{
Console.WriteLine("Scanning Device");
ftStatus = SPI_Device.GetNumberOfDevices(ref ftdiDeviceCount);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
Console.WriteLine("ftStatus NOT OK");
}
Console.WriteLine("Number of device = " + ftdiDeviceCount);
if (ftdiDeviceCount == 0)
{
return;
}
FTDI.FT_DEVICE_INFO_NODE[] ftdiDeviceList = new FTDI.FT_DEVICE_INFO_NODE[ftdiDeviceCount];
ftStatus = SPI_Device.GetDeviceList(ftdiDeviceList);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
return;
string serialnumber = "FTKI02A";
ftStatus = SPI_Device.OpenBySerialNumber(serialnumber);
Console.WriteLine("FTKI02B open status: {0}", ftStatus);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
{
Console.WriteLine(serialnumber + " port open failed");
}
ftStatus = SPI_Config();
Console.WriteLine("\nConfig status: {0}", ftStatus);
if (ftStatus == FTDI.FT_STATUS.FT_OK)
spi_initialized = true;
}
FTDI.FT_STATUS SPI_Config()
{
FTDI.FT_STATUS stat = FTDI.FT_STATUS.FT_OK;
stat = SPI_Device.ResetDevice();
//Purge USB receive buffer first by reading out all old data from FT2232H receive buffer
//stat |= SPI_Device.Purge(FTDI.FT_PURGE.FT_PURGE_RX);
stat |= SPI_Device.GetRxBytesAvailable(ref numBytesRead);
Console.WriteLine("Input buffer size: {0}", numBytesRead);
if (stat == FTDI.FT_STATUS.FT_OK && numBytesRead > 0)
{
numBytesToRead = numBytesRead;
stat |= SPI_Device.Read(inputBuffer, numBytesToRead, ref numBytesRead);
}
stat |= SPI_Device.SetCharacters(0, false, 0, false);
stat |= SPI_Device.SetTimeouts(5000, 5000);
stat |= SPI_Device.SetLatency(16);
//stat |= SPI_Device.SetFlowControl(FTDI.FT_FLOW_CONTROL.FT_FLOW_RTS_CTS, 0x00, 0x00); // This is not done in SPI pdf
stat |= SPI_Device.SetBitMode(0x00, 0x00);
stat |= SPI_Device.SetBitMode(0x00, 0x02); // MPSSE mode
if (stat != FTDI.FT_STATUS.FT_OK)
{
Console.WriteLine("Failed to initialize SPI");
return stat;
}
Delay(50);
// SYNCHRONIZATION WITH BAD COMMAND IS OMITTED HERE
uint dwClockDivisor = 29;
// Configure MPSSE for SPI communication with EEPROM
numBytesToSend = numBytesSent = 0;
outputBuffer[numBytesToSend++] = 0x8A; // disable clock divide by 5 for 60MHz master clock
outputBuffer[numBytesToSend++] = 0x97; // turn off adaptive clocking
outputBuffer[numBytesToSend++] = 0x8D; // 3 phase data clock disable
outputBuffer[numBytesToSend++] = 0x80; // Command to set directions of lower 8 pins and force value on bits set as output on ADBUS
outputBuffer[numBytesToSend++] = 0x00; // Initial state = 0
outputBuffer[numBytesToSend++] = 0x0B; // Set SCK,DO,CS -> output, DI-> input
// The SK clock frequency can be worked out by below algorithm with divide by 5 set as off
// SK frequency = 60MHz /((1 + [(1 + 0xValueH*256) OR 0xValueL])*2)
outputBuffer[numBytesToSend++] = 0x86; // command to set clock divisor
outputBuffer[numBytesToSend++] = (byte) (dwClockDivisor & 0xFF); //Set 0xValue L of clock divisor
outputBuffer[numBytesToSend++] = (byte) (dwClockDivisor >> 8); // Set 0xValue H of clock divisor
stat |= SPI_Device.Write(outputBuffer, numBytesToSend, ref numBytesSent);
Delay(20);
// Turn Off loop back in case
numBytesToSend = 0;
outputBuffer[numBytesToSend++] = 0x85;
stat |= SPI_Device.Write(outputBuffer, numBytesToSend, ref numBytesSent);
if (stat == FTDI.FT_STATUS.FT_OK)
Console.WriteLine("\nSPI INITIALIZATION SUCCESSFUL.");
return stat;
}
/********* SEND DATA **********/
void WREN_Command()
{
// This command writes WREN command
numBytesToSend = numBytesSent = 0;
// Chip select enable
outputBuffer[numBytesToSend++] = 0x80; // GPIO command ADBUS
outputBuffer[numBytesToSend++] = 0x00; // set values -> CS High, MOSI and SCL low
outputBuffer[numBytesToSend++] = 0x0B; // set directions -> bit3: CS, bit2: MISO, bit1: MOSI, bit0: SCK
outputBuffer[numBytesToSend++] = MSB_FALLING_EDGE_CLOCK_BIT_OUT;
outputBuffer[numBytesToSend++] = 7;
outputBuffer[numBytesToSend++] = FLASH_CMD_WREN; // Write WREN command to SPI FLASH
//SPI_CS_Disable
outputBuffer[numBytesToSend++] = 0x80; // GPIO command ADBUS
outputBuffer[numBytesToSend++] = 0x08; // set values -> CS, MOSI and SCL low
outputBuffer[numBytesToSend++] = 0x0B; // set directions -> bit3: CS, bit2: MISO, bit1: MOSI, bit0: SCK
ftStatus = SPI_Device.Write(outputBuffer, numBytesToSend, ref numBytesSent);
}
Which command do we send to use BDBUS, first I modified
string serialnumber = "FTKI02B"; // "FTKI02A";
ftStatus = SPI_Device.OpenBySerialNumber(serialnumber);
To send and receive data through BDBUS which in the following line ?
// Chip select enable
outputBuffer[numBytesToSend++] = 0x80; // GPIO command ADBUS
Related
I am looking for a little help.
I have a program to communicate with a controller through Modbus TCP.
The only problem is I cannot extend the Nop from 125 to 400 because I got Illegal Data Address error message.
Could you please help me with this?
try
{
byte slaveid = 1;
byte function = 4;
ushort id = function;
ushort startAddress = 0;
uint NoP = 125;
byte[] frame = ReadInputRegistersMsg(id, slaveid, startAddress, function, NoP);
this.Write(frame); //data send to controller
Thread.Sleep(100);
byte[] buffReceiver = this.Read(); //data recieving from controller
int SizeByte = buffReceiver[8]; // Data what I got from the controller
UInt16[] temp = null;
if (function != buffReceiver[7])
{
byte[] byteMsg = new byte[9];
Array.Copy(buffReceiver, 0, byteMsg, 0, byteMsg.Length);
byte[] data = new byte[SizeByte];
textBox2.Text = Display(byteMsg);
byte[] errorbytes = new byte[3];
Array.Copy(buffReceiver, 6, errorbytes, 0, errorbytes.Length);
this.CheckValidate(errorbytes); // check the answer -> error message
}
else
{
byte[] byteMsg = new byte[9 + SizeByte];
Array.Copy(buffReceiver, 0, byteMsg, 0, byteMsg.Length);
byte[] data = new byte[SizeByte];
textBox2.Text = Display(byteMsg); // Show received messages in windows form app
Array.Copy(buffReceiver, 9, data, 0, data.Length);
temp = Word.ConvertByteArrayToWordArray(data); // Convert Byte[]-> Word[]
}
// Result
if (temp == null) return;
string result = string.Empty;
//foreach (var item in temp) // show all the data
for(int i=0;i<100;i++) // show the first 100 data
{
//result += string.Format("{0} ", item);
result += temp[i];
}
textBox3.Text = result; // insert the result into the textbox (windows form app)
}
catch
{
}
The ReadInputRegister Message is the following:
private byte[] ReadInputRegistersMsg(ushort id, byte slaveAddress, ushort startAddress, byte function, uint NoP)
{
byte[] frame = new byte[12];
frame[0] = (byte)(id >> 8); // Transaction Identifier High
frame[1] = (byte)id; // Transaction Identifier Low
frame[2] = 0; // Protocol Identifier High
frame[3] = 0; // Protocol Identifier Low
frame[4] = 0; // Message Length High
frame[5] = 6; // Message Length Low(6 bytes to follow)
frame[6] = slaveAddress; // Slave address(Unit Identifier)
frame[7] = function; // Function
frame[8] = (byte)(startAddress >> 8); // Starting Address High
frame[9] = (byte)startAddress; // Starting Address Low
frame[10] = (byte)(NoP >> 8); // Quantity of Registers High
frame[11] = (byte)NoP; // Quantity of Registers Low
return frame;
}
The hard limit for modbus is 125 NoP
I've a NFC reader along with MIFARE Classic 1K card. I've a Visual C# winforms project. Right now I'm able to connect to the reader and detect the card and get it's UUID. The problem I'm facing is while writing and reading data. I searched a lot on internet, found some solution even tested the demo code provided with the SDK... nothing's working.
Let me describe the workflow and code I'm using for writing, authenticating a block, sending APDU and reading the block.
Following is the code for writing data to block 5.
String tmpStr = Text;
int indx;
if (authenticateBlock(Block))
{
ClearBuffers();
SendBuff[0] = 0xFF; // CLA
SendBuff[1] = 0xD6; // INS
SendBuff[2] = 0x00; // P1
SendBuff[3] = (byte)int.Parse(Block); // P2 : Starting Block No.
SendBuff[4] = (byte)int.Parse("16"); // P3 : Data length
SendBuff[5] = 0xFF;
SendBuff[6] = 0xFF;
SendBuff[7] = 0xFF;
SendBuff[8] = 0xFF;
SendBuff[9] = 0xFF;
SendBuff[10] = 0xFF;
for (indx = 0; indx <= (tmpStr).Length - 1; indx++)
{
SendBuff[indx + 5] = (byte)tmpStr[indx];
}
SendLen = SendBuff[4] + 5;
RecvLen = 0x02;
retCode = SendAPDUandDisplay(2);
if (retCode != Card.SCARD_S_SUCCESS)
{
MessageBox.Show("fail write");
}
else
{
MessageBox.Show("write success");
}
}
else
{
MessageBox.Show("FailAuthentication");
}
CloseCardConnection();
The function SendAPDUandDisplay is as below
private int SendAPDUandDisplay(int reqType)
{
int indx;
string tmpStr = "";
pioSendRequest.dwProtocol = Aprotocol;
pioSendRequest.cbPciLength = 8;
//Display Apdu In
for (indx = 0; indx <= SendLen - 1; indx++)
{
tmpStr = tmpStr + " " + string.Format("{0:X2}", SendBuff[indx]);
}
retCode = Card.SCardTransmit(hCard, ref pioSendRequest, ref SendBuff[0],
SendLen, ref pioSendRequest, ref RecvBuff[0], ref RecvLen);
if (retCode != Card.SCARD_S_SUCCESS)
{
return retCode;
}
else
{
try
{
tmpStr = "";
switch (reqType)
{
case 0:
for (indx = (RecvLen - 2); indx <= (RecvLen - 1); indx++)
{
tmpStr = tmpStr + " " + string.Format("{0:X2}", RecvBuff[indx]);
}
if ((tmpStr).Trim() != "90 00")
{
//MessageBox.Show("Return bytes are not acceptable.");
return -202;
}
break;
case 1:
for (indx = (RecvLen - 2); indx <= (RecvLen - 1); indx++)
{
tmpStr = tmpStr + string.Format("{0:X2}", RecvBuff[indx]);
}
if (tmpStr.Trim() != "90 00")
{
tmpStr = tmpStr + " " + string.Format("{0:X2}", RecvBuff[indx]);
}
else
{
tmpStr = "ATR : ";
for (indx = 0; indx <= (RecvLen - 3); indx++)
{
tmpStr = tmpStr + " " + string.Format("{0:X2}", RecvBuff[indx]);
}
}
break;
case 2:
for (indx = 0; indx <= (RecvLen - 1); indx++)
{
tmpStr = tmpStr + " " + string.Format("{0:X2}", RecvBuff[indx]);
}
break;
}
}
catch (IndexOutOfRangeException)
{
return -200;
}
}
return retCode;
}
Function authenticateBlock is as following
private bool authenticateBlock(String block)
{
ClearBuffers();
/*SendBuff[0] = 0xFF; // CLA
SendBuff[2] = 0x00; // P1: same for all source types
SendBuff[1] = 0x82; // INS: for stored key input
SendBuff[3] = 0x00; // P2 : Memory location; P2: for stored key input
SendBuff[4] = 0x05; // P3: for stored key input
SendBuff[5] = 0x01; // Byte 1: version number
SendBuff[6] = 0x00; // Byte 2
SendBuff[7] = (byte)int.Parse(block); // Byte 3: sectore no. for stored key input
SendBuff[8] = 0x60; // Byte 4 : Key A for stored key input
SendBuff[9] = (byte)int.Parse("1"); // Byte 5 : Session key for non-volatile memory
*/
SendBuff[0] = 0xD4;
SendBuff[1] = 0x4A;
SendBuff[2] = 0x01;
SendBuff[3] = 0x00;
SendBuff[4] = (byte) int.Parse(block);
SendBuff[5] = 0xFF;
SendBuff[6] = 0xFF;
SendBuff[7] = 0xFF;
SendBuff[8] = 0xFF;
SendBuff[9] = 0xFF;
SendBuff[10] = 0xFF;
/*SendLen = 0x0A;
RecvLen = 0x02;*/
SendLen = 4;
RecvLen = 255;
retCode = SendAPDUandDisplay(2);
if (retCode != Card.SCARD_S_SUCCESS)
{
//MessageBox.Show("FAIL Authentication!");
return false;
}
return true;
}
One strange thing to notice here is that whatever values I set in sendBuff this function always returns true value and the write data code "The very first code block" returns write success message
But after executing the write data code when I read that very block "5" in my case, there is nothing present there. My read block code returns an empty string and when I try to double check if data was written and my faulty code couldn't read I use an external software to verify that was the value added or not, that software also does not show the data that I wrote and got that write success message.
Ok following is the code I'm using to read block 5.
public string readBlock(String Block)
{
string tmpStr = "";
int indx;
if (authenticateBlock(Block))
{
ClearBuffers();
/*
SendBuff[0] = 0xFF; // CLA
SendBuff[1] = 0xB0;// INS
SendBuff[2] = 0x00;// P1
SendBuff[3] = (byte)int.Parse(Block);// P2 : Block No.
SendBuff[4] = (byte)int.Parse("16");// Le
*/
SendBuff[0] = 0xD4;
SendBuff[1] = 0x40;
SendBuff[2] = 0x01;
SendBuff[3] = 0x30;
SendBuff[4] = byte.Parse(Block.ToString(), System.Globalization.NumberStyles.HexNumber);
SendBuff[5] = 0xFF;
SendBuff[6] = 0xFF;
SendBuff[7] = 0xFF;
SendBuff[8] = 0xFF;
SendBuff[9] = 0xFF;
SendBuff[10] = 0xFF;
//SendLen = 5;
//RecvLen = SendBuff[4] + 2;
SendLen = 5;
RecvLen = 255;
retCode = SendAPDUandDisplay(2);
if (retCode == -200)
{
return "outofrangeexception";
}
if (retCode == -202)
{
return "BytesNotAcceptable";
}
if (retCode != Card.SCARD_S_SUCCESS)
{
return "FailRead";
}
// Display data in text format
for (indx = 0; indx <= RecvLen - 1; indx++)
{
tmpStr = tmpStr + Convert.ToChar(RecvBuff[indx]);
}
return (tmpStr);
}
else
{
return "FailAuthentication";
}
}
Please Note that the read block method is called after checking that is a reader connected connected, if so then I call the
readblock method and it returns an empty string
I've tried several values as you would see in comments but nothing seems to help, it's been 3 long days and I'm still stuck here.
Can someone please help me figure where I'm doing it wrong and what values should I send in order to authenticate the block?
Please do me a favour that if anyone gets to knows the problem in my code or want to correctify the values I'm setting in sendBuff[] then please quote them in C# code so I can use exactly the solution you want me to implement
Any sincere help would be highly regarded, thanks in advance.
I have only experimented with mifare 1k, using Arduino.
In this instance, after detecting the card, and retrieving the UUID, It needs to select the card before reading/writing. Are you doing this select card step?
As its a S50 1K Classic the 'bytemap' is different and the process cycle while ostensibly the same you need to check that its a S50 before continuing by getting the ATR/ATS and parsing it to retrieve the switch setting. With contact its ATR, contactless ATS but is technically the same thing. Under PCSC this is asking for the readerchangestate when asking the reader is a card present, done before sending an APDU. You can also get other settings at the same time.
For MFS50 you need to perform a 'S'elect then a 'L'ogin using the sector key then read that sectors first three of 4 blocks but ignore most of the first sector block - the keys are in the fourth block along with other control bytes. The 'UID' is returned on 'S'elect, success or fail on 'L'ogin, data or 'E'rror on reading the blocks in the sector. For 14443 sector 0 the first block is occupied by the 'manufacturing' data which depends on the construct can have 4, 7 or 12 bytes as the UID with from a data point of view embedded CRC and check bytes, so cannot be used as a UID - it is a data map. Lights, C, ultralights, EV1's have a different 'bytemap' and may or may not have 'L'ogins at card or sector. These are 14443 types, there is also a 15693 type which has just data in the sectors. Some Chinese 14443 have writable manufacturing blocks, but usually its a mix of static, settings and OTP (once bit set cannot unset, used for authentication and NFC verification of size!).
Classic 1K: ident UID: 66908648, requires sector key log in (A read, B
read/write)
Sector 0:
6690864838880400468f76594d100612
00000000000000000000000000000000
00000000000000000000000000000000
ffffffffffffff078069ffffffffffff
...
Sector 15:
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
ffffffffffffff0780bcffffffffffff
Mifare ultralight: UID 0489d802a44080, might require sector login but key held elsewhere.
Sector 0:
0489D8DD
02A44080
66480900
00010001
.
Sector 1:
00000000
00000000
00000000
000000EE
15693: UID D89A1F24500104E0
Sector 0:
50555955
Sector 1:
48485353
Sector 2:
59435300
Sector 3:
00000000
...
Sector 15:
00000000
So, get the ATR/ATS and work out what card you have, then deal with it accordingly. Oh, and use the belt, braces and a piece of string approach - after writing to a card read it again to compare the written to what is expected. 15693 require sector complete writes else nothing gets written in that sector.
Will that be Type 2 NFC/NDEF - there are other standards. Have cannibalized a Zebra printer to encode and print NTAG201's bullseyes on the fly.
i have a OBEXConnect and OBEXRequest custom functions, i am not using library for it
OBEXConnect function is as following
private bool OBEXConnect()
{
//send client request
byte[] ConnectPacket = new byte[7];
ConnectPacket[0] = 0x80; // Connect
ConnectPacket[1] = 0x00; // Packetlength Hi Byte
ConnectPacket[2] = 0x07; // Packetlength Lo Byte
ConnectPacket[3] = 0x10; // Obex v1
ConnectPacket[4] = 0x00; // no flags
ConnectPacket[5] = 0x20; // 8k max packet size Hi Byte
ConnectPacket[6] = 0x00; // 8k max packet size Lo Byte
stream.Write(ConnectPacket,0,ConnectPacket.Length);
//listen for server response
byte[] ReceiveBufferA = new byte[3];
stream.Read(ReceiveBufferA,0,3);
if (ReceiveBufferA[0] == 160) // 0xa0
{
//success, decode rest of packet
int plength = (0xff * ReceiveBufferA[1]) + ReceiveBufferA[2]; //length of packet is...
//listen for rest of packet
byte[] ReceiveBufferB = new byte[plength-3];
stream.Read(ReceiveBufferB,0,plength-3);
int obver = ReceiveBufferB[0]; //server obex version (16 = v1.0)
int cflags = ReceiveBufferB[1]; //connect flags
int maxpack = (0xff * ReceiveBufferB[2]) + ReceiveBufferB[3]; //max packet size
return true;
}
else
{
return false;
}
}
and here is OBEXRequest function
private int OBEXRequest(string tReqType, string tName, string tType, string tFileContent)
{
//send client request
int i;
int offset;
int packetsize;
byte reqtype = 0x82;
int tTypeLen = 0x03;
int typeheadsize;
int typesizeHi = 0x00;
int typesizeLo = 0x03;
//tName = "contact.vcf";
//tType = "text/x-vCard";
//tFileContent = "BEGIN:VCARD\r\nVERSION:2.1\r\nN:;aardvark\r\nFN:aardvark\r\nEND:VCARD\r\n";
if (tReqType == "GET")
{
reqtype = 0x83; // 131 GET-Final
}
if (tReqType == "PUT")
{
reqtype = 0x82; // 130 PUT-Final
}
packetsize = 3;
//Name Header
int tNameLength = tName.Length;
int nameheadsize = (3 + (tNameLength*2) + 2);
int namesizeHi = (nameheadsize & 0xff00)/0xff;
int namesizeLo = nameheadsize & 0x00ff;
packetsize = packetsize + nameheadsize;
if (tType != "")
{
//Type Header
tTypeLen = tType.Length;
typeheadsize = 3 + tTypeLen + 1;
typesizeHi = (typeheadsize & 0xff00)/0xff;
typesizeLo = typeheadsize & 0x00ff;
packetsize = packetsize + typeheadsize;
}
//Body
int fileLen = tFileContent.Length;
int fileheadsize = 3 + fileLen ;
int filesizeHi = (fileheadsize & 0xff00)/0xff;;
int filesizeLo = fileheadsize & 0x00ff;;
packetsize = packetsize + fileheadsize;
int packetsizeHi = (packetsize & 0xff00)/0xff;
int packetsizeLo = packetsize & 0x00ff;
byte[] tSendByte = new byte[packetsize];
//PUT-final Header
tSendByte[0] = reqtype; // Request type e.g. PUT-final 130
tSendByte[1] = Convert.ToByte(packetsizeHi); // Packetlength Hi
tSendByte[2] = Convert.ToByte(packetsizeLo); // Packetlength Lo
offset = 2;
//Name Header
tSendByte[offset+1] = 0x01; // HI for Name header
tSendByte[offset+2] = Convert.ToByte(namesizeHi); // Length of Name header (2 bytes per char)
tSendByte[offset+3] = Convert.ToByte(namesizeLo); // Length of Name header (2 bytes per char)
// Name+\n\n in unicode
byte[] tNameU = System.Text.Encoding.BigEndianUnicode.GetBytes(tName);
tNameU.CopyTo(tSendByte,offset+4);
offset = offset + 3 + (tNameLength*2);
tSendByte[offset+1] = 0x00; // null term
tSendByte[offset+2] = 0x00; // null term
offset = offset + 2;
if (tType != "")
{
//Type Header
tSendByte[offset+1] = 0x42; // HI for Type Header 66
tSendByte[offset+2] = Convert.ToByte(typesizeHi); // Length of Type Header
tSendByte[offset+3] = Convert.ToByte(typesizeLo); // Length of Type Header
for (i=0;i<=(tTypeLen-1);i++)
{
tSendByte[offset+4+i] = Convert.ToByte(Convert.ToChar(tType.Substring(i,1)));
}
tSendByte[offset+3+tTypeLen+1] = 0x00; // null terminator
offset = offset+3+tTypeLen+1;
}
//Body
tSendByte[offset+1] = 0x49; //HI End of Body 73
tSendByte[offset+2] = Convert.ToByte(filesizeHi); //
tSendByte[offset+3] = Convert.ToByte(filesizeLo); //1k payload + 3 for HI header
for (i=0;i<=(fileLen-1);i++)
{
tSendByte[offset+4+i] = Convert.ToByte(Convert.ToChar(tFileContent.Substring(i,1)));
}
//tSendByte[offset+4+fileLen] = 0x00; // null terminator
offset = offset+3+fileLen;
stream.Write(tSendByte,0,tSendByte.Length );
//listen for server response
//TODO: can hang here forever waiting response...
bool x = stream.DataAvailable; // changed bluetoothclient - public NetworkStream GetStream()
byte[] tArray4 = new byte[3];
stream.Read(tArray4,0,3);
x = stream.DataAvailable;
if (tArray4[0] == 160) // 0xa0
{
int plength = (tArray4[1] * 256) + tArray4[2] - 3;
byte[] tArray5 = new byte[plength];
if (plength >0)
{
stream.Read(tArray5,0,plength);
//TODO: data in returned packet to deal with
}
return 160;
}
if (tArray4[0] == 197) // 0xc5 Method not allowed
{
return 197;
}
if (tArray4[0] == 192) // 0xc0 Bad Request
{
return 192;
}
return 0;
}
i want to read the phone book of mobile but i not succeeded yet
i try on one samsung mobile it gives error bad request i follow the solutions above mentioned but when name = null then obexrequest function gives error
when i try it on huawei mobile it gives unknown error
i try this code as well it throw error that this method is not implemented
Read contacts using obex in c#
i call these functions like this
string tName = "";
string tType = "text/x-vCard";
string tFileContent = "";
int result = OBEXRequest("GET",tName,tType,tFileContent);
switch (result)
{
case 160: // 0xa0
addtolog("OK");
break;
case 197: // 0xc5
addtolog("Method not allowed");
break;
case 192: // 0xc0
addtolog("Bad Request");
break;
default:
addtolog("Other Error");
break;
}
can any body point out my mistake
Quser.exe allows a client to see user sessions on a remote RDP server. For example,
C:\>quser /server:MyRDPserver
USERNAME SESSIONNAME ID STATE IDLE TIME LOGON TIME
userA 3 Disc 1+20:03 08/07/2014 12:36
userB 4 Disc 1+22:28 08/07/2014 10:38
I would like to build this functionality into a C++ or C# program. Yes, I could just spawn quser.exe and parse the output, but is there an Win32 API or .Net framework class that can give me the same information? Specifically:
User Name
Connection State
Logon time
I've found that using WMI (Win32_LoggedOnUser) to find the same information is unreliable, as it often lists stale connections. I've also tried the psloggedon approach of enumerating subkeys of HKEY_USERS and looking for the Volatile Environment key, but this also suffers from the same problem.
I'm going to answer my own question.
First of all, you need to make sure that permissions are set correctly on the target machine. This entails setting HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\AllowRemoteRPC to 1. A powershell script to do this is:
# Get the service account credential
$cred = Get-Credential my_admin_account
$Target_Computers = #("Computer_1","Computer_2")
# open the remote registry
[long]$HIVE_HKLM = 2147483650
foreach($c in $Target_Computers)
{
$StdRegProv = Get-WmiObject -List -Namespace root\default -ComputerName $c -Credential $cred | where { $_.Name -eq "StdRegProv" }
$StdRegProv.SetDWORDValue($HIVE_HKLM, "SYSTEM\CurrentControlSet\Control\Terminal Server", "AllowRemoteRPC", 1)
}
As Xearinox said, for C++ you can use the WTSxxx functions in the Win32 API. Assuming your computers are not XP, here is some C++ code:
#include <string>
#include <iostream>
#include <iomanip>
#include <windows.h>
#include <WtsApi32.h>
using namespace std;
const unsigned num_connection_states = 10;
const wchar_t* connection_state_list[num_connection_states] = {
L"Active",
L"Connected",
L"ConnectQuery",
L"Shadow",
L"Disc",
L"Idle",
L"Listen",
L"Reset",
L"Down",
L"Init" };
int print_error(DWORD err)
{
// format the message
LPTSTR* ppBuffer = nullptr;
DWORD retval = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER, nullptr, err, 0, reinterpret_cast<LPTSTR>(ppBuffer), 0, nullptr);
// print out
wcerr << "Error: *ppBuffer" << endl;
return 1;
}
wstring format_time(const LARGE_INTEGER& time)
{
// convert to a local Win32 file time
FILETIME ft = { time.LowPart, time.HighPart };
FileTimeToLocalFileTime( &ft, &ft );
// convert to a system time
SYSTEMTIME st;
FileTimeToSystemTime( &ft, &st );
wchar_t local_date[255], local_time[255];
GetDateFormat( LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, local_date, sizeof(local_date)/sizeof(wchar_t) );
GetTimeFormat( LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, local_time, sizeof(local_time)/sizeof(wchar_t) );
wstring result = local_date;
result.append(L" ");
result.append(local_time);
return result;
}
const _int64 SECOND = 10000000;
const _int64 MINUTE = 60*SECOND;
const _int64 HOUR = 60*MINUTE;
const _int64 DAY = 24*HOUR;
wstring format_timespan(const LARGE_INTEGER& timespan)
{
// convert to a local Win32 file time
FILETIME ft = { timespan.LowPart, timespan.HighPart };
FileTimeToLocalFileTime( &ft, &ft );
// convert to a system time
SYSTEMTIME st;
FileTimeToSystemTime( &ft, &st );
wchar_t local_time[255];
int daydiff = floor(
GetTimeFormat( LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, local_time, sizeof(local_time)/sizeof(wchar_t) );
wstring result = local_date;
result.append(L" ");
result.append(local_time);
return result;
}
int wmain(int argc, wchar_t* argv[])
{
// check args
if(argc > 2)
{
wcout << "Usage: " << argv[0] << " [server_name]\n";
return 1;
}
// server name
bool current_server = true;
wstring server_name = L".";
if(argc == 2)
{
server_name = argv[1];
current_server = false;
}
// open the server
HANDLE hServer;
if(current_server)
hServer = WTS_CURRENT_SERVER_HANDLE;
else
hServer = WTSOpenServer(const_cast<LPWSTR>(server_name.c_str()));
// enumerate through the sessions
DWORD Count = 0;
WTS_SESSION_INFO* pSessionInfo = nullptr;
BOOL success = WTSEnumerateSessions(hServer, 0, 1, &pSessionInfo, &Count);
if(success == 0)
return false;
// write the headers
wcout << " " << left << setw(24) << "USERNAME";
wcout << setw(19) << "SESSIONNAME";
wcout << "ID ";
wcout << setw(9) << "STATE";
wcout << "IDLE TIME LOGON TIME";
// loop through each session
for(unsigned long s=0; s<Count; s++)
{
LPTSTR pBuffer = nullptr;
DWORD BytesReturned = 0;
wcout << "\n " << left;
// try getting all info at once
WTSINFO* info = nullptr;
success = WTSQuerySessionInformation(hServer, pSessionInfo[s].SessionId, WTSSessionInfo, reinterpret_cast<LPTSTR*>(&info), &BytesReturned);
bool have_wtsinfo = true;
if(!success)
{
// see why failed
DWORD err = GetLastError();
if(err == ERROR_NOT_SUPPORTED)
have_wtsinfo = false;
else
return print_error(err);
}
// print user name
wstring user_name;
if(have_wtsinfo)
user_name = info->UserName;
else
{
success = WTSQuerySessionInformation(hServer, pSessionInfo[s].SessionId, WTSUserName, &pBuffer, &BytesReturned);
if(!success)
continue;
user_name = pBuffer;
WTSFreeMemory(pBuffer);
}
wcout << setw(24) << user_name;
// print session name
wstring session_name;
if(have_wtsinfo)
session_name = info->WinStationName;
else
{
success = WTSQuerySessionInformation(hServer, pSessionInfo[s].SessionId, WTSWinStationName, &pBuffer, &BytesReturned);
if(!success)
continue;
session_name = pBuffer;
WTSFreeMemory(pBuffer);
}
wcout << setw(19) << session_name;
// print session ID
wcout << right << setw(2) << pSessionInfo[s].SessionId;
// print connection state
WTS_CONNECTSTATE_CLASS connect_state;
if(have_wtsinfo)
connect_state = info->State;
else
{
success = WTSQuerySessionInformation(hServer, pSessionInfo[s].SessionId, WTSConnectState, &pBuffer, &BytesReturned);
if(!success)
continue;
connect_state = *reinterpret_cast<WTS_CONNECTSTATE_CLASS*>(pBuffer);
WTSFreeMemory(pBuffer);
}
if(connect_state>=num_connection_states)
continue;
wcout << " " << left << setw(8) << connection_state_list[connect_state];
// get idle time
LARGE_INTEGER idle = info->CurrentTime;
idle.QuadPart -= info->LogonTime.QuadPart;
// print logon time - not supported
if(info->LogonTime.QuadPart!=0)
{
wcout << format_time(info->LogonTime);
}
// clean up
WTSFreeMemory(info);
}
// clean up
WTSFreeMemory(pSessionInfo);
if(!current_server)
WTSCloseServer(hServer);
}
For C#, the easiest way is to use the Cassia library, which is basically a C# wrapper around the same API functions.
You can call a Win32 API to create a process and pass the "quser /server:MyRDPserver" as parameters,I usually do like this:
PROCESS_INFORMATION process_info;
STARTUPINFOA startup_info;
string cmdline2;
char error_msg[1024];
memset(&process_info, 0, sizeof(process_info));
memset(&startup_info, 0, sizeof(startup_info));
startup_info.cb = sizeof(startup_info);
argc = argarray.size();
for(int i = 0; i < argc; i++) {
cmdline2 += argarray.at(i);
if(i != (argc - 1)) cmdline2 += " ";
}
string command = suCmdLineRemoveQuotations(argarray.at(0));
retval = CreateProcessA(command.c_str(), (LPSTR)cmdline2.c_str(), NULL, NULL, TRUE,
0, NULL, NULL, &startup_info, &process_info);
if (!retval) {
windows_error_string(error_msg, sizeof(error_msg));
error = error_msg;
return false;
}
WaitForSingleObject(process_info.hProcess, msecs);
if(GetExitCodeProcess(process_info.hProcess, &status)) {
// status maybe is STILL_ACTIVE, in that case, the process is killed
if(status == STILL_ACTIVE) {
TerminateProcess(process_info.hProcess, 1);
}
ecode = status;
}
return true;
when the process startup, you can redirect the output.If you use Qt,the problem become simple,you can use QProcess to implement.
I have a problem reading real time temperature data from the DS18B20+ sensor on a DLPIO20 device. I'm using the FTD2XX.DLL .NET wrapper (version 1.0.14) on the Windows platform (as per link: http://www.ftdichip.com/Support/SoftwareExamples/CodeExamples/CSharp/FTD2XX_NET_v1.0.14.zip).
Test application to demonstrate the issue is below.
Here is what I mean by real-time.
2.1 At fairly constant ambient temperature (let's say 20° C) have few temperature reads to see consistent results in debug mode (break point at the end of temperature read cycle on line 55).
2.2.Then, while on break point, just breath on sensor or use other means to heat it few degrees above ambient.
2.3. Run two or three more cycles of temperature readings.
The first read I get after the sensor heats up is the 'old' temperature of 20° C. Only on second or third read cycles I've got realistic results around 28° C.
What's interesting, with test application program IO20Demo (provided with the purchase of the DLP-IO20 board) if I issued Convert command before the read, I get a real-time result of 28° C right away. With this program and managed .NET wrapper class I also send Convert command before Read, but to no avail. The big difference is IO20Demo doesn't use managed wrapper class, but uses FTD2XX.lib directly.
Could you help me understand what I'm doing wrong here? How I can get real-time temperature data using managed .NET wrapper class?
Your help is greatly appreciated!
/// <summary>
/// Program for DLPIO20 device to read temperature data from DS18B20+
/// digital temperature sensor attached to one of its channels.
/// </summary>
class Program
{
static void Main(string[] args)
{
FTDI FtdiWrapper = null;
// DLPIO20 channel where the DS18B20+ sensor is attached
byte sensorChannel = 0x06;
try
{
// create new instance of the FTDI device class
FtdiWrapper = ConnectToFirstFtdiDevice();
if (FtdiWrapper == null || !FtdiWrapper.IsOpen)
{
throw new Exception("Error connection to FTDI device.");
}
// didn't helped at all for 85dC issue
//PurgeRxBuffer(FtdiWrapper);
// helped avoid 85dC issue at first read
ConvertSensorData(FtdiWrapper, sensorChannel);
// send read sensor command
float? degreesC = null;
for (int i = 0; i < 100; i++)
{
// calling Convert just before ReadTemperatureSensor causes
// IO20Demo (using FTD2XX.lib) to return real temperature
// but it doesn't help when using .NET wrapper
ConvertSensorData(FtdiWrapper, sensorChannel);
// other failed attempts to get real time sensor data
// previous value returned:
//PurgeRxBuffer(FtdiWrapper);
// read but only initiate conversion on success
degreesC = ReadTemperatureSensor(FtdiWrapper, sensorChannel);
if (degreesC == null)
{
throw new Exception("Error converting raw data to Celsius");
}
var message = string.Format("Success! {0}° Celsius.", degreesC);
Console.WriteLine(message);
}
Console.WriteLine("Press any key to exit ...");
Console.ReadKey();
}
catch (Exception ex)
{
Console.WriteLine(ex);
Console.WriteLine("Press any key to exit ...");
Console.ReadKey();
}
finally
{
if (FtdiWrapper != null && FtdiWrapper.IsOpen)
{
FtdiWrapper.Close();
}
}
}
This is the code used to connect to the first FTDI device
static private FTDI ConnectToFirstFtdiDevice()
{
FTDI FtdiWrapper = new FTDI();
UInt32 ftdiDeviceCount = 0;
FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OTHER_ERROR;
// Determine the number of FTDI devices connected to the machine
ftStatus = FtdiWrapper.GetNumberOfDevices(ref ftdiDeviceCount);
// Check status
if (ftStatus != FTDI.FT_STATUS.FT_OK)
throw new Exception(string.Format("Error after GetNumberOfDevices(), ftStatus: {0}", ftStatus));
if (ftdiDeviceCount == 0)
throw new Exception("No FTDI device found");
// Allocate storage for device info list
var ftdiDeviceList = new FTDI.FT_DEVICE_INFO_NODE[ftdiDeviceCount];
// Populate our device list
ftStatus = FtdiWrapper.GetDeviceList(ftdiDeviceList);
if (ftStatus == FTDI.FT_STATUS.FT_OK)
{
// Open first device in our list by serial number
ftStatus = FtdiWrapper.OpenBySerialNumber(ftdiDeviceList[0].SerialNumber);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
throw new Exception(string.Format("Error opening first device, ftStatus: {0}", ftStatus));
ftStatus = FtdiWrapper.SetBaudRate(9600);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
throw new Exception(string.Format("Error to set Baud rate, ftStatus: {0}", ftStatus));
// Set data characteristics - Data bits, Stop bits, Parity
ftStatus = FtdiWrapper.SetDataCharacteristics(FTDI.FT_DATA_BITS.FT_BITS_8, FTDI.FT_STOP_BITS.FT_STOP_BITS_1, FTDI.FT_PARITY.FT_PARITY_NONE);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
throw new Exception(string.Format("Error to set data characteristics , ftStatus: {0}", ftStatus));
// Set flow control - set RTS/CTS flow control
ftStatus = FtdiWrapper.SetFlowControl(FTDI.FT_FLOW_CONTROL.FT_FLOW_RTS_CTS, 0x11, 0x13);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
throw new Exception(string.Format("Error to set flow control , ftStatus: {0}", ftStatus));
// Set read timeout to 5 seconds, write timeout to infinite
ftStatus = FtdiWrapper.SetTimeouts(5000, 0);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
throw new Exception(string.Format("Error to set timeouts, ftStatus: {0}", ftStatus));
}
return FtdiWrapper;
}
Method to convert raw sensor data
static private void ConvertSensorData(FTDI FtdiWrapper, byte sensorChannel)
{
FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OTHER_ERROR;
UInt32 numBytesWritten = 0;
byte[] convertCommand = new byte[] { 0x03, 0x40, sensorChannel };
ftStatus = FtdiWrapper.Write(convertCommand, convertCommand.Length, ref numBytesWritten);
bool isAllBytesWritten = numBytesWritten == convertCommand.Length;
if (ftStatus != FTDI.FT_STATUS.FT_OK && isAllBytesWritten)
throw new Exception(string.Format("Failed to write Convert command to device; Status: {0}, isAllBytesWritten: {1}", ftStatus.ToString(), isAllBytesWritten));
}
Method to read sensor temperature
static private float? ReadTemperatureSensor(FTDI FtdiWrapper, byte sensorChannel)
{
float? degreesC = null;
FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OTHER_ERROR;
UInt32 numBytesWritten = 0;
byte[] readSensorCommand = new byte[] { 0x03, 0x41, sensorChannel };
ftStatus = FtdiWrapper.Write(readSensorCommand, readSensorCommand.Length, ref numBytesWritten);
bool isAllBytesWritten = numBytesWritten == readSensorCommand.Length;
if (ftStatus != FTDI.FT_STATUS.FT_OK && isAllBytesWritten)
throw new Exception(string.Format("Failed to write readSensorCommand to device; Status: {0}, isAllBytesWritten: {1}", ftStatus.ToString(), isAllBytesWritten));
// Read back response
UInt32 numBytesAvailable = 0;
UInt32 numBytesExpected = 2; // read sensor command expected to return 2 bytes
while (numBytesAvailable == 0)
{
Thread.Sleep(40); // value of 40 taken from DLP IO20 demo solution
ftStatus = FtdiWrapper.GetRxBytesAvailable(ref numBytesAvailable);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
throw new Exception("Failed to get number of bytes available to read; error: " + ftStatus);
} //while (numBytesAvailable < numBytesExpected);
if (numBytesAvailable != numBytesExpected)
throw new Exception("Error: Invalid data in buffer. (1350)");
UInt32 numBytesRead = 0;
byte[] rawData = new byte[numBytesExpected];
ftStatus = FtdiWrapper.Read(rawData, numBytesAvailable, ref numBytesRead);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
throw new Exception("Failed to read data from device after command has been sent; error: " + ftStatus);
//convert raw response data to degrees Celsius
degreesC = ConvertTemperature(rawData);
return degreesC;
}
Method to purge the transmit buffer
static private void PurgeRxBuffer(FTDI FtdiWrapper)
{
UInt32 numBytesAvailable = 0;
UInt32 numBytesRead = 0;
FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OTHER_ERROR;
byte[] rx = new byte[1001]; //allocate large enough space to read from device
Thread.Sleep(5);
ftStatus = FtdiWrapper.GetRxBytesAvailable(ref numBytesAvailable);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
throw new Exception("Failed to get number of bytes available to read; error: " + ftStatus);
if (numBytesAvailable > 1000)
numBytesAvailable = 1000;
while (numBytesAvailable > 0)
{
//read the data from the buffer
numBytesRead = 0;
ftStatus = FtdiWrapper.Read(rx, numBytesAvailable, ref numBytesRead);
ftStatus = FtdiWrapper.GetRxBytesAvailable(ref numBytesAvailable);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
throw new Exception("Failed to get number of bytes available to read; error: " + ftStatus);
if (numBytesAvailable > 1000)
numBytesAvailable = 1000;
Thread.Sleep(5);
}
}
Method to convert temperature from raw data to Celsius
static private float? ConvertTemperature(byte[] rawData)
{
float? tempCelsius = null;
bool isnegative = false;
//check input
if (rawData.Length < 2)
throw new Exception(string.Format("Input parameter rawData for temperature conversion must be 2 bytes, actual length is: {0}", rawData.Length));
int temp = rawData[0] | (rawData[1] << 8);
if ((temp & 0x8000) == 0x8000)//if MSBit is set then negative temperature
{
temp &= 0x07ff;
isnegative = true;
temp = 0x800 - temp;
}
temp &= 0x07ff;
tempCelsius = (float)((float)temp / 16.0);
if (isnegative) tempCelsius *= -1;
return tempCelsius;
}
}
I think you would need to set the latency timer on the FTDI device in your ConnectToFirstFtdiDevice to the min value, I use 16ms for mine and it helped solve this type of issue for me. The purgeRX is only a software buffer not HW so that will not prevent you from having stale measurements in the FTDI USB buffer.
should use monitor / command / response design pattern here. there are repeated command/response sequences here so implementing a pattern reduces the redundancies that exist in your code. i'd start out with an interface & command/response structure with event handlers; i.e. if FTDI.deviceCount > 0, then fire the event handler. , follow up with child dependent handlers . on the receive side, .net serial port handler at the lowest level is TDM based. it WILL lose some information along the way. to be complete, add a simple packet passing protocol, such as XOR with checksum at both ends. i.e. calculate checksum of message at device, send command, receive command at other end, calculate checksum, compare against captured checksum. if same then OK, else, echo captured command back to device. vice-ersa here..
my two cents == my two dollars, same thing
You cannot get available bytes from calling FtdiWrapper.GetRxBytesAvailable. You need to call FtdiWrapper.Read in a loop until you get your expected bytes, then jump out the loop.