I'm try to write a javacard applet that need to add/sub two array of bytes.
the addition was success but the subtraction fail in some cases ("when there is a borrow from the procceding byte").
Can you check my code and improve it to work better?
package phase1;
import javacard.framework.APDU;
import javacard.framework.Applet;
import javacard.framework.ISO7816;
import javacard.framework.ISOException;
import javacard.framework.Util;
import javacard.security.CryptoException;
public class keygen extends Applet {
public static final short _0 = 0;
public final static byte[] one = {(byte) 0xff, (byte) 0xff, (byte) 0xff,(byte) 0xff,(byte) 0xff,(byte) 0xff};
byte [] G = {(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x11};
private keygen() {
}
public static void install(byte bArray[], short bOffset, byte bLength)throws ISOException {
try{
new keygen().register();
} catch (Exception e) {
ISOException.throwIt((short) 0x8888);
}
}
public void process(APDU apdu) throws ISOException {
// TODO Auto-generated method stub
if (selectingApplet()) return;
//short sendlen = 0;
byte[] buf = apdu.getBuffer();
byte ins = buf[ISO7816.OFFSET_INS];
byte [] val = new byte [(short) G.length];
short i;
short len = (short) G.length ;
short Alen = (short) (len - 1);
short b = (short) 0 ;
byte[] Z = new byte [(short) len];
byte[] y = new byte [(short) 2];
try{
switch (ins){
case (byte) 0x01: //0x0F
{
Z = addarray (G , one);
apdu.setOutgoing();
buf = Z;
apdu.setOutgoingLength(len);
apdu.sendBytesLong(Z, (short) 0,len);
break;
}
case (byte) 0x02: //0x0F
{ //Z = new byte [(short) 7];
Z = subarray1 (G , one);
apdu.setOutgoing();
buf= Z;
apdu.setOutgoingLength(len);
apdu.sendBytesLong(Z, (short) 0,len);
break;
}
default:
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
}
}catch (CryptoException e) {
ISOException.throwIt(((CryptoException) e).getReason());
}
}
private byte [] addarray (byte [] Arr1, byte [] Arr2 )
{
short i;
short [] X = new short [(short) 6];
short len = (short) Arr1.length ;
short Alen = (short) (len - 1);
byte [] AddArr = new byte [len];
short R = (short) 0;
byte[] Z = new byte [(short) 2];
for (i = Alen; i >= 0 ; i--)
{
X[i] = (short) ((Arr1[i] & 0xFF) + (Arr2[i]&0xff) + R);
Util.setShort(Z, (short) 0, (short) X[i]);
AddArr[i] = (byte) Z[1];
R = (short) (Z[0]);
}
return AddArr;
}
private byte [] subarray1 (byte [] Arr1, byte [] Arr2)
{
short i;
byte [] X = new byte [(short) 6];
short len = (short) Arr1.length ;
short Alen = (short) (len - 1);
byte [] SubArr = new byte [len];
short R = (short) 0;
byte[] Z = new byte [(short) 2];
for (i = Alen; i > 0 ; i--)
{
X[i] = (byte) (Arr1[i] - Arr2[i] - (byte) R );
Util.setShort(Z, (short) 0, (short) X[i]);
SubArr[i] = (byte) Z[1];
R = (short) (Z[0] );
}
return SubArr;
}
}
There is an optional class in Java Card API named bigIntNumber. If your card doesn't implemented it, I share its source code with you:
/**
* Class BigIntNumber provides addition, subtraction and comparison functions
* for unsigned integers represented in byte array format in bug endian order.
*
*/
public class BigIntNumber {
/**
* Add two unsigned integers represented in array A and B. The sum stored in
* array C
*
* #param A the left operand
* #param AOff the starting position in array A.
* #param B the right operand.
* #param BOff the starting position in array B.
* #param C the result of (A+B)
* #param COff the starting position in array C.
* #param len the number of bytes in the operands as well in the computed
* result. this parameter can not be a negative number.
* #return false if the result overflows. if overflows occurs, the sum would
* be the true mathematical result with the most significant bytes discarded
* to fit into array C of the specified length.
* #throws ArrayOuutOfBoundException if array access out of bound.
*/
public static boolean add(byte[] A, byte AOff, byte[] B, byte BOff, byte[] C, byte COff, byte len) {
short result = 0;
for (len = (byte) (len - 1); len >= 0; len--) {
// add two unsigned bytes and the carry from the
// previous byte computation.
result = (short) (getUnsignedByte(A, AOff, len) + getUnsignedByte(B, BOff, len) + result);
// store the result in byte array C
C[(byte) (len + COff)] = (byte) result;
// has a carry?
if (result > 0x00FF) {
result = 1;
result = (short) (result + 0x100);
} else {
result = 0;
}
}
//produce overflow in the sum.
if (result == 1) {
return false;
}
return true;
}
/**
* Subtract two unsigned integers represented in array A and B. The sum stored in
* array C
*
* #param A the left operand
* #param AOff the starting position in array A.
* #param B the right operand.
* #param BOff the starting position in array B.
* #param C the result of (A-B)
* #param COff the starting position in array C.
* #param len the number of bytes in the operands as well in the computed
* result. this parameter can not be a negative number.
* #return false if the result underflows. if underflows occurs, the sum would
* be the mathematical result of A + ~B + 1.
* #throws ArrayOuutOfBoundException if array access out of bound.
*/
public static boolean subtract(byte[] A, byte AOff, byte[] B, byte BOff, byte[] C, byte COff, byte len) {
byte borrow = 0;
short result;
for (len = (byte) (len - 1); len >= 0; len--) {
// subtract one unsigned byte from the other.
// also subtract the borrow from the previous byte computation.
result = (short) (getUnsignedByte(A, AOff, len) - getUnsignedByte(B, BOff, len) - borrow);
// need to borrow?
if (result < 0) {
borrow = 1;
result = (short) (result + 0x100);
} else {
borrow = 0;
}
// store the result in C
C[(byte) (len + COff)] = (byte) result;
}
// is the result underflow?
if (borrow == 1) {
return false;
}
return true;
}
/**
* Compare two unsigned integers represented in array A and B. The sum stored in
* array C
*
* #param A the left operand
* #param AOff the starting position in array A.
* #param B the right operand.
* #param BOff the starting position in array B.
* #param C the result of (A-B)
* #param COff the starting position in array C.
* #param len the number of bytes in the operands as well in the computed
* result. this parameter can not be a negative number.
* #return the result of comparison as below:
* 0 if identical
* 1 if the left operand is bigger than the right operand
* -1 if the left operand is smaller than the right operand
* #throws ArrayOuutOfBoundException if array access out of bound.
*/
public static byte compare(byte[] A, byte AOff, byte[] B, byte BOff, byte len) {
byte count = (byte) 0;
for (; count < len; count++) {
short C = getUnsignedByte(A, AOff, count);
short D = getUnsignedByte(A, AOff, count);
if (C < D) {
return -1;
}
if (C > D) {
return 1;
}
}
return 0;
}
/**
*
* Get the unsigned byte at the index (AOff + count)
*/
private static short getUnsignedByte(byte[] A, byte AOff, byte count) {
return (short) (A[(short) (count + AOff)] & 0x00FF);
}
}
And this is a sample applet that I wroto to show you how does the above class methods work:
package phase1;
import javacard.framework.APDU;
import javacard.framework.Applet;
import javacard.framework.ISO7816;
import javacard.framework.ISOException;
import javacard.framework.Util;
import static phase1.BigIntNumber.*;
public class TestBigInt extends Applet {
// Defining global arrays for Operands A and B.
// LenA and LenB are defined to check if equal length of A and B are going
// to add, compare or subtract or not. Len of operands musb be equal between 1 byte to 8 bytes.
public static byte[] OpA = new byte[8];
public static byte[] OpB = new byte[8];
public static byte[] result = new byte[8];
public static byte lenA;
public static byte lenB;
// Defining supported INS valuse for APDU Command.
public static final byte INS_INIT_OPERAND = (byte) 0x10;
public static final byte INS_ADD = (byte) 0x20;
public static final byte INS_SUBTRACT = (byte) 0x30;
public static final byte INS_COMPARE = (byte) 0x40;
// P1 parameter in the APDU command
public static final byte OPERAND_A = 0x01;
public static final byte OPERAND_B = 0x02;
// Defining Exception Status Words
public static short SW_NOT_EQUAL_LENGTH = (short) 0x6910;
public static short SW_OVERFLOW_OCCURS = (short) 0x6911;
public static short SW_UNDERFLOW_OCCURS = (short) 0x6912;
private TestBigInt() {
}
public static void install(byte bArray[], short bOffset, byte bLength) throws ISOException {
new TestBigInt().register();
}
public void process(APDU apdu) throws ISOException {
if (selectingApplet()) {
return;
}
byte[] buf = apdu.getBuffer();
switch (buf[ISO7816.OFFSET_INS]) {
case INS_INIT_OPERAND:
apdu.setIncomingAndReceive();
if (buf[ISO7816.OFFSET_LC] > (byte) 0x08) {
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}
if (buf[ISO7816.OFFSET_P1] == OPERAND_A) {
Util.arrayCopyNonAtomic(buf, ISO7816.OFFSET_CDATA, OpA, (short) 0x00, buf[ISO7816.OFFSET_LC]);
lenA = buf[ISO7816.OFFSET_LC];
} else if (buf[ISO7816.OFFSET_P1] == OPERAND_B) {
Util.arrayCopyNonAtomic(buf, ISO7816.OFFSET_CDATA, OpB, (short) 0x00, buf[ISO7816.OFFSET_LC]);
lenB = buf[ISO7816.OFFSET_LC];
} else {
ISOException.throwIt(ISO7816.SW_WRONG_P1P2);
}
break;
case INS_ADD:
if (lenA != lenB) {
ISOException.throwIt(SW_NOT_EQUAL_LENGTH);
}
if (add(OpA, (byte) 0x00, OpB, (byte) 0x00, result, (byte) 0x00, lenA)) {
apdu.sendBytesLong(result, (short) 0x00, (short) lenA);
} else {
ISOException.throwIt(SW_OVERFLOW_OCCURS);
}
break;
case INS_SUBTRACT:
if (lenA != lenB) {
ISOException.throwIt(SW_NOT_EQUAL_LENGTH);
}
if (subtract(OpA, (byte) 0x00, OpB, (byte) 0x00, result, (byte) 0x00, lenA)) {
apdu.sendBytesLong(result, (short) 0x00, (short) lenA);
} else {
ISOException.throwIt(SW_UNDERFLOW_OCCURS);
}
break;
case INS_COMPARE:
// ...
break;
default:
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
}
}
}
It seems works fine:
Connect successful.
Download Cap begin...
Download Cap successful.
Install Applet begin...
Install Applet successful.
Select Applet begin...
Select Applet successful.
Send: 00 10 01 00 07 11 22 33 44 55 66 77 00 //Initilizing Operand A
Recv: 90 00
Time used: 21.000 ms
Send: 00 10 02 00 07 11 22 33 44 55 66 77 00 //Initlizing Operand B
Recv: 90 00
Time used: 19.000 ms
Send: 00 20 00 00 00 // Compute A+B
Recv: 22 44 66 88 AA CC EE 90 00
Time used: 67.000 ms
Send: 00 30 00 00 00 // Compute A-B
Recv: 00 00 00 00 00 00 00 90 00
Time used: 73.000 ms
Send: 00 10 02 00 07 00 00 44 44 44 44 44 00 // Changing Operand B
Recv: 90 00
Time used: 14.000 ms
Send: 00 20 00 00 00 // Compute A+B again
Recv: 11 22 77 88 99 AA BB 90 00
Time used: 66.000 ms
Send: 00 30 00 00 00 // Compute A-B
Recv: 11 21 EF 00 11 22 33 90 00
Time used: 71.000 ms
Sorry, I didn't checked your code. Just two simple hint:
1- Try to don't use dynamic fields in methods. Java Card doesn't support automatic garbage collection, so the memory that you assign to a field dynamically (i.e. using new keyword), will not reclaimed automatically until calling requestObjectDeletion() method (and it's optional too!) :)
2- 0x8888 is not a standard status world in the ISO7816-4 standard and some smart cards has problem with non-standard status words. Try to choose 6XXX (60XX is also non-standard value) or 9XXX for status words.
Related
I have a UInt64 value with some bits on and some off e.g.:
01010101 01010101 01010101 01010101 01010101 01010101 01010101 01010101
How can I easily shift the set bits to the right, such they are to the right end of their respective bytes e.g:
00001111 00001111 00001111 00001111 00001111 00001111 00001111 00001111
I've seen questions which move the on bits all the way to the right of the 64 bit unsigned integer, but I only want to shift them to the right of the byte in which they lie if possible.
Thanks.
using System;
using System.Linq;
namespace ConsoleApplication5
{
public class Program
{
public static void Main(String[] args)
{
var inputAsBinaryString = "01010101 01010101 01010101 01010101 01010101 01010101 01010101 01010101";
var inputAsUInt64 = GetBinaryStringAsUInt64(inputAsBinaryString);
var actualAsUInt64 = GetRightAlignedBytes(inputAsUInt64);
var actualAsBinaryString = GetAsBinaryString(actualAsUInt64);
var expectedAsBinaryString = "00001111 00001111 00001111 00001111 00001111 00001111 00001111 00001111";
var expectedAsUInt64 = GetBinaryStringAsUInt64(expectedAsBinaryString);
} // <-- Set a breakpoint here and inspect the values.
/* Bit-manipulation methods. */
private static UInt64 GetRightAlignedBytes(UInt64 n)
{
var rightAlignedByteArray =
BitConverter
.GetBytes(n)
.Select(b => GetRightAlignedByte(b))
.ToArray();
return BitConverter.ToUInt64(rightAlignedByteArray, 0);
}
/* Shove all of a byte's bits to the right. */
private static Byte GetRightAlignedByte(Byte b)
{
/* The << operator only works on 32 and 64 bit values.
This requires treating the result as an Int32 until it's returned. */
Int32 result = 0;
var numberOfSetBits = GetNumberOfSetBits(b);
for (Byte n = 1; n <= numberOfSetBits; n++)
{
/* Need to set n bits, but only perform n - 1 left shifts. */
result |= 1;
if (n < numberOfSetBits)
result = result << 1;
}
return (Byte) result;
}
private static Byte GetNumberOfSetBits(Byte b)
{
/* There are many ways to count the number of "set" bits in a byte.
This StackOverflow question
http://stackoverflow.com/questions/109023/how-to-count-the-number-of-set-bits-in-a-32-bit-integer
has a mind-numbing collection of answers.
Most of them are probably more efficient than this method. */
Int32 result = 0;
/* The >> operator only works on 32 and 64 bit values.
This requires converting the Byte parameter "b" to an Int32. */
Int32 n = b;
while (n > 0)
{
result += (n & 1);
n = n >> 1;
}
return (Byte) result;
}
/* GetBinaryStringAs* methods */
private static Int32 GetBinaryStringAsInt32(String s)
{
return Convert.ToInt32(String.Join("", s.Trim().Where(c => (c == '0') || (c == '1'))), 2);
}
private static UInt64 GetBinaryStringAsUInt64(String s)
{
return Convert.ToUInt64(String.Join("", s.Trim().Where(c => (c == '0') || (c == '1'))), 2);
}
/* GetAsBinaryString methods. */
private static String GetAsBinaryString_Helper(Byte[] bytes)
{
/* The order of the bytes returned by System.BitConverter.GetBytes()
depends on the CPU architecture. The returned byte array
will round-trip with other BitConverter methods, like its
ToInt32() method. But those same bytes will not round-trip
with any of the System.Convert methods, like ToInt32(String, Int32).
The System.Convert.To* methods expect the order of the bytes they
receive to be the *reverse* of the order returned by
System.BitConverter.GetBytes().
The value returned by this method can - after stripping off the spaces -
be fed into a System.Convert.To*() method.
For example, this round-trip test should print "True":
// Hi byte Lo byte
Int32 n = 257; // 00000000 00000000 00000001 00000001
Console.WriteLine(GetBinaryStringAsInt32(GetAsBinaryString(n)) == n);
*/
return String.Join(" ", bytes.Reverse().Select(b => GetAsBinaryString(b)));
}
private static String GetAsBinaryString(Int32 n)
{
/* Note that signed integers use two's complement
binary representation for negative numbers.
For example, calling this method with a parameter
of -42 returns this string:
11111111 11111111 11111111 11010110
*/
return GetAsBinaryString_Helper(BitConverter.GetBytes(n));
}
private static String GetAsBinaryString(UInt64 n)
{
return GetAsBinaryString_Helper(BitConverter.GetBytes(n));
}
private static String GetAsBinaryString(Byte n)
{
return Convert.ToString(n, 2).PadLeft(8, '0');
}
}
}
I have buffer (array) full of audio data, filled with AudioRecord method.
I want play this reversed. When I try to reverse the buffer I just get noise.
public void startWriteAndPlayProcess (){
writeAudio();
playAudio();
}
private void writeAudio(){
audioTrack.write(reverseArray(audioBuffer), 0, bufferSize);
}
private void playAudio(){
audioTrack.play();
}
private byte [] reverseArray ( byte array []){
byte [] array1 = new byte [array.length];
for (int i=0; i<array1.length; i++){
array1[i]= array[array1.length-1-i];
}
return array1;
}
What You people can recomend?
The underlying audio samples are actually an array of shorts (16-bit) or ints (24 or 32-bit). If you just reverse the raw byte array then you are putting the least significant byte on the top and this will make your signal sound like noise. To get it to work properly you need to first convert the byte array to an array of the proper type, reverse that, and then convert it back into a byte array.
private void writeAudio()
{
short[] shortArray = toShortArray(audioBuffer);
short[] reversedShortArray = reverseArray(shortArray);
byte[] reversedByteArray = toByteArray(reversedShortArray);
audioTrack.write(reversedByteArray, 0, bufferSize);
}
private short[] toShortArray(byte[] byteArray)
{
short[] shortArray = new short[byteArray.length / 2];
for (int i = 0 ; i < shortArray.length; i)
{
shortArray[i] = (short)((short)byteArray[i*2] | (short)(byteArray[i*2 + 1] << 8));
// alternatively - depending on the endianess of the data:
// shortArray[i] = (short)((short)byteArray[i*2] << 8 | (short)(byteArray[i*2 + 1]));
}
return shortArray;
}
Of course you'll have to change the type of reverseArray. I'll leave it up to you to figure out how to go back to bytes from the short array or to write the int versions of them if that's what you need.
I'm working on my GSM modem (Huawei E171) to send USSD commands.
to do this i use this commands at the first:
AT+CMGF=1
AT+CSCS=? ----> result is "IRA" this is my modem default
after that i sent these commands and i have got these results and everything works fine.
//*141*1# ----->to check my balance
+CUSD:
0,"457A591C96EB40B41A8D0692A6C36C17688A2E9FCB667AD87D4EEB4130103D
0C8281E4753D0B1926E7CB2018881E06C140F2BADE5583819A4250D24D2FC
BDD653A485AD787DD65504C068381A8EF76D80D2287E53A55AD5653D554
31956D04",15
//*100# ----> this command give me some options to charge my mobile
+CUSD:
1,"06280627062C06470020062706CC06310627064606330644000A0030002E062E0
63106CC062F00200634062706310698000A0031002E067E062706330627063106A
F0627062F000A0032002E0622067E000A0033002E06450644062A000A003
4002E06330627064506270646000A0035002E067E0627063106330
6CC06270646000A002300200028006E0065007800740029000A",72
i found some codes to decode these result:
to decode checking balance result i used:
string result141="457A591C96EB40B41A8D0692A6C36C17688A......."
byte[] packedBytes = ConvertHexToBytes(result141);
byte[] unpackedBytes = UnpackBytes(packedBytes);
//gahi in kar mikone gahi balkaee nafahmidam chera
string o = Encoding.Default.GetString(unpackedBytes);
my function's codes are:
public static byte[] ConvertHexToBytes(string hexString)
{
if (hexString.Length % 2 != 0)
return null;
int len = hexString.Length / 2;
byte[] array = new byte[len];
for (int i = 0; i < array.Length; i++)
{
string tmp = hexString.Substring(i * 2, 2);
array[i] =
byte.Parse(tmp, System.Globalization.NumberStyles.HexNumber);
}
return array;
}
public static byte[] UnpackBytes(byte[] packedBytes)
{
byte[] shiftedBytes = new byte[(packedBytes.Length * 8) / 7];
int shiftOffset = 0;
int shiftIndex = 0;
// Shift the packed bytes to the left according
//to the offset (position of the byte)
foreach (byte b in packedBytes)
{
if (shiftOffset == 7)
{
shiftedBytes[shiftIndex] = 0;
shiftOffset = 0;
shiftIndex++;
}
shiftedBytes[shiftIndex] = (byte)((b << shiftOffset) & 127);
shiftOffset++;
shiftIndex++;
}
int moveOffset = 0;
int moveIndex = 0;
int unpackIndex = 1;
byte[] unpackedBytes = new byte[shiftedBytes.Length];
//
if (shiftedBytes.Length > 0)
{
unpackedBytes[unpackIndex - 1] =
shiftedBytes[unpackIndex - 1];
}
// Move the bits to the appropriate byte (unpack the bits)
foreach (byte b in packedBytes)
{
if (unpackIndex != shiftedBytes.Length)
{
if (moveOffset == 7)
{
moveOffset = 0;
unpackIndex++;
unpackedBytes[unpackIndex - 1] =
shiftedBytes[unpackIndex - 1];
}
if (unpackIndex != shiftedBytes.Length)
{
// Extract the bits to be moved
int extractedBitsByte = (packedBytes[moveIndex] &
_decodeMask[moveOffset]);
// Shift the extracted bits to the proper offset
extractedBitsByte =
(extractedBitsByte >> (7 - moveOffset));
// Move the bits to the appropriate byte
//(unpack the bits)
int movedBitsByte =
(extractedBitsByte | shiftedBytes[unpackIndex]);
unpackedBytes[unpackIndex] = (byte)movedBitsByte;
moveOffset++;
unpackIndex++;
moveIndex++;
}
}
}
// Remove the padding if exists
if (unpackedBytes[unpackedBytes.Length - 1] == 0)
{
byte[] finalResultBytes = new byte[unpackedBytes.Length - 1];
Array.Copy(unpackedBytes, 0,
finalResultBytes, 0, finalResultBytes.Length);
return finalResultBytes;
}
return unpackedBytes;
}
but to decode second result i used:
string strHex= "06280627062C06470020062706CC06310......";
strHex = strHex.Replace(" ", "");
int nNumberChars = strHex.Length / 2;
byte[] aBytes = new byte[nNumberChars];
using (var sr = new StringReader(strHex))
{
for (int i = 0; i < nNumberChars; i++)
aBytes[i] = Convert.ToByte(
new String(new char[2] {
(char)sr.Read(), (char)sr.Read() }), 16);
}
string decodedmessage= Encoding.BigEndianUnicode.
GetString(aBytes, 0, aBytes.Length);
both of theme works current but why i should different decoding way to decode these results?
from where i can find, i should use which one of these two types of decoding?
USSD command responses +CUSD unsolicited responses are formatted as follows:
+CUSD: <m>[<str_urc>[<dcs>]]
Where "m" is the type of action required, "str_urc" is the response string, and "dcs" is the response string encoding.
This quote is from a Siemens Cinterion MC55i manual but applies generally to other modem manufacturers:
If dcs indicates that GSM 03.38 default alphabet is used TA converts GSM alphabet into current TE character
set according to rules of GSM 07.05 Annex A. Otherwise in case of invalid or omitted dcs conversion of
str_urc is not possible.
USSD's can be sent in 7-Bit encoded format or UC2 hence when looking at your two example responses you can see either a DCS of 15 or 72.
GSM 03.38 Cell Broadcast Data Coding Scheme in integer format (default 15). In case of an invalid or omitted
dcs from the network side (MT) will not be given out.
So if you get a DCS of 15 then it is 7-Bit encoded. And if it's 72 then it will be UC2. So from this you can easily select either your first decoding routine or second.
Im want to control MCP2200 in linux.
I found Text Link and set everything.
For example:
I type in console
GP3-1
It will sets pin 3 to 1. But i dont know what to type in console
for controlling the mcp2200 you will need a program doing the stuff for you.
The USBtoUART didn't work for me, maybe you'll have to do some coding yourself - but you can use it to understand how to connect to the mcp2200 hid.
For controlling the IOs, just set up a 16-byte array, filled with the data described here:
http://ww1.microchip.com/downloads/en/DeviceDoc/93066A.pdf
If you want to control some more stuff but gpios, you'll have to do some more - it is possible to control more than just the gpios of the mcp2200 from linux.
I did a little usb trace of the communication of the windows config tool, extracted some informations and - tadaah, there you go with your own pID/vID, Manufacturer and Product strings.
Note: you'll probably need the HIDAPI MikeF was talking about.
First of all, some definitions:
// NOTE: max. string length for manufacturer / product string is 63 bytes!!
// from usb trace of mcp2200 config tool
#define MCP2200_SECRET_CONFIGURE 0x01
#define MCP2200_CFG_PID_VID 0x00
#define MCP2200_CFG_MANU 0x01
#define MCP2200_CFG_PROD 0x02
... and some variables:
unsigned char **mcp2200_manu_string;
unsigned char **mcp2200_prod_string;
The output message for manufacturer string looks like
/* configure manufacturer string (16 x 16 bytes):
* output buffer:
* #0: [01 01 00 16 03 58 00 4B 00 72 00 FF FF FF FF FF]
* | | | | | | | | | | | +-----------+--> Always FF
* | | | | | | +-----+-----+-----------------> Always 00
* | | | | | +-----+-----+--------------------> First 3 Chars of Manufacturer Name / Product Name
* | | | | +-----------------------------------> In #0: 0x03, After #0: 0x00
* | | | +--------------------------------------> (Length (Manufacturer Name) * 2) + 2 (after #0: chars of manufacturer name)
* | | +-----------------------------------------> Counter 0x00 .. 0x0F
* | +--------------------------------------------> MCP2200 Config Bit (MCP2200_CFG_MANU / PROD / VID_PID)
* +-----------------------------------------------> MCP2200_SECRET_CONFIGURE from usb trace
*/
if you put all this in a function, it could look like this:
void prepare_cfg_strings (char* manu, char* prod) {
char manuStr[64];
char prodStr[64];
unsigned int i, k = 0;
unsigned char tmp = 0;
memset (manuStr, 0x00, sizeof(manuStr));
memset (prodStr, 0x00, sizeof(prodStr));
// allocate mcp2200_{manu,prod}_string buffer, 2-dim array with 16 x 16 chars
if (( mcp2200_manu_string = ( unsigned char** )malloc( 16*sizeof( unsigned char* ))) == NULL ) {
// error
}
if (( mcp2200_prod_string = ( unsigned char** )malloc( 16*sizeof( unsigned char* ))) == NULL ) {
// error
}
for ( i = 0; i < 16; i++ )
{
if (( mcp2200_manu_string[i] = ( unsigned char* )malloc( 16 )) == NULL ) {
/* error */
}
if (( mcp2200_prod_string[i] = ( unsigned char* )malloc( 16 )) == NULL ) {
/* error */
}
/* init the rows here */
memset (mcp2200_manu_string[i], 0x00, sizeof(&mcp2200_manu_string[i]));
memset (mcp2200_prod_string[i], 0x00, sizeof(&mcp2200_prod_string[i]));
}
// manuStr holds (strlen(manuStr) * 2) + 2 in byte[0] and manufacturer string from byte[1] on
strcpy (&manuStr[1], manu);
manuStr[0] = ((strlen (&manuStr[1]) * 2) + 2);
// prodStr holds (strlen(prodStr) * 2) + 2 in byte[0] and product string from byte[1] on
strcpy (&prodStr[1], prod);
prodStr[0] = ((strlen (&prodStr[1]) * 2) + 2);
// build manufacturer / product strings
for (i=0, k=0; i<16; i++, k+=4) {
if (i==0) {
tmp = 0x03;
} else {
tmp = 0x00;
}
// manufacturer string
mcp2200_manu_string[i][0] = MCP2200_SECRET_CONFIGURE;
mcp2200_manu_string[i][1] = MCP2200_CFG_MANU;
mcp2200_manu_string[i][2] = i;
mcp2200_manu_string[i][3] = manuStr[k];
mcp2200_manu_string[i][4] = tmp;
mcp2200_manu_string[i][5] = manuStr[k+1];
mcp2200_manu_string[i][6] = 0x00;
mcp2200_manu_string[i][7] = manuStr[k+2];
mcp2200_manu_string[i][8] = 0x00;
mcp2200_manu_string[i][9] = manuStr[k+3];
mcp2200_manu_string[i][10] = 0x00;
mcp2200_manu_string[i][11] = 0xff;
mcp2200_manu_string[i][12] = 0xff;
mcp2200_manu_string[i][13] = 0xff;
mcp2200_manu_string[i][14] = 0xff;
mcp2200_manu_string[i][15] = 0xff;
// product string
mcp2200_prod_string[i][0] = MCP2200_SECRET_CONFIGURE;
mcp2200_prod_string[i][1] = MCP2200_CFG_PROD;
mcp2200_prod_string[i][2] = i;
mcp2200_prod_string[i][3] = prodStr[k];
mcp2200_prod_string[i][4] = tmp;
mcp2200_prod_string[i][5] = prodStr[k+1];
mcp2200_prod_string[i][6] = 0x00;
mcp2200_prod_string[i][7] = prodStr[k+2];
mcp2200_prod_string[i][8] = 0x00;
mcp2200_prod_string[i][9] = prodStr[k+3];
mcp2200_prod_string[i][10] = 0x00;
mcp2200_prod_string[i][11] = 0xff;
mcp2200_prod_string[i][12] = 0xff;
mcp2200_prod_string[i][13] = 0xff;
mcp2200_prod_string[i][14] = 0xff;
mcp2200_prod_string[i][15] = 0xff;
}
}
Call this function in your main loop:
prepare_cfg_strings ("MyManufacturerName, "MyProductName");
Open a hid handle to your mcp2200 and put this stuff on the bus:
// write manufacturer string configuration to usb device
for (i=0; i<16; i++) {
hid_write (handle, mcp2200_manu_string[i], 16);
}
// write product string configuration to usb device
for (i=0; i<16; i++) {
hid_write (handle, mcp2200_prod_string[i], 16);
}
If you want to flash the mcp2200 with your own VendorID / ProductID configure your message:
// Microchip VID: 0x04d8
// MCP2200 PID: 0x00df
mcp2200_pid_vid_cfg[] = 01 00 D8 04 DF 00 00 00 00 00 00 00 00 00 00 00
| | +---+ +---+--------------------------------> Product ID (bytes swapped)
| | +--------------------------------------> Vendor ID (bytes swapped)
| +--------------------------------------------> MCP2200 Config Bit (MCP2200_CFG_VID_PID)
+-----------------------------------------------> MCP2200_SECRET_CONFIGURE from usb trace
and put it on the bus:
hid_write (handle, mcp2200_pid_vid_cfg, 16);
Have Fun!
n.
You will not be able to control the GPIO ports from the console/terminal via USB tty...
The USB to serial/UART converter is one of the features of MCP2200, to control the GPIO, you need to send commands via USB & HID driver. to achieve this, you will need the following.
HIDAPI:
https://github.com/signal11/hidapi
USBtoUART:
https://github.com/Miceuz/USBtoUART
USBtoUART requires hid.o from the HIDAPI package.... so start with HIDAPI first...
good luck!
MikeF
ps: I made a few modifications to the code, to accept binary format for controlling the GPIO ports, etc... it has been compiled fine on x86 and ARM ( Raspberry Pi )
What is the most portable and "right" way to do conversion from extended precision float (80-bit value, also known as long double in some compilers) to double (64-bit) in MSVC win32/win64?
MSVC currently (as of 2010) assumes that long double is double synonym.
I could probably write fld/fstp assembler pair in inline asm, but inline asm is not available for win64 code in MSVC. Do I need to move this assembler code to separate .asm file? Is that really so there are no good solution?
Just did this in x86 code...
.686P
.XMM
_TEXT SEGMENT
EXTRN __fltused:DWORD
PUBLIC _cvt80to64
PUBLIC _cvt64to80
_cvt80to64 PROC
mov eax, dword ptr [esp+4]
fld TBYTE PTR [eax]
ret 0
_cvt80to64 ENDP
_cvt64to80 PROC
mov eax, DWORD PTR [esp+12]
fld QWORD PTR [esp+4]
fstp TBYTE PTR [eax]
ret 0
_cvt64to80 ENDP
ENDIF
_TEXT ENDS
END
If your compiler / platform doesn't have native support for 80 bit floating point values, you have to decode the value yourself.
Assuming that the 80 bit float is stored within a byte buffer, located at a specific offset, you can do it like this:
float64 C_IOHandler::readFloat80(IColl<uint8> buffer, uint32 *ref_offset)
{
uint32 &offset = *ref_offset;
//80 bit floating point value according to the IEEE-754 specification and the Standard Apple Numeric Environment specification:
//1 bit sign, 15 bit exponent, 1 bit normalization indication, 63 bit mantissa
float64 sign;
if ((buffer[offset] & 0x80) == 0x00)
sign = 1;
else
sign = -1;
uint32 exponent = (((uint32)buffer[offset] & 0x7F) << 8) | (uint32)buffer[offset + 1];
uint64 mantissa = readUInt64BE(buffer, offset + 2);
//If the highest bit of the mantissa is set, then this is a normalized number.
float64 normalizeCorrection;
if ((mantissa & 0x8000000000000000) != 0x00)
normalizeCorrection = 1;
else
normalizeCorrection = 0;
mantissa &= 0x7FFFFFFFFFFFFFFF;
offset += 10;
//value = (-1) ^ s * (normalizeCorrection + m / 2 ^ 63) * 2 ^ (e - 16383)
return (sign * (normalizeCorrection + (float64)mantissa / ((uint64)1 << 63)) * g_Math->toPower(2, (int32)exponent - 16383));
}
This is how I did it, and it compiles fine with g++ 4.5.0. It of course isn't a very fast solution, but at least a functional one. This code should also be portable to different platforms, though I didn't try.
I've just written this one. It constructs an IEEE double number from IEEE extended precision number using bit operations. It takes the 10 byte extended precision number in little endian format:
typedef unsigned long long uint64;
double makeDoubleFromExtended(const unsigned char x[10])
{
int exponent = (((x[9] << 8) | x[8]) & 0x7FFF);
uint64 mantissa =
((uint64)x[7] << 56) | ((uint64)x[6] << 48) | ((uint64)x[5] << 40) | ((uint64)x[4] << 32) |
((uint64)x[3] << 24) | ((uint64)x[2] << 16) | ((uint64)x[1] << 8) | (uint64)x[0];
unsigned char d[8] = {0};
double result;
d[7] = x[9] & 0x80; /* Set sign. */
if ((exponent == 0x7FFF) || (exponent == 0))
{
/* Infinite, NaN or denormal */
if (exponent == 0x7FFF)
{
/* Infinite or NaN */
d[7] |= 0x7F;
d[6] = 0xF0;
}
else
{
/* Otherwise it's denormal. It cannot be represented as double. Translate as singed zero. */
memcpy(&result, d, 8);
return result;
}
}
else
{
/* Normal number. */
exponent = exponent - 0x3FFF + 0x03FF; /*< exponent for double precision. */
if (exponent <= -52) /*< Too small to represent. Translate as (signed) zero. */
{
memcpy(&result, d, 8);
return result;
}
else if (exponent < 0)
{
/* Denormal, exponent bits are already zero here. */
}
else if (exponent >= 0x7FF) /*< Too large to represent. Translate as infinite. */
{
d[7] |= 0x7F;
d[6] = 0xF0;
memset(d, 0x00, 6);
memcpy(&result, d, 8);
return result;
}
else
{
/* Representable number */
d[7] |= (exponent & 0x7F0) >> 4;
d[6] |= (exponent & 0xF) << 4;
}
}
/* Translate mantissa. */
mantissa >>= 11;
if (exponent < 0)
{
/* Denormal, further shifting is required here. */
mantissa >>= (-exponent + 1);
}
d[0] = mantissa & 0xFF;
d[1] = (mantissa >> 8) & 0xFF;
d[2] = (mantissa >> 16) & 0xFF;
d[3] = (mantissa >> 24) & 0xFF;
d[4] = (mantissa >> 32) & 0xFF;
d[5] = (mantissa >> 40) & 0xFF;
d[6] |= (mantissa >> 48) & 0x0F;
memcpy(&result, d, 8);
printf("Result: 0x%016llx", *(uint64*)(&result) );
return result;
}
Played with the given answers and ended up with this.
#include <cmath>
#include <limits>
#include <cassert>
#ifndef _M_X64
__inline __declspec(naked) double _cvt80to64(void* ) {
__asm {
// PUBLIC _cvt80to64 PROC
mov eax, dword ptr [esp+4]
fld TBYTE PTR [eax]
ret 0
// _cvt80to64 ENDP
}
}
#endif
#pragma pack(push)
#pragma pack(2)
typedef unsigned char tDouble80[10];
#pragma pack(pop)
typedef struct {
unsigned __int64 mantissa:64;
unsigned int exponent:15;
unsigned int sign:1;
} tDouble80Struct;
inline double convertDouble80(const tDouble80& val)
{
assert(10 == sizeof(tDouble80));
const tDouble80Struct* valStruct = reinterpret_cast<const tDouble80Struct*>(&val);
const unsigned int mask_exponent = (1 << 15) - 1;
const unsigned __int64 mantissa_high_highestbit = unsigned __int64(1) << 63;
const unsigned __int64 mask_mantissa = (unsigned __int64(1) << 63) - 1;
if (mask_exponent == valStruct->exponent) {
if(0 == valStruct->mantissa) {
return (0 != valStruct->sign) ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity();
}
// highest mantissa bit set means quiet NaN
return (0 != (mantissa_high_highestbit & valStruct->mantissa)) ? std::numeric_limits<double>::quiet_NaN() : std::numeric_limits<double>::signaling_NaN();
}
// 80 bit floating point value according to the IEEE-754 specification and
// the Standard Apple Numeric Environment specification:
// 1 bit sign, 15 bit exponent, 1 bit normalization indication, 63 bit mantissa
const double sign(valStruct->sign ? -1 : 1);
//If the highest bit of the mantissa is set, then this is a normalized number.
unsigned __int64 mantissa = valStruct->mantissa;
double normalizeCorrection = (mantissa & mantissa_high_highestbit) != 0 ? 1 : 0;
mantissa &= mask_mantissa;
//value = (-1) ^ s * (normalizeCorrection + m / 2 ^ 63) * 2 ^ (e - 16383)
return (sign * (normalizeCorrection + double(mantissa) / mantissa_high_highestbit) * pow(2.0, int(valStruct->exponent) - 16383));
}