203 Commits

Author SHA1 Message Date
Kévin Redon
b149ea3039 cardem: ignore set ATR
the PPS procedure with baud rate change has not been tested.
by keeping the default ATR instead of applying the ATR sent by
the host software, no other baud rate choice is offered.

Change-Id: Ibf7c6b83d2cf68172c7aa25116d838e24a95d5fe
2019-09-24 17:48:33 +02:00
Kévin Redon
6b0afb3761 cardem: fix TPDU state check
this change allows to initialize the TPDU state while in
ISO_S_WAIT_TPDU, before actually entering ISO_S_TPDU

Change-Id: I505d3add32a43de31499b800bc53442f99f65931
2019-09-24 17:45:16 +02:00
Kévin Redon
90abc09cf3 cardem: ensure VCC_PHONE is floating
this change is mainly relevant for the SIMtrace board, but also
affects the others.
First we ensure VCC_PHONE is not forwarded to VCC_SIM because the
card could affect the signal (card could draw too much current or
feed back current in).
next we disable VCC_SIM. the card slot does not need to be
powered, and the FPF2019 leaks current back to VCC_PHONE, even
with forwarding disabled (the reverse current protection only
kicks in when VCC_PHONE is briefly shorted to ground, but still
leaks 0.6V).
enable the ADC channels normally used to measure VCC, even if
not used. the dedicated ADC pins leak current when left
unconfigured. enabling them puts them in high impedance.

Change-Id: If1487c1c191838aaa08b654e49cd31c7180ffc19
2019-07-18 18:50:58 +02:00
Kévin Redon
76c2eebae2 cardem: use USART timeout for waiting time
the reset/ATR handling has been heavily updated/fixed.
instead of using the timer counter peripheral to handle
the waiting time and corresponding timeout, the USART peripheral
internal timeout mechanism is used.
this is particularly important for the SIMtrace board since the
clock signal is not connected to the timer counter.
thus this change adds card emulation support for SIMtrace boards.

Fi and Di have been properly rename to F and D since the "i"
stands only for an "indicated" value, not the actual value.
this does not change the USB protocol (the variable have just been
renamed).
additional variables store more information about the card
capabilities

NOTE: it has only be tested for the SIMtrace board

Change-Id: Ibcb2c8cace9137695adf5fb3de43566f7cfb93b5
2019-07-18 16:10:34 +02:00
Kévin Redon
e3d516745d make: only compile source for corresponding app
since simtrace supports multiple application, but currently not
at the same time, the feature support is not app specific

Change-Id: I98ff92450cc2a247b294d2e15df171f3fe7c5156
2019-06-13 17:30:41 +02:00
Kévin Redon
0cbe9a4fb6 cardem: currently simtrace does not support cardem
the SIMtrace board does not support the current card emulation
application because this uses a timer counter to handle the
timeouts, but on the SIMtrace board this is not connected to the
CLK signal

Change-Id: Idd09ea534179f0ede705573e1373dbd045c9828a
2019-06-13 17:17:43 +02:00
Kévin Redon
1a88fd8066 use simplest ATR
this is the shortest and simplest ATR possible according to the
ISO 7816-3 spec.
it does not offer any non-default parameters (F, D, WI, ...)

Change-Id: I4ff41b5120bcadca652296f9d3691f7606be2bd2
2019-05-15 00:23:31 +02:00
Kévin Redon
73d4d49b83 minor: ignore usbstring binary
Change-Id: I18fc3179f8b7f3f1272d26853007876156fc1e03
2019-05-14 23:56:07 +02:00
Kévin Redon
558f25237e make sim switch board specific
the simtrace board uses a bus switch not used on qmod and owhw to
switch the SIM between physical and virtual

Change-Id: Ieaf2ed4761fc3e04f33f9aac5c04a768c9a6f71e
2019-05-14 23:39:42 +02:00
Kévin Redon
7fd7674577 minor add comments
this is just to better understand the flow

Change-Id: I045286836176da729cc8c863866d6f6aa3836592
2019-05-14 23:32:55 +02:00
Kévin Redon
7a060da30f rename PIN_PHONE_IO to PIN_USIM1_IO
this matches the naming scheme used for USIM2

Change-Id: I486b14260faec897e8c8698c4b7987bf36492497
2019-05-14 23:23:47 +02:00
Kévin Redon
5b2ade08dd better detect VCC and nRST changes
monitoring the state changes of the VCC and nRST lines is required
to correctly detect warm and cold reset

Change-Id: I72099956332724f84226e1495fdc5a5b1a034695
2019-05-14 23:20:26 +02:00
Kévin Redon
6470d999b7 add ISO 7816-3 library to remsim project
Change-Id: I99f3fecbc00d2379c3a6dc457b047c6fee41c292
2019-05-14 21:56:45 +02:00
Kévin Redon
46a1f167f7 add library providing ISO 7816-3 utilities
this will become part of libosmocore since it it common to smart
card related projects (such as osmo-ccid-firmware)

Change-Id: I3d4c65d137fc4555fcb256443feadd1c695de73d
2019-05-14 21:50:45 +02:00
Kévin Redon
0954e3b283 minor : fix typo in comment
Change-Id: Ie310143fe713a51fa1adf8bf7599374282341f2e
2019-05-14 21:26:48 +02:00
Kévin Redon
c2a3836777 minor: improve debug output
Change-Id: Ibfc22b95c0be3ac78bd50a40e31cc7d8546d81d9
2019-02-07 18:20:20 +01:00
Kévin Redon
a2b2df235a remsim: use simplest ATR
this ATR does not encode any data and uses all defaults.
the lower default speed is also better handled by the hardware.
handling faster speeds is upcoming.

Change-Id: I5a4f2f94bea1a15aedbef5a6f2f49344387dc11d
2019-02-07 18:01:23 +01:00
Kévin Redon
af7544aa9d minor: move USB debug output from info to debug level
else it's too nosy while debugging other components, not often
used, and break the flow since it does not and a line.

Change-Id: I8920ff7c33b4c9fb174bb31a29334a63fcbede43
2019-02-07 17:58:26 +01:00
Kévin Redon
f6f507ab3c minor: make debug output only verbose in info level
the longer output is to fast and often incomplete.
the shorter version is enough to view the progress when not
debugging.

Change-Id: I97bb84da68d1f3bc14fb7c05400edf1748f55460
2019-02-07 17:55:28 +01:00
Kévin Redon
844c6608cf minor: use same LED pattern for cardem as other opplications
Change-Id: I5608c3312b648c0d59f79338ef1f97b6fe08f5b9
2019-02-07 17:53:18 +01:00
Kévin Redon
8ed780ec35 minor: updated copyright years
Change-Id: I9254b1ddf6436b5a4964b9124a36ae17bfc22886
2019-02-07 17:52:08 +01:00
Kévin Redon
ad3414fdf7 minor: fix spacing
Change-Id: I2f3127c7b276c9726fd0242e3e29be22f9d6255c
2019-02-07 17:42:29 +01:00
Kévin Redon
2fdcf3b38d cardem: add more debug information for TPDU state
this just adds the name of the TPDU state on top of the state number.

the ISO state is cleaned up accordingly

Change-Id: Id5104a2c3579dedb092c179748e9ed525673841c
2018-10-25 10:42:33 +02:00
Kévin Redon
7e5cda5732 remsim: fix TPDU response size transmission
the TDPU response data size can be up to 256.
this length cannot be stored in a uint8_t, which would cause the
length to become 0, no data being send, and the reader reset the
card because of misbehaviour of the card (i.e. no/malformed
response leading to the timeout of the waiting time).

Change-Id: Iae7671085aaa3115a02d82530dd7a0e7e2d4155e
2018-10-21 12:29:26 +00:00
Kévin Redon
032fc5f844 remsim: update copyright
Change-Id: Ibcf093877ee53f8446c97bfa50c8370ceda24c53
2018-10-21 12:29:10 +00:00
Kévin Redon
b1f99c909c remsim: add already parsed USB path argument info
Change-Id: I03de93ebb92b1d1b5004cbe865cdf1fa0b2b23ac
2018-10-21 12:29:10 +00:00
Martin Hauke
53b4e593aa Fix compiler warning: no-return-in-nonvoid-function simtrace2_usb.c
RPM post-build-checks found some issue and marks these as error:
[   61s] I: Program returns random data in a function
[   61s] E: simtrace2 no-return-in-nonvoid-function simtrace2_usb.c:88

Change-Id: Id16fb7fc4f13176b2b6443af02a5848d8fcfb069
2018-10-13 22:14:06 +00:00
Harald Welte
dc85fbc3e1 libusb_util.c: Avoid gcc warning about strncpy()
What we're doing is actually legal: We copy the full size of the
destination array, and then overwrite the last byte with NUL.  However,
gcc isn't smart enough to see that:

libusb_util.c:162:5: warning: ‘strncpy’ specified bound 20 equals destination size [-Wstringop-truncation]
     strncpy(out[out_idx].path, path, sizeof(out[out_idx].path));
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Let's copy one byte less to make it happy.

Change-Id: I30ddacdc73e5245c7c38b92d1e94e39b13fae7d3
2018-10-12 15:15:08 +02:00
Harald Welte
66ffb6d493 debian/control: Add dependency to libpcsclite-dev
The host utilities use libpcsclite, and the missing build dependency
causes build failures in our nightly OBS builds since commit
faf1e88e48 was merged:

[  131s] cc -o simtrace2-remsim simtrace2-remsim.o apdu_dispatch.o simtrace2-discovery.o libusb_util.o -Wl,-z,relro `pkg-config --libs libusb-1.0 libosmocore` -pthread `pkg-config --libs libosmosim libpcsclite`
[  131s] Package libpcsclite was not found in the pkg-config search path.
[  131s] Perhaps you should add the directory containing `libpcsclite.pc'
[  131s] to the PKG_CONFIG_PATH environment variable
[  131s] No package 'libpcsclite' found

Change-Id: I29adfc629e5e4ffd0bf8b9035ef9138fe7693d96
2018-09-23 16:59:23 +02:00
Kévin Redon
5b5d24ebf3 owhw: set the right simtrace USB ID in usb2udp
Change-Id: I0b54c2eb98b3fad1e2afaf9b81fbe4518b01fbda
2018-09-08 08:22:56 +02:00
Kévin Redon
faf1e88e48 host: clean library dependencies
remsim also needs libpcsclite
`pkg-config --libs libosmocore` and -losmocore are duplicates
`pkg-config --libs libosmosim` is equivalent to -losmosim
pthread it needed (by most applications) for static compilation
LDFLAGS+= allows static compilation when running
LDFLAGS="-static" make

Change-Id: Ic7bd6f2be074d6f652d4f84f4996c8588ea5f851
2018-09-06 23:15:44 +02:00
Kévin Redon
64f69fc4ac owhw: add missing function board_main_top
the board_main_top function was not defined, causing a hard fault
when initializing the board

Change-Id: Ib92003416648822c4115472992850c592bc4047a
2018-09-06 22:52:45 +02:00
Kévin Redon
6303c39a00 owhw: add missing function board_exec_dbg_cmd
the board_exec_dbg_cmd function was not defined, causing a hard
fault on user input

Change-Id: I3ecc1f7bdb2484f5a67c36163d33ebc065e4e709
2018-09-06 22:51:32 +02:00
Kévin Redon
ad0958e9e3 minor: update copyright
Change-Id: Iafcd029be9b3f8cf2e90f08d5e9802912d6a59b1
2018-09-06 22:49:56 +02:00
Kévin Redon
4f3a0356a4 minor: fix typo in comment
Change-Id: I3edb50abe93bc8574c9c1f25b34f75dab2e8f0ce
2018-09-06 22:48:11 +02:00
Kévin Redon
7d5d011095 minor: add checks on configurations and functions
these checks prevent out of bounds access and running
unset function pointers.

Change-Id: Ida889d40b898fc1ab8b885800431833570fdaafe
2018-09-06 22:47:01 +02:00
Kévin Redon
1dbcf62295 qmod: add LED user control
this is used during board testing

Change-Id: I4ccd787f6e307f523821725de158e3c6f1508ee2
2018-09-04 16:15:15 +02:00
Kévin Redon
e5f891a825 EEPROM: fix Wformat compile warning
Change-Id: I86434a46a75f2acc30e20c33edab6dd3f87e052b
2018-09-04 13:31:26 +02:00
Kévin Redon
a6bd7178b5 qmod: output EEPROM data only on debug level, and add completion output
the EEPROM byte output was causing data loss on the serial output,
resulting is automatic tests failing.
instead an end text will be output to detect the end of the procedure.

Change-Id: Ib8d3cbd01d0e34432d424355f4fafb24bc5273a1
2018-09-03 21:11:44 +02:00
Kévin Redon
ba15387b09 DFU: fix Wformat compile warning
Change-Id: I8c422d8a709f8311c40d37e1f1f01dcd3a199b6f
2018-09-03 21:11:44 +02:00
Kévin Redon
c171112994 stdio: fix detection of malformated format strings
the error code returned by vsnprintf was ignored,
resulting in printing the string from a previous print.

Change-Id: I8506b05d56da55d1357a1234917adf341b46e1db
2018-09-03 21:10:58 +02:00
Kévin Redon
29200c6223 stdio: add void 'l' format string qualifier
Wformat requires uint32_t to be used in format string with the 'l'
qualifier (l = long = at least 32 bits).
this qualifier was not handled before.
since on ARM 32-bit int == long we can simply ignore it (stdio
already does not support 64-bit data).

Change-Id: Ib506a66f68712c6b3eeb5129a39abf47ec86a2a7
2018-08-28 19:43:37 +02:00
Kévin Redon
80d9476602 UART: switch baud rate to 921600 bps
the higher baud rate allows for more debugging (without dropping
data) and is well supported by USB for UART adapters (this
standard baud rate is 8 x 115200).
the closest matching integer value is calculated for UART CR.
no floating point calculation can be used since this would
increase the size of the resulting binary by ~ 2kB (for the
softfp). this is not possible for the DFU since it already is
close to the maximum size of 16 kB.

Change-Id: I82b74f697342d580ccb79ada4715f35f4e8cca86
2018-08-28 19:19:10 +02:00
Kévin Redon
e2b0f971e5 set main clock for using UART at 921600 bps
UART baud rate is main clock (MCK) divided by CR*16.
The MCK values are chosen >= 48 MHz and <= 64 MHz to have a near
integer value CR for a baud rate of 921600 bps.
The end MCK frequency between simtrace and qmod differ slightly
but are close to 58 MHz.

Change-Id: Iaa4a97fc68494c93b9d128503515d88049de506c
2018-08-28 19:13:13 +02:00
Harald Welte
e07640c35a tag debian release 0.5.1
Change-Id: Id6559b1019353815eea9f6653b6560e9a8aab23a
2018-08-26 11:51:13 +02:00
Harald Welte
82b628524f simtrace2-sniff: Fix build with released libosmocore versions
There's still no released libosmocore defining the GSMTAP_TYPE_SIM
sub-types (Change-Id: I5bd0dff5a4a90cfe96d9c4f3dec6657e1d85bf7a
dated Jul 26, 2018).

Let's make sure users don't need an unreleased version of the library
if it's only about a few #defines that we can just copy here for
backwards compatibility.

Change-Id: I2fd9e14873711d60f194bb404420bbfbb0a00f48
2018-08-26 11:43:12 +02:00
Harald Welte
cb78b55c26 Revert "debian/control: Depend on libosmocore >= 0.12.1"
This reverts commit 77ff745cca.

libosmocore 0.12.1 is not recent enough, I misread the 'gitk' output.

Change-Id: I87a8e5bbb4aea0c991abe5372f840d76f17378eb
2018-08-26 11:43:11 +02:00
Harald Welte
77ff745cca debian/control: Depend on libosmocore >= 0.12.1
Only this version includes the GSMTAP_SIM_ATR and GSMTAP_SIM_APDU
definitions.

Change-Id: I988cad56aed755af416fc7f23822dcf0229dbb7d
2018-08-26 10:52:46 +02:00
Harald Welte
bd9d94994d v0.5 debian package release
Change-Id: Iaf56c03f966a5dfc8b750d926f0429223aeec54e
2018-08-26 10:37:39 +02:00
Harald Welte
95fac3aeab Add Debian packaging rules
Change-Id: Iece115e4dde87bff5dc36286668f50de0abdcb9e
2018-08-26 10:20:05 +02:00
Harald Welte
c17bf77ecc owhw: Fix cardem GPIO initialization pointer value
This fixes a bug, identified by the below compiler warning:

libboard/owhw/source/owhw.c: In function 'cardsim_gpio_init':
libboard/owhw/source/owhw.c:39:16: warning: passing argument 1 of 'PIO_Configure' from incompatible pointer type [-Wincompatible-pointer-types]
  PIO_Configure(&pins_cardsim, ARRAY_SIZE(pins_cardsim));
                ^
In file included from ./atmel_softpack_libraries/libchip_sam3s/chip.h:45:0,
                 from libboard/owhw/source/owhw.c:20:
./atmel_softpack_libraries/libchip_sam3s/include/pio.h:189:16: note: expected 'const Pin * {aka const struct _Pin *}' but argument is of type 'const Pin (*)[2] {aka const struct _Pin (*)[2]}'
 extern uint8_t PIO_Configure( const Pin *list, uint32_t size ) ;
                ^~~~~~~~~~~~~

Change-Id: I4c1de66c0b8475bb355b1d128f6ec88b2f2a7fcf
2018-08-26 10:20:05 +02:00
Harald Welte
c394109964 firmware: Enable -Wformat and resolve all related compiler warnings
There have been tons of format-string related bugs in our code which
we never discovered due to disabling -Wformat.  Let's fix that.

Change-Id: I5ec466361bcc526fac1f4897673264ee5af3458b
2018-08-26 10:20:05 +02:00
Harald Welte
888f196595 add master Makefile to build firmware and host tools
Change-Id: I715d3fdaff9d80673bb2208ea9d56637f4e459af
2018-08-26 10:20:02 +02:00
Harald Welte
f7f61cd10f Makefiles: Add "make install" target
Change-Id: Ic6835ce55930c60f909e140878c4abab8628e077
2018-08-26 10:09:43 +02:00
Harald Welte
0e95f53588 host: Fix "make clean": remove simtrace2-sniff
Change-Id: Ib233b6a4b3976286196da95036cadcf2d3382f77
2018-08-26 09:54:55 +02:00
Kévin Redon
76ef811a4e jenkins: add simtrace/trace to the builds
trace is now stable enough on simtrace to be built and uploaded.

Change-Id: I157fff9930d03a7ec52ecac4a1be0511ea66c010
2018-08-07 19:01:25 +02:00
Kévin Redon
fecfa2aa51 jenkins: clean after upload
the upload failed because after the firmware were built (make),
they where removed (make clean).
now they are removed only after the upload.

Change-Id: Ie4421a6fa9207eb541107de9c14f265626f6be96
2018-08-07 17:51:48 +02:00
Kévin Redon
c428516efa qmod: error on EEPROM erase fail
repeating the EEPROM erase (byte write) in case of byte write failure
could lead in an infinite loop.
log the error an return error code instead.

Change-Id: Id6f3654d877ca772ba04237da91a6e86e3f441ec
2018-08-07 15:14:37 +00:00
Kévin Redon
37e7861c4d jenkins: fix publish
the script argument was not saved in the publish variable used later
to decide if publishing/uploading is needed.

Change-Id: Ic768a8e96e5e4d72acf3979da1412d683f79ec55
2018-08-07 12:09:49 +02:00
Kévin Redon
ff3d84922d USB: increase USB reset time
USB reset can be signaled by pulling low USB D+ for at least 10 ms,
according to the USB specification. This force a re-enumeration.
This time is increased to 20 ms to work with more USB HUBs.

Some SAM3S based board have external D+ pull-up mechanism (such as
SIMtrace) which needs to be used to pull D+ low.
This is a legacy mechanism from SAM7S history.
This mechanism is not required anymore on the SAM3S, and the qmod
does not use it. When the USB HAL is suspended, the transceiver is
disabled, causing D+ and D- to be pulled low. Then the HAL is activated
again. This is particularly required when DFU is started (and
enumerated), and after flashing the SAM3S switched to the main
application (without reset), so it can properly re-enumerate.

This board difference is now defined on the board header.

Change-Id: I9b58d8101c2fcf5595026b675728826af26127a3
2018-08-07 12:09:49 +02:00
Harald Welte
9547e419eb qmod: Add 'e' command for erasing the EEPROM
Change-Id: Id7cb0db568dd3e9d796829bf0019d63048612998
2018-08-07 10:00:49 +00:00
Kévin Redon
8daba9cc9a gcc: fix warning
moving the define after the header fixes the following warning:
                 from ./atmel_softpack_libraries/libchip_sam3s/source/exceptions.c:46:
libcommon/include/stdio.h:63:12: warning: redundant redeclaration of 'printf_sync' [-Wredundant-decls]
 signed int printf_sync(const char *pFormat, ...);
            ^~~~~~~~~~~
./atmel_softpack_libraries/libchip_sam3s/source/exceptions.c:45:16: note: previous declaration of 'printf_sync' was here
 #define printf printf_sync
                ^~~~~~~~~~~
libcommon/include/stdio.h:51:12: note: in expansion of macro 'printf'
 signed int printf(const char *pFormat, ...);

Change-Id: I21a8de325e8f8b91297dd157f2d6a0f64434bb28
2018-08-06 16:23:33 +02:00
Kévin Redon
d5f583da60 jenkins: add build uploads
firmware binaries should be uploaded to
https://ftp.osmocom.org/binaries/simtrace2/firmware/
this directory wiki be documented in the SIMtrace 2 wiki for users
to get the latest firmware images without having to cross-compile
themselves.

Change-Id: I589531f59e54a0997b012bdd91e3bef9f847f517
2018-08-06 15:57:43 +02:00
Kévin Redon
04ccb770fd remsim: fix USB hanging USB transfer
After a couple of seconds of USB data exchange between remsim and
cardem, the USB transfer hangs.
On host side (remsim) I can see the USB BULK IN request.
On device side (cardem) I see that data has been submitted and
"sent" over USB, but on wireshark with USBmon I don't see the
corresponding USB BULK IN response.
When exiting remsim or just after powering of qmod (causing an
error in remsim) the USB BULK IN is show in wireshark. Thus it
must have been in a buffer, but not read by libusb_bulk_transfer.
By shortening the timeout a new libusb_bulk_transfer is made more
frequently, and the data gets read successfully.

T;his change also fixes the URB data display.

Change-Id: I1d124a41cc90893506933f6d76dc7331e52a74f9
2018-08-04 11:16:15 +02:00
Kévin Redon
910e6830b9 cardem (minor): trace tx data send over USB
Change-Id: I69cef43dd5a78e9f82cc045cdb90c326b03d1f68
2018-08-04 11:16:15 +02:00
Kévin Redon
9cccb2bab5 add libosmcore utilities
osmo_hexdump is particularly useful.
previously it was only defined, but not implemented.
this cause random behaviour upon call, often resulting in
memory corruption.

Change-Id: Ifd9120fa951f41693903fb657d10826959f1599f
2018-08-04 11:16:15 +02:00
Kévin Redon
8a4fba5ea2 cardem: add state name in trace
this helps reading the output while debugging quite a lot

Change-Id: Idf301e09cf14e2412e29dcb252563bc6e4e5c630
2018-08-04 11:16:15 +02:00
Kévin Redon
1b39fd31ee cardem (minor): remove to verbose log trace
Change-Id: Ie43a33af3728c0700f71527ca75d909a9ebd2529
2018-08-04 11:16:15 +02:00
Kévin Redon
0f4abf5eaa cardem: minor typo fix in comment
Change-Id: Ib1dee95e15db1c6bb3b45920d7c1a567e2ba474b
2018-08-04 11:16:15 +02:00
Kévin Redon
1836ac0761 add synchronous UART transmission and use it in exceptions
The default ISR (particularly the HardFault handler) print information,
but this information was not displayed on the console because the UART
IRQ is lower than some default blocking IRQ.
Allowing to set synchronous transfer corrects this.

The underlying Atmel exception library had to be modified to use the
synchronous output.

Making UART_PutChar always synchronous when called from an ISR is not
desired because we use TRACE_ macros is some ISR. The synchronous
output must be set explicitly.

Change-Id: I1b4ace5185cf2dc32684934ed12bf6a8682e9bad
2018-08-04 11:16:13 +02:00
Kévin Redon
dd36d9b010 sniff: send incomplete TPDU when reset is asserted
Change-Id: I8d7e4d604cded535e40d27c2be872268e0f24c20
2018-08-01 10:35:55 +02:00
Kévin Redon
8b8e58b00e cardem: use TC2 as WI and update WT after ATR
Change-Id: I3e51b16d557bc664f87563e1a3dce6642de474d2
2018-07-30 18:19:11 +02:00
Kévin Redon
8f70c3eb1f remsim: fix payload overwriting
The slot number is in the header, and correctly set in st_push_hdr.
Setting the slot in st_slot_tx_msg will overwrite the payload data.
This caused bytes three of the ATR to be changed from 0x96 to 0x00,
corrupting the ATR. This corruption is caught by the ATR checksum,
and the modem would reset the card (2 additional times) to try to
get correct ATR.

Change-Id: If971699993617fc50557d20582c344ea06645a3f
2018-07-30 15:03:55 +02:00
Kévin Redon
ebe672e926 cardem: use TC_ETU to trigger ATR sending
this changes how ATR is handled.
the ATR is also printed when set (as important debug information).
the test is also updated to correspond to the new mechanism (
simulating the timeout before sending the ATR)

Change-Id: I69df797e2feadffa9f5f977cb71b69386cee7cd0
2018-07-30 15:02:35 +02:00
Kévin Redon
d8ebd6ab77 cardem: increase watchdog to 2 seconds
a lot of the procedures are done in ISRs, but the watchdog is only
reset in the main loop.
this causes frequent reset, particularly at the beginning were
states have to the initialized.

Change-Id: Iad364444fca9d18f9a8cf47d5e0840ccd7bac2ef
2018-07-29 09:58:31 +02:00
Kévin Redon
738a04aefb cardem: show detailed reset cause
this helps detecting when a reset was due to the watchdog

Change-Id: I2d59c2f2c8fe9e559eddfafacf25879263ef81ff
2018-07-29 09:58:31 +02:00
Kévin Redon
2a44dc598d sniff: increase debug output
Change-Id: Ife0bbcf4a25aaa445a36768c00004e6e0d9a4947
2018-07-29 09:58:28 +02:00
Kévin Redon
ec396bf402 sniff: fix ATR checksum calculation
this issue also cause the sent ATR to be empty

Change-Id: I6edff7aeb3185c835656acde75886fb6c90c0582
2018-07-28 20:59:44 +02:00
Kévin Redon
697199676e sniff: ensure the checksum error flag is also printed
the firmware now also use a generic value_string array (as does the
host application)

Change-Id: I861bd8b52e8f2f2a4786bbe1cc834917119dc394
2018-07-28 20:59:41 +02:00
Kévin Redon
8e84f8125c sniff: rename reset hold/release to assert/deassert
this change is to match the nomenclature used in cardem

Change-Id: Ide99e731cad26aec949ad14d54f46fa611a0b7f8
2018-07-26 15:34:08 +02:00
Kévin Redon
d1c6536154 sniff: send ATR over GSMTAP
Change-Id: Id35129883f08002a4a796b56954a128e2b533245
2018-07-26 14:51:15 +02:00
Kévin Redon
352809992c USB: print decoded USB error
In case of error it also ensures the returned value is NULL.
Else a segfault would occur because the caller (e.g. remsim)
continued on with a free handler.

Change-Id: Ie7f20e3eff03acf77eb08283747ca8e032b9b4c8
2018-07-24 09:57:23 +02:00
Kévin Redon
a71a6f48cb I2C: return error after failed write
The previous mechanism of retrying a failed write could become a
infinite blocking loop (until watchdog tiemout).

Also the array size is used to know how much data to write and verify
instead of a constant.

Change-Id: I8d2d090c5f4d1195f4c7eb29b3958a7bb05f56ec
2018-07-24 09:54:18 +02:00
Kévin Redon
57b60d23cf I2C: add wait time after write to let EEPROM write
The Atmel AT24C02 defines a maximum tWR waiting time after a byte
write of 5 ms before a next write.
Enforcing this wait time also fixed the failed verification in qmod,
where it was reading 0xffff instead of the written value.

Change-Id: I42c90b8d0329e425f275067e87d584212a43a90b
2018-07-24 09:49:18 +02:00
Kévin Redon
b60538888f cardem: fix USB message parsing
the msg->l2h pointer was not set but used later on, e.g. in
dispatch_usb_command_cardem, case SIMTRACE_MSGT_DT_CEMU_SET_ATR):
>   case SIMTRACE_MSGT_DT_CEMU_SET_ATR:
>   >   atr = (struct cardemu_usb_msg_set_atr *) msg->l2h;
>   >   card_emu_set_atr(ci->ch, atr->atr, atr->atr_len);
l2h is by default 0, thus not pointing to the actual message l2h.
I wonder how cardem worked worked before with this issue though.

Change-Id: Ifbb53dbf478d8dade82251f769e78e1306e77434
2018-07-18 14:06:23 +02:00
Kévin Redon
680bdaba96 cardem: fix typo
Change-Id: Ibeeb01b21a3ccfa74642f13694a20054e920837e
2018-07-18 14:00:57 +02:00
Kévin Redon
f66af0c640 sniff: add checksum verification for ATR and PPS
a checksum error is only signaled in the USB message with the
corresponding flag.

Change-Id: I277868267c3199eea216ab47bdd09fb2fb944b06
2018-07-11 22:33:16 +02:00
Kévin Redon
5f6b8717a4 fix 'ISO_S_IN_ATR not handled' gcc warning
when building the cardem application GCC would output the following warning:
libcommon/source/card_emu.c: In function 'card_emu_process_rx_byte':
libcommon/source/card_emu.c:764:2: warning: enumeration value 'ISO_S_IN_ATR' not handled in switch [-Wswitch]
  switch (ch->state) {
  ^~~~~~

in card emulation the reader should not send data while the card is
sending its ATR.
this is true for other states already handled (RESET, ...). in
these cases an error message is output.
this behaviour is now the default case as data from the reader is
only expected in 3 cases: ISO_S_WAIT_TPDU, ISO_S_IN_TPDU, and
ISO_S_IN_PTS.

Change-Id: Ifbc8dbe1c9f176343304f211c7e6068fb977961e
2018-07-11 22:24:46 +02:00
Kévin Redon
ac0843af83 make adc2uv common
when building the trace app for the simtrace board gcc was outputing
the following error:
libboard/common/source/boardver_adc.c:20:17: warning: 'adc2uv' defined but not used [-Wunused-function]
 static uint32_t adc2uv(uint16_t adc)

adc2uv is used by qmod, and defined in two places:
in boardver_adc.c and mode_cardemu.c.

this change will have adc2uv only defined in boardver_adc.c and make
available in the header to be used by mode_cardemu.c.

Change-Id: I8a772638fa8dd02d8bc8b7631de5af5a22647c55
2018-07-11 22:24:46 +02:00
Kévin Redon
31ed8029b7 host sniff: add functions to print flags
Change-Id: If3c0a4790662bcc64db5ff03adcc033836e16ad0
2018-07-11 22:24:40 +02:00
Kévin Redon
3b7624c120 host sniff: process remaining usb messages in buffer
Change-Id: I1746c0187b2e5dbef44b4b336fee3bd9ded15079
2018-07-11 22:01:58 +02:00
Kévin Redon
f000831d72 sniffer: fix inverted reset meaning
Change-Id: I860e2e29c059e1e0ec126695bb68d489891a17da
2018-07-11 22:01:58 +02:00
Kévin Redon
b37bda0b55 sniffer: only allocate USB message if queue is not too long
When the host does not retrieved the USB messages, they keep getting
queue in the firmware, filling the RAM, and preventing further memory
to be allocated.

Change-Id: I0e447acdf757dcb5dc5c4d8b84a4235866914cad
2018-07-11 22:01:58 +02:00
Kévin Redon
c6b968067d sniffer: also send malformed message over USB
Change-Id: I124c8db1d2f836e185630bbe8b5e52eb085d702a
2018-07-11 22:01:58 +02:00
Kévin Redon
a95bb1e85d minor: fix linker warning
linker warning:
obj/simtrace/dfu_sniffer.o: In function `usb_send_data':
/media/data/work/simtrace2/simtrace2/firmware/libcommon/source/sniffer.c:338: warning: undefined reference to `putchar'

Change-Id: I934f3fcb474d4046e921511a024c3a0b8533c782
2018-07-11 22:01:58 +02:00
Kévin Redon
da5578bd85 sniffer: set LED pattern
The red and green LEDs are now used as follows:
- red on = power (firmware is running)
- red blink = error detected (e.g. during ISO-7816 parsing)
- green on = running (sniffer mode is running)
- green blink = activity (e.g. USB message sent)

Change-Id: Ib1b6ff87fb92d6ed3ecae4bc89386206aaab508e
2018-07-11 22:01:58 +02:00
Kévin Redon
d975411511 LED: add need pattern
new LED pattern: off for 200 ms and then on

Change-Id: Id2c40dc20d75ed6f38b735164ad1eb2860dc480c
2018-07-11 22:01:58 +02:00
Kévin Redon
a2fccba96c sniffer: move reset handling from ISR to main loop
Change-Id: Ia88fb4baf49017524bb201123da3511e5342ba48
2018-07-11 22:01:58 +02:00
Kévin Redon
411428eb5e sniffer: move data print before USB send
when the host software does not retrieve the USB messages the memory
is filled and no new USB messages can be allocated, preventing the
following code to print the message

Change-Id: Ie8946894a84cb853b45555f7abb1ca6f32111425
2018-07-11 22:01:58 +02:00
Kévin Redon
f82f0f6eff USB: add flags for sniff data and centralise transfer
Also fix issue in usb_msg_alloc_hdr and add cosmetic spaces around
operations.

Change-Id: I768a0ad639aa5e648a630af72d01f7b68082b6b6
2018-07-11 22:01:58 +02:00
Kévin Redon
55f0612c8e cosmetic: put spaces around operations
Change-Id: If5ba5f8d16680e8403944274336ea595017063db
2018-07-11 22:01:58 +02:00
Kévin Redon
33d1eb73fd replace leading spaces with tabs
Change-Id: I86783eba0827b58303b10310e9f6b9625e1a27f1
2018-07-11 22:01:58 +02:00
Kévin Redon
93717e43b3 set linux end of line
Change-Id: I5200f0d6f39b0641cac26a4109a3cd33e8474b9b
2018-07-11 22:01:58 +02:00
Kévin Redon
9a12d68c74 firmware: set license to GPLv2+
Change-Id: Id4c00159f984976b6d8641900fb64e36a3a30407
2018-07-11 22:01:58 +02:00
Kévin Redon
efbcf38afb host: set license to GPLv2+
Change-Id: I0948d74874af1d3a0f1b4cbcb4a838e4ecd9fe3f
2018-07-11 22:01:56 +02:00
Kévin Redon
9918c2840e DFU: use central DFU override check
TRACE_INFO will also provide the DFU start reason, but TRACE_INFO
(TRACE_LEVEL >= 4) should only be used for debugging.
WARNING: With TRACE_LEVEL >= 4 the DFU binary is over the maximum of
16 kiB allocated for the DFU bootloader.
Thus make combined will not boot the main application because its
start if after the expecte 16 kiB address; and flashing using DFU
will overwrite the DFU bootloader itself.

Change-Id: I82323e0f76c03f67df7dc8f2b6783166cc25f3aa
2018-07-11 20:48:24 +02:00
Kévin Redon
d24e9bde26 DFU: re-enable UART after testing forced bootloader
The qmod does not have a separate force button as simtrace has.
Instead it check is TX and RX of UART are shorted using PIO.
If the pins are not set back to the UART peripheral, the TRACE/debug
console output will not work anymore.

Change-Id: Id434b49909d6395a2f93a00f39d2d770a5725466
2018-07-07 14:56:50 +02:00
Kévin Redon
2bdaa73aff UART: remove unused code
PutChar already takes care of enabling the IRQ

Change-Id: I63af5eba27c9a6f3e23412060028e817e4d9f233
2018-07-07 14:53:50 +02:00
Kévin Redon
fcf2743552 UART: make IRQ/ISR enabling simpler
Change-Id: Id3742850eb5bac91559e0c2b4144bd7b1ae5b07b
2018-07-07 14:51:35 +02:00
Kévin Redon
d44cb80bc5 DFU: disable configured console UART before starting main app
The DFU uses the UART peripheral (with IRQ/ISR) for the debug output
console. Before starting the main application we should make sure
this configuration is reset to avoid interference (particularly the
IRQ/ISR).
This is not too important though since the main application
reconfigures the UART for console output.
Other peripheral could also be disabled (e.g. all other PIO used
by DFU), but most of them also get configured by the main application.

Change-Id: I8234d1b85938ad6393094c08183f613ad09ee01b
2018-07-07 14:43:50 +02:00
Kévin Redon
9e29a3eb37 DFU: set stack pointer before starting main app
The stack size is fixed. The linker script puts the stack section
after the bss section. The initial stack pointer is not at the
end of the RAM (as often seen).
Thus the initial stack pointer address of the main application
is different than the one from DFU. When starting the main
application the stack pointer needs to be set to the new value.
If this is not done the main application stack may overwrite the
data in bss, even without exceeding the fixed stack size.

Change-Id: Ie354d603fe302d3d5bdfa9c31575411de722323b
2018-07-07 14:18:58 +02:00
Kévin Redon
bf6b1b1a3e buffer: increase buffer size to 512 to cope with fast and long TPDUs
Change-Id: I194c90cf09306a982d80c5bf1222397af6e658a9
2018-07-04 17:55:20 +02:00
King Kévin
4cbdc7cf18 fix LED switching on/off
In the SIMtrace and QMOD schematics the LEDs are connected to +3.3V.
Thus to switch the LED on we need to set the pin low.

Change-Id: Id8cc27e6f0b6556ba5e7ea4d254dd0fe59042a0c
2018-07-04 17:55:20 +02:00
King Kévin
86f48fc962 minor style change: use ARRAY_SIZE
Change-Id: Ia5243c342535963a3800849cd5a7d183a510d2d6
2018-07-04 17:55:20 +02:00
King Kévin
1200a5228f sniffer: add waiting time WT update
the waiting time (WT) is used to detect timeouts (e.g. for
unresponsive card or just to signal an error/NAK). it is essential
to detect to timeout to end current data transfer (e.g. change state).
by default (after a reset) to timeout is 9600 ETU, but this can change
at two places:
- after the ATR using the value of TC2 (if present)
- after a PPS (only F is used, and not D)

because the timeout value can be larger than the 16-bit of the USART
TO register, an external variable needs to be used for the count down.

Change-Id: I9735660ffce161cec8d4e63fa60a66fc8ef57525
2018-07-04 17:55:20 +02:00
Kévin Redon
fe763b7698 sniffing: decrease USB IRQ prioprity to prevent USART overrun
Handling the USB message queue is done in an ISR and take quite some time.
This can cause a USART/SIM sniffing buffer overrun, resulting in data loss.
By setting the USB IRQ lower than the USART IRQ, the USB ISR can be
interrupted (for short) and no data gets lost.

Change-Id: I870a0aa8e251bbb53249c54bfcaa45de5b5a9486
2018-07-04 17:55:20 +02:00
Kévin Redon
c9bd715289 sniffing: fix procedure byte handling and make TPDU parsing more strict
Change-Id: If991152f11c4b864ab1386f21dc13c335e6b281f
2018-07-04 17:55:20 +02:00
Kévin Redon
35e8bdf879 sniffer: also send incomplete (e.g. timeout) data (PPS/ATR/TPDU)
Change-Id: Ib070aca181042b477f1ffec48d63dc56c1e4609a
2018-07-04 17:55:20 +02:00
Kévin Redon
709a431ab9 sniffing: move conversion convertion and flag processing from ISR to main loop to keep ISR fast and focus on data capture
Change-Id: Ieefa8a5f81dbcc12c1ad3059660dbffa0c1a4961
2018-07-04 17:55:20 +02:00
Kévin Redon
30f90a78fc console: drop data to be send when buffer is already full
don't wait for space to be available in the buffer since since would
prevent from processing non-console (e.g. debug) more important data

Change-Id: Ia625b09eb30bb7b43edd3989f697d8ef33200f28
2018-07-04 17:10:08 +02:00
Kévin Redon
7406337a7f sniffer: display F and D values frim PPS
Change-Id: I3641dcb6c24695a6d3dd3a1ee4333f56a07c99f0
2018-07-04 17:10:08 +02:00
Kévin Redon
6e3f1121e6 host USB: add host application to receive and display USB sniffing messages sent by firmware
Change-Id: Idefbf21e0bbd2a1e3647fe9aebaf88d1b62dae2d
2018-07-04 17:10:08 +02:00
Kévin Redon
de97fd25bd sniffer USB: implement USB communication and send parsed messages
Change-Id: Ice7817480705f2124b08c1ff9a8826558b6d8b2b
2018-07-04 17:10:08 +02:00
Kévin Redon
012940f48e USB device: add USB message structure for sniffer communication
Change-Id: Id2c6f32ade2fec9b9ef91bd8c5e1fd195f2d7351
2018-07-04 17:10:08 +02:00
Kévin Redon
e2f84f6a8b host USB: use central SIMtrace USB ID definition header
Change-Id: Id18e64fba0a2c308a8aef7d3865200bf0237cae9
2018-07-04 17:10:08 +02:00
Kévin Redon
4d6a4b949c host usb_util fix: used provided class, sub-class, and interfave when finding matching interfaces
Change-Id: Ibc06e751e6ca0f9e9a40d82c4eeddfb975240f91
2018-07-04 17:10:08 +02:00
Kévin Redon
a1012b170a USB: add central file to define USB IDs, classes, and endpoints
Change-Id: Iba81f32a92c68a973e8e7adbc4c2a1064ba5290f
2018-07-04 17:10:06 +02:00
Kévin Redon
42bd026416 minor: fix typos in comment
Change-Id: I01b49e047a586dff449d4e134751108e391a8822
2018-07-04 16:33:00 +02:00
Kévin Redon
638cec820f sniff: add WT timeout detection using USART timeout (TC is not required)
Change-Id: I4ec6e812e7e1eb91005027d2e864fc315550d79c
2018-07-04 16:33:00 +02:00
Kévin Redon
00ec89d73f sniff: add TPDU parsing (TPDUs become APDUs on the upper layer)
Change-Id: I09d050d95bd2ab140fe6b4926a37278eb08cc347
2018-07-04 16:33:00 +02:00
Kévin Redon
cf59919494 sniff: print parsed ATR and PPS; use red LED to show main application is running; use green LED to indicate activity (message parsed)
Change-Id: I8e906bdbf2c91e608757ae442dfb241f981b8f1e
2018-07-04 16:33:00 +02:00
Kévin Redon
11914d9658 LED: add short LED pulse blinking pattern
Change-Id: I0fdc2f902a3b92da6aa9b9c8500abae8a2f79447
2018-07-04 16:32:54 +02:00
Kévin Redon
3113e3d2e5 update_fidi: remove debug output since this function is called in time critical ISR
Change-Id: I08f407d407a18dae3f360ddc64769ddfaeb5b559
2018-07-04 14:29:28 +02:00
Kévin Redon
9def7631ba DFU: switch green LED on to indicate DFU mode, and red LED to indicate flashing activity
Change-Id: I8e34fd869ed94ad122d6a17f5a432f5a09b820bb
2018-07-04 14:29:28 +02:00
Kévin Redon
ca9e4bf4ba board: fix LED pin definition
Change-Id: Ia6c80c0268dec708845e1dad281caaa42027f9db
2018-07-04 14:29:28 +02:00
Kévin Redon
8210ec3f62 DFU: remove force bootloader button debug message since the console is output message is not initialized yet
Change-Id: Ibea0105929a8dc38b43dacd9d1e576d7b51d0c6a
2018-07-04 14:29:28 +02:00
Kévin Redon
8fa6ff5979 sniffer: use ISR to store sniffed data in buffer, add ATR and PPS parsing, and PPS related FiDi update
Change-Id: I4b38ce1d80e370fda6aa181e959ba3f1286bb922
2018-07-04 14:29:28 +02:00
Kévin Redon
866d20b10e trace: increase watchdog for 500 to 2000 ms to provide more time handling buffered data
Change-Id: Iacd85525f05e692b44183bd4c4585b9e70865cfe
2018-07-04 14:29:28 +02:00
Kévin Redon
4fe99fad59 ISO7816: change update_fidi to use provided USART
Also disables write protection for USART register if required

Change-Id: I716f4bc3a22800cbce402b146f14ef8b2aab2a98
2018-07-04 14:29:28 +02:00
Kévin Redon
7be52ec1ce SIMtrace: enable interrupt on edge dection for SIM_RST pin to reset the sniffer ISO state
Change-Id: I92ff29abd6a8690dd033d8cf13ad0d1ff9740fe5
2018-07-04 14:29:28 +02:00
Kévin Redon
a2b367633c SIMtrace: fix default SIM_RST pin state to allow phone controlled reset
Change-Id: I1942ec6bd499cb2e14f6d7699a2b2d9b4197e654
2018-07-04 14:29:28 +02:00
Kévin Redon
927ffb46eb SIMtrace: only enable main sniffing mode on SIMtrace board
Change-Id: Iff6ebb1d98aa0c31f6d78508afde8f1b05f0f85b
2018-07-04 14:29:28 +02:00
Kévin Redon
d7a6de57d2 sniffer: add state definitions, improve IRQ handling, update pins configuration
Change-Id: I6b5dfd6d573ac122a60585a24c8a620642805ad5
2018-07-04 14:29:27 +02:00
Kévin Redon
353351ddf4 simtrace: add support for sniffing on both USART
Change-Id: I69eb458e7cb186c990e5d6fbc780f37fdd0cd884
2018-07-04 14:28:19 +02:00
Kévin Redon
4091d78c4b board: comment USART definitions and add corresponding IRQ numbers
Change-Id: I3c38e7d75bc7b511827c33af69e335e50d0b35d2
2018-07-04 14:28:19 +02:00
Kévin Redon
ee62a9da56 simtrace: add dedicated power pins configuration for sniffing
Change-Id: Ie37edbae6ea42d2b0c2a30eb5590afd0be797d39
2018-07-04 14:28:17 +02:00
Kévin Redon
45ad62d8d4 sniff: use USART 0 instead of USART 1
Use USART 0 connected to the SIM card side to sniff the communication.
The card side can also measure ETU times.
Do proper pin initialization.
This code can already capture the ATR communication between phone and card.

Change-Id: I0597ec723cb2225540c89c3821b91d8a45adfcd6
2018-07-04 11:24:13 +00:00
Kévin Redon
2c4e2af21f SIMtrace board: comment and fix pin definition
Change-Id: Ic77ad5bf6c00c9122c6bb0e12b90e6c5406855fd
2018-07-04 11:24:13 +00:00
Kévin Redon
7b73462442 sniff mode: handle USART 1 RX interrupt to show sniffer data
Change-Id: I5504369aed39844b7cf21e5b3ccb542daa6b946e
2018-07-04 11:24:13 +00:00
Kévin Redon
36abece0b1 enable (empty) sniffer support for SIMtrace board
Change-Id: I51619135fd6f5423542f261e7d76bab1a5713e2b
2018-07-04 11:24:13 +00:00
Kévin Redon
f9997e9d26 copy working cardem app to trace
because the applications share the board capabilities defined in
libboard/*/include/board.h and USB configurations are enabled according
to the previously defined capabilities in libcommon/source.usb.c, all
applications actually offer the same functions.
thus creating the trace application is only mainly a cosmetic change, as the
sniffer function will also be present and enabled in the cardem application.

Change-Id: I24b3500a0905cbd622507722280b3c7e7f188bde
2018-07-04 11:24:13 +00:00
Harald Welte
05cc7f6531 ringbuffer: Don't print/TRAC from ringbuffer
In commit eac1bec428 we start to use the
ringbuffer inside the console printing code.  As a result, we must not
use TRACE_*() or printf() from within ringbuffer.c code to avoid
infinite recursion.

Instead, let rbuf_write() return a negative return value in case the
ring buffer overflows.  This way, the callers (outside the
console/stdout code) can print an error message themselves.

Change-Id: Ib009f013be119dbad22fa2b7d60ec8dee59baee5
2018-07-04 04:42:22 +02:00
Harald Welte
46893451de echo all command characters entered on serial console
This is required to make python pexpect.fdexpect happy, as it
requires that all characters are echo-ed back in order to detect
when the output of a given command starts.

Change-Id: I73b24e43f6c8b86a2766aba67d8307c184448aa0
2018-07-03 22:30:30 +02:00
Harald Welte
cb6e20596e contrib/jenkins.sh: Also run firmware tests + build-test host software
Change-Id: Ie53857164d0a21daac334057c5bafbfd9912bf4b
2018-07-01 16:33:25 +02:00
Harald Welte
bb2eb19fb1 firmware/test: Add more include paths
Change-Id: I4287fbae6921ed0605265812df5d7243e8857864
2018-07-01 08:47:39 +02:00
Harald Welte
9d90d284ed Use system include <foo.h> notation for libosmocore headers
the curent local copies of libosmocore headers + source is a temporary
hack anyway. We should instead rely on a system-wide install of
libosmocore cross-compiled for arm-none-eabi.  But leave that as a
second (later) step beyond this patch.

Change-Id: Ia63fd842d45a2b404233b4326050e7eda0604cf0
2018-06-29 22:26:57 +02:00
Harald Welte
ebe8b2069c Makefile: fix automatic creation of obj directory
since we're using obj/$BOARD, we must use "-p" to create the directory
recursively
2018-06-29 21:44:12 +02:00
Harald Welte
105c1dce4f add contrib/jenkins.sh for build verification
The contrib/jenkins.sh script will build all supported apps for all
supported builds.  It will be used by jenkins/gerrit build testing.
2018-06-29 21:39:42 +02:00
Harald Welte
1cfc2614dd apps/dfu/main.c: Avoid variable declaration in for loop initial
This fixes the following compile error:

apps/dfu/main.c:73:3: error: 'for' loop initial declarations are only allowed in C99 or C11 mode
   for (unsigned int i=0; i<len; i++) {
   ^
apps/dfu/main.c:73:3: note: use option -std=c99, -std=gnu99, -std=c11 or -std=gnu11 to compile your code

which was recently introduced in b73f0a00bc
2018-06-29 21:07:41 +02:00
Kévin Redon
a9bca48914 ring buffer: increase buffer size from 128 to 256 to cope with large debug output 2018-06-29 20:07:31 +02:00
Kévin Redon
eac1bec428 console: use buffer and interrupts instead of busy loops for UART debug output 2018-06-29 20:07:31 +02:00
Kévin Redon
51c128bc35 DFU: fix typo in USB strings 2018-06-29 20:07:31 +02:00
Kévin Redon
869dbfafe4 DFU: incread watchdog timeout and restart watchdog before writing in flash to prevent the watchdog to trigger while flashing 2018-06-29 20:07:31 +02:00
Kévin Redon
80303c135b DFU: only boot the application if it has a valid start 2018-06-29 20:07:31 +02:00
Kévin Redon
d86cab0080 DFU: uncomment print message when DFU is forced using the button 2018-06-29 20:07:31 +02:00
Kévin Redon
b73f0a00bc DFU: unlock the flash before writing, verify written data, and relock it 2018-06-29 20:07:31 +02:00
Kévin Redon
f5869d4a59 USB: implement USB reset by setting the on-board pull-up on D+ low 2018-06-29 20:07:31 +02:00
Kévin Redon
4136c242a8 USBD: send empty packet when non-existing descriptor string is requested
Sometimes descriptor string 0xee is requested.
This is a mechanism used by Microsoft Windows to further identify the USB device.
Instead of stalling, as is the original code, leading to an USB reset, we send an empty packet.
I am not sure if sending an empty string would be better, but an empty packet seems sufficient.
2018-06-29 20:07:31 +02:00
Kévin Redon
318309f30f dfu: fix address destination check and add stack overwrite check in USBDFU_handle_dnload
During DFU download the destination start address is checked to not exceed the
RAM or flash end address, but it is also necessary to check if the end of the
data to be downloaded is also within the allowed range.
When downloading to RAM it is also necessary to check if the data to be
downloaded does not overwrite (i.e. corrupt) the stack.
2018-06-29 20:07:31 +02:00
Kévin Redon
0828b914e7 README: rewrite to better explain environment variables and point to the wiki for flashing 2018-06-29 20:07:31 +02:00
Kévin Redon
76be7c806e fix pointer casting warning
fixes following warning:
libboard/common/source/board_cstartup_gnu.c:137:11: warning: assignment to 'void (*)(void)' from 'unsigned int' makes pointer from integer without a cast [-Wint-conversion]
  appReset = pSrc[1];
2018-06-29 20:07:31 +02:00
Kévin Redon
a38a126361 fix: initialize uninitialized variable in USBDFU_DFU_RequestHandler 2018-06-29 20:07:31 +02:00
Kévin Redon
6822716428 add printf attribute declaration to remove warning
the __attribute__ ((format (printf, 1, 0))) declaration remove the following
compilation warning:
warning: function 'osmo_panic' might be a candidate for 'gnu_printf' format
 attribute [-Wsuggest-attribute=format]
   osmo_panic_default(fmt, args);
2018-05-21 17:18:58 +02:00
Kévin Redon
a93f7273b3 fix: remove duplicate volatile declaration 2018-05-21 17:17:20 +02:00
Kévin Redon
432ba5140e add copyright notice
The original board startup script is provided by Atmel.
It has been modified to handle application or DFU booting.
The copyright notice has been updated to reflect this change.
2018-05-21 17:13:50 +02:00
Harald Welte
849d20e29e Add firmware/TODO.txt that was not committed so far 2018-05-11 15:49:31 +02:00
Harald Welte
e48d6f2321 Add README.md 2018-05-11 15:48:54 +02:00
Harald Welte
af616ec4e2 CCID driver: Use USBD_GetDriver() instead of non-initialized state variable 2017-11-29 00:45:23 +01:00
Harald Welte
6051e126da CCID: re-enable control request handler for CCID class requests 2017-11-29 00:26:34 +01:00
Harald Welte
7f62c24532 USB: Handle DFU requests by USBD.c to keep application callback
e.g. in CCID mode we need to treat class-specific control requests,
and we want to do this in a way how the CCID code doesn't need to
understand about DFU.
2017-11-29 00:24:28 +01:00
Harald Welte
75cf93e04d rename ccid.c to mode_ccid.c to align with mode_cardemu.c 2017-11-28 23:00:40 +01:00
Harald Welte
2afd57f00a cardem: Don't dispatch UART IRQs to possible NULL pointers
A given configuration might not expose callback functions for
the UART interrupts.
2017-11-28 22:52:56 +01:00
Harald Welte
0633b25974 iso7816_4: Re-trigger watchdog while waiting for character 2017-11-28 22:47:09 +01:00
Harald Welte
c1e2254854 simtrace: Boot into DFU when BOOTLOADER button is pressed
This recovers the old functionality of the SAM7 based OpenPCD firmware.
2017-11-28 22:29:53 +01:00
Harald Welte
27f5fc681c DFU: Move "Override DFU" (force DFU) code to board-specific section
Each board can define its own conditions on which the controller should
boot into DFU mode rather than normal application mode.  Let's move the
"UART loopback jumper" to QMOD specific part.  For SIMtrace we have an
actual button and can use that in a future patch.
2017-11-28 22:15:56 +01:00
Harald Welte
7b250bfc8d board_simtrace: Add minimal debug menu on debug USART 2017-11-28 22:10:49 +01:00
Harald Welte
ed75c62acf {ccid,sniffer}.c: Add comments on USB callbacks 2017-11-28 21:23:12 +01:00
Harald Welte
5c081911a9 remove dead code (source/phone.c), superseded by card_emu.c/mode_cardemu.c 2017-11-28 21:21:50 +01:00
Harald Welte
5e6e8dcbde Make build of CCID code succeed again on BOARD=simtrace 2017-11-28 20:58:06 +01:00
Harald Welte
c35998e20d Makefile: Disable -Wundef and -Wsign-compare for now
This silences tons of warnings which are making it hard to identify
actual issues when looking at the compiler output.
2017-11-28 20:47:23 +01:00
Harald Welte
ba2ad563cc fix build of APP=cardem on BOARD=simtrace 2017-11-28 19:49:41 +01:00
Harald Welte
fc87c24326 mode_cardem: Build on platforms without WWAN_PERST suppotrt 2017-11-28 19:17:27 +01:00
Harald Welte
f231541601 Fix typos in usb.c, llist_irqsafe.h and dfu.h 2017-11-28 19:16:57 +01:00
Harald Welte
119624f46f WIP: use local_irq_{save,restore}() 2017-11-04 12:28:30 +01:00
Harald Welte
7b36306113 [firmware] WIP: make talloc irq-safe 2017-11-04 12:17:09 +01:00
Harald Welte
eb50c9f914 [firmware] sim_switch + wwan_perst: Don't re-initialize
The logic to detect if the respective module is already initialized
or not was broken.  When performing initialization, we of course need
to set initialized=1.
2017-11-03 20:52:35 +01:00
Harald Welte
965d5c918a [firmware] cardemu: Skip CARD_INSERT if board doesn't support it 2017-11-03 20:48:11 +01:00
Harald Welte
514c6d1da0 [firmware] wwan_perst: Print index when releasing WWAN_PERST 2017-11-03 20:40:56 +01:00
Harald Welte
e7f2f9a5e0 [firmware] wwam_led: use 0/1 instead of 1/2
most (all) other code modules have already moved over to
consistently using a 0-based index.
2017-11-03 20:38:31 +01:00
Harald Welte
4e837d45db [firmware] card_pres: use modem number at start of line
... like most other code modules, too
2017-11-03 20:36:17 +01:00
Harald Welte
b52b886186 [firmware] card_pres: Use 0/1 index number instead of 1/2
We have moved most (all?) other code to work with slots 0/1
rather than 1/2.
2017-11-03 20:33:10 +01:00
Harald Welte
c47fc5febf set local slot LED according to remote/local state.
The LED is illuminated as long as the slot is in local (physical SIM
card) mode.
2017-05-20 14:46:57 +01:00
Harald Welte
02d0ec6e08 uart_console: Re-start watchdog during busy-waiting for serial chars 2017-05-20 14:46:57 +01:00
124 changed files with 13239 additions and 8483 deletions

1
.gitignore vendored
View File

@@ -21,3 +21,4 @@ host/simtrace2-list
host/simtrace2-remsim host/simtrace2-remsim
host/simtrace2-remsim-usb2udp host/simtrace2-remsim-usb2udp
usb_strings_generated.h usb_strings_generated.h
firmware/usbstring/usbstring

27
Makefile Normal file
View File

@@ -0,0 +1,27 @@
all: fw utils
define RULES
fw-$(1)-$(2):
make -C firmware BOARD=$(1) APP=$(2)
fw-$(1)-$(2)-clean:
make -C firmware BOARD=$(1) APP=$(2) clean
endef
$(eval $(call RULES,simtrace,dfu))
$(eval $(call RULES,simtrace,trace))
$(eval $(call RULES,simtrace,cardem))
$(eval $(call RULES,qmod,dfu))
$(eval $(call RULES,qmod,cardem))
fw-clean: fw-simtrace-dfu-clean fw-simtrace-trace-clean fw-simtrace-cardem-clean fw-qmod-dfu-clean fw-qmod-cardem-clean
fw: fw-simtrace-dfu fw-simtrace-trace fw-simtrace-cardem fw-qmod-dfu fw-qmod-cardem
utils:
make -C host
clean: fw-clean
make -C host clean
install:
make -C firmware install
make -C host install

39
README.md Normal file
View File

@@ -0,0 +1,39 @@
SIMtrace v2.0
=============
This is the repository for the next-generation SIMtrace devices,
providing abilities to trace the communication between (U)SIM card and
phone, remote (U)SIM card forward, (U)SIM man-in-the-middle, and more.
This is under heavy development, and right now it is not surprising if
things still break on a daily basis.
NOTE: Nothing in this repository applies to the SIMtrace v1.x hardware
or its associated firmware. SIMtrace v1.x is based on a different CPU /
microcontroller architecture and uses a completely different software
stack and host software.
Supported Hardware
------------------
At this point, the primary development target is still the OWHW + sysmoQMOD
device, but we expect to add support for a SAM3 based SIMtrace hardware
board soon.
The goal is to support the following devices:
* Osmocom SIMtrace 1.x with SAM3 controller
** this is open hardware and schematics / PCB design is published
* sysmocom sysmoQMOD (with 4 Modems, 4 SIM slots and 2 SAM3)
** this is a proprietary device, publicly available from sysmocom
* sysmocom OWHW (with 2 Modems and 1 SAM3 onboard)
** this is not publicly available hardware, but still supported
This Repository
---------------
This repository contains several directory
* firmware - the firmware to run on the actual devices
* hardware - some information related to the hardware
* host - Programs to use on the USB host to interface with the hardware

79
contrib/jenkins.sh Executable file
View File

@@ -0,0 +1,79 @@
#!/bin/bash
TOPDIR=`pwd`
if ! [ -x "$(command -v osmo-build-dep.sh)" ]; then
echo "Error: We need to have scripts/osmo-deps.sh from http://git.osmocom.org/osmo-ci/ in PATH !"
exit 2
fi
set -e
publish="$1"
base="$PWD"
deps="$base/deps"
inst="$deps/install"
export deps inst
osmo-clean-workspace.sh
mkdir "$deps" || true
osmo-build-dep.sh libosmocore "" '--disable-doxygen --enable-gnutls'
export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
export LD_LIBRARY_PATH="$inst/lib"
BUILDS=""
BUILDS+="simtrace/dfu simtrace/trace simtrace/cardem "
BUILDS+="qmod/dfu qmod/cardem "
BUILDS+="owhw/dfu owhw/cardem "
cd $TOPDIR/firmware
for build in $BUILDS; do
board=`echo $build | cut -d "/" -f 1`
app=`echo $build | cut -d "/" -f 2`
echo
echo "=============== $board / $app START =============="
make BOARD="$board" APP="$app"
echo "=============== $board / $app RES:$? =============="
done
echo
echo "=============== FIRMWARE TESTS ==========="
cd $TOPDIR/firmware/test
make clean
make
./card_emu_test
make clean
echo
echo "=============== HOST START =============="
cd $TOPDIR/host
make clean
make
make clean
if [ "x$publish" = "x--publish" ]; then
echo
echo "=============== UPLOAD BUILD =============="
cat > "$WORKSPACE/known_hosts" <<EOF
[rita.osmocom.org]:48 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDgQ9HntlpWNmh953a2Gc8NysKE4orOatVT1wQkyzhARnfYUerRuwyNr1GqMyBKdSI9amYVBXJIOUFcpV81niA7zQRUs66bpIMkE9/rHxBd81SkorEPOIS84W4vm3SZtuNqa+fADcqe88Hcb0ZdTzjKILuwi19gzrQyME2knHY71EOETe9Yow5RD2hTIpB5ecNxI0LUKDq+Ii8HfBvndPBIr0BWYDugckQ3Bocf+yn/tn2/GZieFEyFpBGF/MnLbAAfUKIdeyFRX7ufaiWWz5yKAfEhtziqdAGZaXNaLG6gkpy3EixOAy6ZXuTAk3b3Y0FUmDjhOHllbPmTOcKMry9
[rita.osmocom.org]:48 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPdWn1kEousXuKsZ+qJEZTt/NSeASxCrUfNDW3LWtH+d8Ust7ZuKp/vuyG+5pe5pwpPOgFu7TjN+0lVjYJVXH54=
[rita.osmocom.org]:48 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK8iivY70EiR5NiGChV39gRLjNpC8lvu1ZdHtdMw2zuX
EOF
SSH_COMMAND="ssh -o 'UserKnownHostsFile=$WORKSPACE/known_hosts' -p 48"
rsync -avz --delete -e "$SSH_COMMAND" $TOPDIR/firmware/bin/*.bin binaries@rita.osmocom.org:web-files/simtrace2/firmware/
fi
echo
echo "=============== FIRMWARE CLEAN =============="
cd $TOPDIR/firmware/
for build in $BUILDS; do
board=`echo $build | cut -d "/" -f 1`
app=`echo $build | cut -d "/" -f 2`
make BOARD="$board" APP="$app" clean
done
osmo-clean-workspace.sh

11
debian/changelog vendored Normal file
View File

@@ -0,0 +1,11 @@
simtrace2 (0.5.1) unstable; urgency=medium
* Backwards-compatibility with older (released, non-master) libosmocore
-- Harald Welte <lafore@gnumonks.org> Sun, 26 Aug 2018 11:50:36 +0200
simtrace2 (0.5) unstable; urgency=medium
* Initial debian package release.
-- Harald Welte <lafore@gnumonks.org> Sun, 26 Aug 2018 10:37:19 +0200

1
debian/compat vendored Normal file
View File

@@ -0,0 +1 @@
9

31
debian/control vendored Normal file
View File

@@ -0,0 +1,31 @@
Source: simtrace2
Maintainer: Harald Welte <laforge@gnumonks.org>
Section: devel
Priority: optional
Build-Depends: debhelper (>= 9),
libosmocore-dev,
libpcsclite-dev,
libnewlib-arm-none-eabi,
libusb-1.0-0-dev,
gcc-arm-none-eabi
Standards-Version: 3.9.8
Vcs-Git: git://git.osmocom.org/simtrace2.git
Vcs-Browser: http://git.osmocom.org/simtrace2/
Homepage: http://osmocom.org/projects/simtrace2/wiki
Package: simtrace2-firmware
Section: devel
Architecture: all
Recommends: dfu-util
Description: Firmware for SAM3 based SIMtrace2 USB Devices.
Open Source firmware for the Cortex-M3 microcontroller in the
"Osmocom SIMtrace2" USB-attached peripheral device. Will only work in
SAM3S-based SIMtrace2, not in its SAM7S-based predecessor SIMtrace!
Package: simtrace2-utils
Section: devel
Architecture: any
Multi-Arch: same
Depends: ${shlibs:Depends}, ${misc:Depends}
Recommends: simtrace2-firmware
Description: Host utilities to communicate with SIMtrace2 USB Devices.

4
debian/rules vendored Executable file
View File

@@ -0,0 +1,4 @@
#!/usr/bin/make -f
%:
dh $@

1
debian/simtrace2-firmware.install vendored Normal file
View File

@@ -0,0 +1 @@
usr/share/simtrace2/*.bin

1
debian/simtrace2-utils.install vendored Normal file
View File

@@ -0,0 +1 @@
usr/bin/simtrace2-*

View File

@@ -100,7 +100,7 @@ C_LIBUSB_DFU = dfu.c dfu_desc.c dfu_driver.c
C_LIBCOMMON = string.c stdio.c fputs.c usb_buf.c ringbuffer.c pseudo_talloc.c host_communication.c C_LIBCOMMON = string.c stdio.c fputs.c usb_buf.c ringbuffer.c pseudo_talloc.c host_communication.c
C_BOARD = $(notdir $(wildcard libboard/common/source/*.c)) C_BOARD = $(notdir $(wildcard libboard/common/source/*.c))
C_BOARD += $(notdir $(wildcard libboard/$(BOARD)/source/*.c)) C_BOARD += $(notdir $(wildcard libboard/$(BOARD)/source/*.c))
C_APPLEVEL = $(notdir $(wildcard apps/$(APP)/*.c)) C_APPLEVEL = $(notdir $(wildcard apps/$(APP)/*.c))
@@ -141,13 +141,12 @@ INCLUDES += -Ilibosmocore/include
INCLUDES += -Isrc_simtrace -Iinclude INCLUDES += -Isrc_simtrace -Iinclude
INCLUDES += -Iapps/$(APP) INCLUDES += -Iapps/$(APP)
CFLAGS += -Wall -Wchar-subscripts -Wcomment -Wimplicit-int #-Wformat=2 CFLAGS += -Wall -Wchar-subscripts -Wcomment -Wimplicit-int -Wformat=2
CFLAGS += -Werror-implicit-function-declaration -Wmain -Wparentheses CFLAGS += -Werror-implicit-function-declaration -Wmain -Wparentheses
CFLAGS += -Wsequence-point -Wreturn-type -Wswitch -Wtrigraphs #-Wunused CFLAGS += -Wsequence-point -Wreturn-type -Wswitch -Wtrigraphs #-Wunused
CFLAGS += -Wuninitialized -Wunknown-pragmas -Wfloat-equal -Wundef CFLAGS += -Wuninitialized -Wunknown-pragmas -Wfloat-equal #-Wundef
CFLAGS += -Wshadow -Wpointer-arith -Wbad-function-cast -Wwrite-strings CFLAGS += -Wshadow -Wpointer-arith -Wbad-function-cast -Wwrite-strings
CFLAGS += -Wsign-compare -Waggregate-return CFLAGS += -Waggregate-return #-Wsign-compare
CFLAGS += -Wformat=0
CFLAGS += -Wmissing-format-attribute -Wno-deprecated-declarations CFLAGS += -Wmissing-format-attribute -Wno-deprecated-declarations
CFLAGS += #-Wpacked CFLAGS += #-Wpacked
CFLAGS += -Wredundant-decls -Wnested-externs #-Winline -Wlong-long CFLAGS += -Wredundant-decls -Wnested-externs #-Winline -Wlong-long
@@ -192,7 +191,7 @@ $(OUTPUT)-combined.bin: $(BIN)/$(BOARD)-dfu-flash-padded.bin $(OUTPUT)-dfu.bin
cat $^ > $@ cat $^ > $@
$(BIN) $(OBJ): $(BIN) $(OBJ):
mkdir $@ mkdir -p $@
usbstring/usbstring: usbstring/usbstring.c usbstring/usbstring: usbstring/usbstring.c
gcc $^ -o $@ gcc $^ -o $@
@@ -229,8 +228,12 @@ program:
SERIAL ?= /dev/ttyUSB0 SERIAL ?= /dev/ttyUSB0
log: log:
stty -F $(SERIAL) 115200 stty -F $(SERIAL) 921600
lsof $(SERIAL) && echo "log is already opened" || ( sed -u "s/\r//" $(SERIAL) | ts ) lsof $(SERIAL) && echo "log is already opened" || ( sed -u "s/\r//" $(SERIAL) | ts )
clean: clean:
-rm -fR $(OBJ)/*.o $(BIN)/*.bin $(BIN)/*.elf $(BIN)/*.elf.txt $(BIN)/*.map $(BIN)/*.lst `find . -name \*.p` -rm -fR $(OBJ)/*.o $(BIN)/*.bin $(BIN)/*.elf $(BIN)/*.elf.txt $(BIN)/*.map $(BIN)/*.lst `find . -name \*.p`
install:
mkdir -p $(DESTDIR)/usr/share/simtrace2
cp $(BIN)/*.bin $(BIN)/*.elf $(BIN)/*.elf.txt $(BIN)/*.map $(DESTDIR)/usr/share/simtrace2

View File

@@ -1,70 +1,81 @@
This is the source code for SIMtrace 2 firmwares.
== BOARDS = Hardware
A board defines a given circuit board, i.e. SIMtrace, OWHW, QMOD == Micro-Controller
It defines the given hardware model for which the program is to be The firmware is for Microchip (formerly Atmel) ATSAM3S4B micro-controllers (MCU).
compiled. Product page: https://www.microchip.com/wwwproducts/en/ATSAM3S4B
Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-6500-32-bit-Cortex-M3-Microcontroller-SAM3S4-SAM3S2-SAM3S1_Datasheet.pdf
Note: The SAM3S is now not recommended for new designs.
It can be replaced by the pin-compatible SAM4S.
The MCU can be specified using the environment variable `CHIP` (set to `sam3s4` per default) for future MCU support.
== Boards
The SIMtrace 2 firmware supports multiple boards.
A board defines a given circuit board.
While compiling the firmware, set the target board using the `BOARD` environment variable (set to `qmod` per default).
The supported boards correspond to sub-folders under `libboard`.
Current boards supported are: Current boards supported are:
* simtrace: The good old Osmocom SIMtrace PCB with SAM3 instead of
SAM7, open hardware.
* qmod: A sysmocom-proprietary quad mPCIe carrier board, publicly available
* owhw: An undisclosed sysmocom-internal board, not publicly available
== APPLICATIONS * `simtrace`: The good old Osmocom SIMtrace PCB with SAM3 instead of SAM7, open hardware.
* `qmod`: A sysmocom-proprietary quad mPCIe carrier board, publicly available
* `owhw`: An undisclosed sysmocom-internal board, not publicly available
An application is a specific piece of software with given = Firmware
functionality.
== ENVIRONMENTS == Library
The firmware uses the manufacturer provided Software Package (SoftPack) micro-controller library.
The original library is available at https://www.microchip.com/design-centers/32-bit/softpacks/legacy-softpacks .
Version 2.1 from 2001 is used: http://ww1.microchip.com/downloads/en/DeviceDoc/SAM3S_softpack_2.1_for_CodeSourcery_2010q1.zip
The SIMtrace 2 project uses the `libboard_sam3s-ek`, `libchip_sam3s`, and `usb` sub-libraries, saved in `atmel_softpack_libraries` (with local modifications).
Note: SoftPack is the legacy micro-controller library.
This library is now replaced by the Advanced Software Framework (ASF): https://www.microchip.com/avr-support/advanced-software-framework-(asf) .
The SAM3S ASF documentation is available at http://asf.atmel.com/docs/latest/sam3s/html/index.html .
== Applications
An application is a specific piece of software with given functionality.
While compiling the firmware, set the target application using the `APP` environment variable (set to `dfu` per default).
The supported applications correspond to sub-folder under `apps`.
Current applications supported are:
* `dfu`: The USB DFU bootloader to flash further main appliction firmwares.
* `ccid`: To use SIMtrace 2 as USB CCID smartcard reader.
* `cardem`: To provide remote SIM operation capabilities.
* `trace`: To monitor the communication between a SIM card and a phone (corresponds to the functionality provide by the first SIMtrace)
* `triple_play`: To support the three previous functionalities, using USB configurations.
== Memories
Firmwares can be run from several memory locations:
An environment is a runtime environment, typically defined by a linker
script. The current runtime environments include
* flash: Run natively from start of flash memory * flash: Run natively from start of flash memory
* dfu: Run after a DFU bootloader from an offset after the first 16k * dfu: Run after a DFU bootloader from an offset after the first 16k of flash (the first 16k are reserved for the bootloader)
of flash (the first 16k are reserved for the bootloader)
* ram: Run from within the RAM of the chip, downloaded via JTAG/SWD * ram: Run from within the RAM of the chip, downloaded via JTAG/SWD
== Building == Building
A given software build is made for a specific combination of an APP A given firmware build is made for a specific combination of an application `APP` running in a certain memory `MEM` on a given board `BOARD`.
running in a certain ENVIRONMENT on a given BOARD. When building using `make`, set the target application using the `APP` environment variable and target board using the `BOARD` environment variable, e.g.:
A Makefile is provided. It will create output files in the format
bin/$(BOARD)-$(APP)-$(ENV).{elf,bin}
You can specify the APP and BOARD to build when calling make, like
e.g.
* make APP=cardem BOARD=qmod * make APP=cardem BOARD=qmod
* make APP=dfu BOARD=qmod * make APP=dfu BOARD=qmod
The Makefile will create output files in the format: `bin/$(BOARD)-$(APP)-$(MEM).{elf,bin}`
The level of debug messages can be altered at compile time: The level of debug messages can be altered at compile time:
``` ```
$ make TRACE_LEVEL=4 $ make TRACE_LEVEL=4
``` ```
Accepted values: 0 (NO_TRACE) to 5 (DEBUG) Accepted values: 0 (NO_TRACE) to 5 (DEBUG)
== Flashing = Flashing
For flashing the firmware, there are at least two options. To flash a firmware image follow the instructions provided in the [wiki](https://projects.osmocom.org/projects/simtrace2/wiki/).
=== Using JTAG + OpenOCD to flash the DFU bootloader
The first one is using openocd and a JTAG key.
For this option, a JTAG connector has to be soldered onto the board, which is not attached per default.
```
$ openocd -f openocd/openocd.cfg -c "init" -c "halt" -c "flash write_bank 0 ./bin/$(BOARD)-dfu-flash.bin 0" -c "reset" -c "shutdown"
```
=== Using bossac to flash the DFU bootloader
The second option is using rumba for flashing. No further hardware has to be provided for this option.
FIXME
=== Using DFU to flash application
FIXME

22
firmware/TODO.txt Normal file
View File

@@ -0,0 +1,22 @@
== Important DFU topics / reliability ==
x some kind of DFU fallback / boot cycle counter ?
* CRC check of image before attempting to execute it ?
x Keep WDT running while in DFU or app
? USB control request for flash erase
== QModem related ==
x new vendor/product ID for hub and SAM3s
* board-specfic string descriptors
* re-mapping of USB ports in EEPROM
== Lower Priority ==
* unique serial number in iSerial?
* printing of banner from generic function
* board_main_top() automatically before calling main()
x compile-time USB string generation
* shared USB strings for DFU and runtime
* version detection voltage ranges
* locking of bootloader pages?
* debug console command for switch-to-dfu
* read CPU reset cause (and time?) via USB

View File

@@ -1,3 +1,3 @@
C_FILES += $(C_LIBUSB_RT) C_FILES += $(C_LIBUSB_RT)
C_FILES += card_emu.c ccid.c iso7816_4.c iso7816_fidi.c mitm.c mode_cardemu.c simtrace_iso7816.c sniffer.c tc_etu.c usb.c C_FILES += card_emu.c iso7816_3.c iso7816_4.c mode_cardemu.c simtrace_iso7816.c usb.c

View File

@@ -1,4 +1,22 @@
// FIXME: Copyright license here /* SIMtrace 2 firmware card emulation application
*
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2018-2019, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
* Headers * Headers
*------------------------------------------------------------------------------*/ *------------------------------------------------------------------------------*/
@@ -6,7 +24,7 @@
#include "board.h" #include "board.h"
#include "simtrace.h" #include "simtrace.h"
#include "utils.h" #include "utils.h"
#include "osmocom/core/timer.h" #include <osmocom/core/timer.h>
unsigned int g_unique_id[4]; unsigned int g_unique_id[4];
@@ -84,17 +102,23 @@ static volatile enum confNum simtrace_config = CFG_NUM_CCID;
void USBDDriverCallbacks_ConfigurationChanged(uint8_t cfgnum) void USBDDriverCallbacks_ConfigurationChanged(uint8_t cfgnum)
{ {
TRACE_INFO_WP("cfgChanged%d ", cfgnum); TRACE_INFO_WP("cfgChanged%d ", cfgnum);
simtrace_config = cfgnum; if (cfgnum < ARRAY_SIZE(config_func_ptrs)) {
simtrace_config = cfgnum;
} else {
TRACE_ERROR("trying to set out of bounds config %u\r\n", cfgnum);
}
} }
void USART1_IrqHandler(void) void USART1_IrqHandler(void)
{ {
config_func_ptrs[simtrace_config].usart1_irq(); if (config_func_ptrs[simtrace_config].usart1_irq)
config_func_ptrs[simtrace_config].usart1_irq();
} }
void USART0_IrqHandler(void) void USART0_IrqHandler(void)
{ {
config_func_ptrs[simtrace_config].usart0_irq(); if (config_func_ptrs[simtrace_config].usart0_irq)
config_func_ptrs[simtrace_config].usart0_irq();
} }
/* returns '1' in case we should break any endless loop */ /* returns '1' in case we should break any endless loop */
@@ -106,7 +130,8 @@ static void check_exec_dbg_cmd(void)
return; return;
ch = UART_GetChar(); ch = UART_GetChar();
/* We must echo the character to make python fdexpect happy, which we use in factory testing */
fputc(ch, stdout);
board_exec_dbg_cmd(ch); board_exec_dbg_cmd(ch);
} }
@@ -121,26 +146,42 @@ extern int main(void)
unsigned int i = 0; unsigned int i = 0;
led_init(); led_init();
led_blink(LED_RED, BLINK_3O_5F); led_blink(LED_RED, BLINK_ALWAYS_ON);
led_blink(LED_GREEN, BLINK_ALWAYS_ON);
/* Enable watchdog for 500ms, with no window */ /* Enable watchdog for 2000ms, with no window */
WDT_Enable(WDT, WDT_MR_WDRSTEN | WDT_MR_WDDBGHLT | WDT_MR_WDIDLEHLT | WDT_Enable(WDT, WDT_MR_WDRSTEN | WDT_MR_WDDBGHLT | WDT_MR_WDIDLEHLT |
(WDT_GetPeriod(500) << 16) | WDT_GetPeriod(500)); (WDT_GetPeriod(2000) << 16) | WDT_GetPeriod(2000));
PIO_InitializeInterrupts(0); PIO_InitializeInterrupts(0);
EEFC_ReadUniqueID(g_unique_id); EEFC_ReadUniqueID(g_unique_id);
printf("\n\r\n\r" printf("\n\r\n\r"
"=============================================================================\n\r" "=============================================================================\n\r"
"SIMtrace2 firmware " GIT_VERSION " (C) 2010-2016 by Harald Welte\n\r" "SIMtrace2 firmware " GIT_VERSION "\n\r"
"(C) 2010-2017 by Harald Welte, 2018-2019 by Kevin Redon\n\r"
"=============================================================================\n\r"); "=============================================================================\n\r");
TRACE_INFO("Chip ID: 0x%08x (Ext 0x%08x)\n\r", CHIPID->CHIPID_CIDR, CHIPID->CHIPID_EXID); #if (TRACE_LEVEL >= TRACE_LEVEL_INFO)
TRACE_INFO("Chip ID: 0x%08lx (Ext 0x%08lx)\n\r", CHIPID->CHIPID_CIDR, CHIPID->CHIPID_EXID);
TRACE_INFO("Serial Nr. %08x-%08x-%08x-%08x\n\r", TRACE_INFO("Serial Nr. %08x-%08x-%08x-%08x\n\r",
g_unique_id[0], g_unique_id[1], g_unique_id[0], g_unique_id[1],
g_unique_id[2], g_unique_id[3]); g_unique_id[2], g_unique_id[3]);
TRACE_INFO("Reset Cause: 0x%x\n\r", (RSTC->RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Pos); uint8_t reset_cause = (RSTC->RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Pos;
static const char* reset_causes[] = {
"general reset (first power-up reset)",
"backup reset (return from backup mode)",
"watchdog reset (watchdog fault occurred)",
"software reset (processor reset required by the software)",
"user reset (NRST pin detected low)",
};
if (reset_cause < ARRAY_SIZE(reset_causes)) {
TRACE_INFO("Reset Cause: %s\n\r", reset_causes[reset_cause]);
} else {
TRACE_INFO("Reset Cause: 0x%lx\n\r", (RSTC->RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Pos);
}
#endif
board_main_top(); board_main_top();
@@ -169,7 +210,9 @@ extern int main(void)
} }
TRACE_INFO("calling init of config %u...\n\r", simtrace_config); TRACE_INFO("calling init of config %u...\n\r", simtrace_config);
config_func_ptrs[simtrace_config].init(); if (config_func_ptrs[simtrace_config].init) {
config_func_ptrs[simtrace_config].init();
}
last_simtrace_config = simtrace_config; last_simtrace_config = simtrace_config;
TRACE_INFO("entering main loop...\n\r"); TRACE_INFO("entering main loop...\n\r");
@@ -197,11 +240,17 @@ extern int main(void)
if (last_simtrace_config != simtrace_config) { if (last_simtrace_config != simtrace_config) {
TRACE_INFO("USB config chg %u -> %u\n\r", TRACE_INFO("USB config chg %u -> %u\n\r",
last_simtrace_config, simtrace_config); last_simtrace_config, simtrace_config);
config_func_ptrs[last_simtrace_config].exit(); if (config_func_ptrs[last_simtrace_config].exit) {
config_func_ptrs[simtrace_config].init(); config_func_ptrs[last_simtrace_config].exit();
}
if (config_func_ptrs[simtrace_config].init) {
config_func_ptrs[simtrace_config].init();
}
last_simtrace_config = simtrace_config; last_simtrace_config = simtrace_config;
} else { } else {
config_func_ptrs[simtrace_config].run(); if (config_func_ptrs[simtrace_config].run) {
config_func_ptrs[simtrace_config].run();
}
} }
} }
} }

View File

@@ -1,8 +1,28 @@
/* SIMtrace 2 firmware USB DFU bootloader
*
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2018-2019 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "board.h" #include "board.h"
#include "utils.h" #include "utils.h"
#include "usb/device/dfu/dfu.h" #include "usb/device/dfu/dfu.h"
#include "usb/common/dfu/usb_dfu.h" #include "usb/common/dfu/usb_dfu.h"
#include "manifest.h" #include "manifest.h"
#include "USBD_HAL.h"
#include <osmocom/core/timer.h> #include <osmocom/core/timer.h>
@@ -10,6 +30,14 @@
#define ALTIF_FLASH 1 #define ALTIF_FLASH 1
unsigned int g_unique_id[4]; unsigned int g_unique_id[4];
/* remember if the watchdog has been configured in the main loop so we can kick it in the ISR */
static bool watchdog_configured = false;
/* There is not enough space in the 16 KiB DFU bootloader to include led.h functions */
#ifdef PINS_LEDS
/** LED pin configurations */
static const Pin pinsLeds[] = { PINS_LEDS } ;
#endif
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
* Callbacks * Callbacks
@@ -21,46 +49,85 @@ unsigned int g_unique_id[4];
#define IFLASH_END ((uint8_t *)IFLASH_ADDR + IFLASH_SIZE) #define IFLASH_END ((uint8_t *)IFLASH_ADDR + IFLASH_SIZE)
#define IRAM_END ((uint8_t *)IRAM_ADDR + IRAM_SIZE) #define IRAM_END ((uint8_t *)IRAM_ADDR + IRAM_SIZE)
/* incoming call-back: Host has transfered 'len' bytes (stored at /* incoming call-back: Host has transferred 'len' bytes (stored at
* 'data'), which we shall write to 'offset' into the partition * 'data'), which we shall write to 'offset' into the partition
* associated with 'altif'. Guaranted to be les than * associated with 'altif'. Guaranted to be less than
* BOARD_DFU_PAGE_SIZE */ * BOARD_DFU_PAGE_SIZE */
int USBDFU_handle_dnload(uint8_t altif, unsigned int offset, int USBDFU_handle_dnload(uint8_t altif, unsigned int offset,
uint8_t *data, unsigned int len) uint8_t *data, unsigned int len)
{ {
uint32_t addr; uint32_t addr;
unsigned int i;
int rc; int rc;
/* address of the last allocated variable on the stack */
uint32_t stack_addr = (uint32_t)&rc;
/* kick the dog to have enough time to flash */
if (watchdog_configured) {
WDT_Restart(WDT);
}
printf("dnload(altif=%u, offset=%u, len=%u)\n\r", altif, offset, len); #if TRACE_LEVEL >= TRACE_LEVEL_INFO
TRACE_INFO("dnload(altif=%u, offset=%u, len=%u)\n\r", altif, offset, len);
#else
printf("DL off=%u\n\r", offset);
#endif
#ifdef PINS_LEDS
PIO_Clear(&pinsLeds[LED_NUM_RED]);
#endif
switch (altif) { switch (altif) {
case ALTIF_RAM: case ALTIF_RAM:
addr = RAM_ADDR(offset); addr = RAM_ADDR(offset);
if (addr > IRAM_ADDR + IRAM_SIZE) { if (addr < IRAM_ADDR || addr + len >= IRAM_ADDR + IRAM_SIZE || addr + len >= stack_addr) {
g_dfu->state = DFU_STATE_dfuERROR; g_dfu->state = DFU_STATE_dfuERROR;
g_dfu->status = DFU_STATUS_errADDRESS; g_dfu->status = DFU_STATUS_errADDRESS;
return DFU_RET_STALL; rc = DFU_RET_STALL;
break;
} }
memcpy((void *)addr, data, len); memcpy((void *)addr, data, len);
return DFU_RET_ZLP; rc = DFU_RET_ZLP;
break;
case ALTIF_FLASH: case ALTIF_FLASH:
addr = FLASH_ADDR(offset); addr = FLASH_ADDR(offset);
if (addr > IFLASH_ADDR + IFLASH_SIZE) { if (addr < IFLASH_ADDR || addr + len >= IFLASH_ADDR + IFLASH_SIZE) {
g_dfu->state = DFU_STATE_dfuERROR; g_dfu->state = DFU_STATE_dfuERROR;
g_dfu->status = DFU_STATUS_errADDRESS; g_dfu->status = DFU_STATUS_errADDRESS;
return DFU_RET_STALL; rc = DFU_RET_STALL;
break;
}
rc = FLASHD_Unlock(addr, addr + len, 0, 0);
if (rc != 0) {
TRACE_ERROR("DFU download flash unlock failed\n\r");
rc = DFU_RET_STALL;
break;
} }
rc = FLASHD_Write(addr, data, len); rc = FLASHD_Write(addr, data, len);
if (rc != 0) { if (rc != 0) {
/* FIXME: set error codes */ TRACE_ERROR("DFU download flash erase failed\n\r");
return DFU_RET_STALL; rc = DFU_RET_STALL;
break;
} }
return DFU_RET_ZLP; for (i = 0; i < len; i++) {
if (((uint8_t*)addr)[i]!=data[i]) {
TRACE_ERROR("DFU download flash data written not correct\n\r");
rc = DFU_RET_STALL;
break;
}
}
rc = DFU_RET_ZLP;
break;
default: default:
/* FIXME: set error codes */
TRACE_ERROR("DFU download for unknown AltIf %d\n\r", altif); TRACE_ERROR("DFU download for unknown AltIf %d\n\r", altif);
return DFU_RET_STALL; rc = DFU_RET_STALL;
break;
} }
#ifdef PINS_LEDS
PIO_Set(&pinsLeds[LED_NUM_RED]);
#endif
return rc;
} }
/* incoming call-back: Host has requested to read back 'req_len' bytes /* incoming call-back: Host has requested to read back 'req_len' bytes
@@ -105,31 +172,10 @@ int USBDFU_handle_upload(uint8_t altif, unsigned int offset,
return req_len; return req_len;
} }
static int uart_has_loopback_jumper(void) /* can be overridden by board specific code, e.g. by pushbutton */
WEAK int board_override_enter_dfu(void)
{ {
unsigned int i; return 0;
const Pin uart_loopback_pins[] = {
{PIO_PA9A_URXD0, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT},
{PIO_PA10A_UTXD0, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
};
/* Configure UART pins as I/O */
PIO_Configure(uart_loopback_pins, PIO_LISTSIZE(uart_loopback_pins));
for (i = 0; i < 10; i++) {
/* Set TxD high; abort if RxD doesn't go high either */
PIO_Set(&uart_loopback_pins[1]);
if (!PIO_Get(&uart_loopback_pins[0]))
return 0;
/* Set TxD low, abort if RxD doesn't go low either */
PIO_Clear(&uart_loopback_pins[1]);
if (PIO_Get(&uart_loopback_pins[0]))
return 0;
}
/* if we reached here, RxD always follows TxD and thus a
* loopback jumper has been placed on RxD/TxD, and we will boot
* into DFU unconditionally */
return 1;
} }
/* using this function we can determine if we should enter DFU mode /* using this function we can determine if we should enter DFU mode
@@ -137,22 +183,30 @@ static int uart_has_loopback_jumper(void)
int USBDFU_OverrideEnterDFU(void) int USBDFU_OverrideEnterDFU(void)
{ {
uint32_t *app_part = (uint32_t *)FLASH_ADDR(0); uint32_t *app_part = (uint32_t *)FLASH_ADDR(0);
/* at the first call we are before the text segment has been relocated,
* so g_dfu is not initialized yet */
g_dfu = &_g_dfu;
if (USB_DFU_MAGIC == g_dfu->magic) {
return 1;
}
/* If the loopback jumper is set, we enter DFU mode */ /* If the loopback jumper is set, we enter DFU mode */
if (uart_has_loopback_jumper()) if (board_override_enter_dfu()) {
return 1; return 2;
}
/* if the first word of the application partition doesn't look /* if the first word of the application partition doesn't look
* like a stack pointer (i.e. point to RAM), enter DFU mode */ * like a stack pointer (i.e. point to RAM), enter DFU mode */
if ((app_part[0] < IRAM_ADDR) || if ((app_part[0] < IRAM_ADDR) || ((uint8_t *)app_part[0] > IRAM_END)) {
((uint8_t *)app_part[0] > IRAM_END)) return 3;
return 1; }
/* if the second word of the application partition doesn't look /* if the second word of the application partition doesn't look
* like a function from flash (reset vector), enter DFU mode */ * like a function from flash (reset vector), enter DFU mode */
if (((uint32_t *)app_part[1] < app_part) || if (((uint32_t *)app_part[1] < app_part) ||
((uint8_t *)app_part[1] > IFLASH_END)) ((uint8_t *)app_part[1] > IFLASH_END)) {
return 1; return 4;
}
return 0; return 0;
} }
@@ -180,23 +234,26 @@ extern int main(void)
unsigned int i = 0; unsigned int i = 0;
uint32_t reset_cause = (RSTC->RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Pos; uint32_t reset_cause = (RSTC->RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Pos;
#if 0 /* Enable watchdog for 2000ms, with no window */
led_init();
led_blink(LED_GREEN, BLINK_3O_30F);
led_blink(LED_RED, BLINK_3O_30F);
#endif
/* Enable watchdog for 500ms, with no window */
WDT_Enable(WDT, WDT_MR_WDRSTEN | WDT_MR_WDDBGHLT | WDT_MR_WDIDLEHLT | WDT_Enable(WDT, WDT_MR_WDRSTEN | WDT_MR_WDDBGHLT | WDT_MR_WDIDLEHLT |
(WDT_GetPeriod(500) << 16) | WDT_GetPeriod(500)); (WDT_GetPeriod(2000) << 16) | WDT_GetPeriod(2000));
watchdog_configured = true;
#ifdef PINS_LEDS
/* Configure LED */
PIO_Configure(pinsLeds, sizeof(pinsLeds));
PIO_Set(&pinsLeds[LED_NUM_RED]);
PIO_Clear(&pinsLeds[LED_NUM_GREEN]);
#endif
PIO_InitializeInterrupts(0); PIO_InitializeInterrupts(0);
EEFC_ReadUniqueID(g_unique_id); EEFC_ReadUniqueID(g_unique_id);
printf("\n\r\n\r" printf("\n\r\n\r"
"=============================================================================\n\r" "=============================================================================\n\r"
"DFU bootloader %s for board %s (C) 2010-2017 by Harald Welte\n\r" "DFU bootloader %s for board %s\n\r"
"(C) 2010-2017 by Harald Welte, 2018-2019 by Kevin Redon\n\r"
"=============================================================================\n\r", "=============================================================================\n\r",
manifest_revision, manifest_board); manifest_revision, manifest_board);
@@ -204,7 +261,36 @@ extern int main(void)
TRACE_INFO("Serial Nr. %08x-%08x-%08x-%08x\n\r", TRACE_INFO("Serial Nr. %08x-%08x-%08x-%08x\n\r",
g_unique_id[0], g_unique_id[1], g_unique_id[0], g_unique_id[1],
g_unique_id[2], g_unique_id[3]); g_unique_id[2], g_unique_id[3]);
TRACE_INFO("Reset Cause: 0x%x\n\r", reset_cause); TRACE_INFO("Reset Cause: 0x%lx\n\r", reset_cause);
#if (TRACE_LEVEL >= TRACE_LEVEL_INFO)
/* Find out why we are in the DFU bootloader, and not the main application */
TRACE_INFO("DFU bootloader start reason: ");
switch (USBDFU_OverrideEnterDFU()) {
case 0:
/* 0 normally means that there is no override, but we are in the bootloader,
* thus the first check in board_cstartup_gnu did return something else than 0.
* this can only be g_dfu->magic which is erased when the segment are
* relocated, which happens in board_cstartup_gnu just after USBDFU_OverrideEnterDFU.
* no static variable can be used to store this case since this will also be overwritten
*/
case 1:
TRACE_INFO_WP("DFU switch requested by main application\n\r");
break;
case 2:
TRACE_INFO_WP("bootloader forced (button pressed or jumper set)\n\r");
break;
case 3:
TRACE_INFO_WP("stack pointer (first application word) does no point in RAM\n\r");
break;
case 4: // the is no reason
TRACE_INFO_WP("reset vector (second application word) does no point in flash\n\r");
break;
default:
TRACE_INFO_WP("unknown\n\r");
break;
}
#endif
/* clear g_dfu on power-up reset */ /* clear g_dfu on power-up reset */
if (reset_cause == 0) if (reset_cause == 0)
@@ -213,6 +299,19 @@ extern int main(void)
board_main_top(); board_main_top();
TRACE_INFO("USB init...\n\r"); TRACE_INFO("USB init...\n\r");
/* Signal USB reset by disabling the pull-up on USB D+ for at least 10 ms */
#ifdef PIN_USB_PULLUP
const Pin usb_dp_pullup = PIN_USB_PULLUP;
PIO_Configure(&usb_dp_pullup, 1);
PIO_Set(&usb_dp_pullup);
#endif
USBD_HAL_Suspend();
mdelay(20);
#ifdef PIN_USB_PULLUP
PIO_Clear(&usb_dp_pullup);
#endif
USBD_HAL_Activate();
USBDFU_Initialize(&dfu_descriptors); USBDFU_Initialize(&dfu_descriptors);
while (USBD_GetState() < USBD_STATE_CONFIGURED) { while (USBD_GetState() < USBD_STATE_CONFIGURED) {
@@ -229,7 +328,9 @@ extern int main(void)
i++; i++;
} }
/* Initialize the flash to be able to write it, using the IAP ROM code */
FLASHD_Initialize(BOARD_MCK, 1); FLASHD_Initialize(BOARD_MCK, 1);
TRACE_INFO("entering main loop...\n\r"); TRACE_INFO("entering main loop...\n\r");
while (1) { while (1) {
WDT_Restart(WDT); WDT_Restart(WDT);

View File

@@ -1,5 +1,5 @@
sysmocom - s.f.m.c. GmbH sysmocom - s.f.m.c. GmbH
SIMtrace 2 compatible device SIMtrace 2 compatible device
DFU (Device Firmare Upgrade) DFU (Device Firmware Upgrade)
RAM RAM
Flash (Application Partition) Flash (Application Partition)

View File

@@ -0,0 +1,3 @@
C_FILES += $(C_LIBUSB_RT)
C_FILES += iso7816_4.c iso7816_fidi.c simtrace_iso7816.c sniffer.c usb.c

View File

@@ -0,0 +1,236 @@
/* SIMtrace 2 firmware sniffer application
*
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*------------------------------------------------------------------------------
* Headers
*------------------------------------------------------------------------------*/
#include "board.h"
#include "simtrace.h"
#include "utils.h"
#include "osmocom/core/timer.h"
unsigned int g_unique_id[4];
/*------------------------------------------------------------------------------
* Internal variables
*------------------------------------------------------------------------------*/
typedef struct {
/* static initialization, called whether or not the usb config is active */
void (*configure) (void);
/* initialization function after the config was selected */
void (*init) (void);
/* de-initialization before selecting new config */
void (*exit) (void);
/* main loop content for given configuration */
void (*run) (void);
/* Interrupt handler for USART0 */
void (*usart0_irq) (void);
/* Interrupt handler for USART1 */
void (*usart1_irq) (void);
} conf_func;
static const conf_func config_func_ptrs[] = {
/* array slot 0 is empty, usb configs start at 1 */
#ifdef HAVE_SNIFFER
[CFG_NUM_SNIFF] = {
.configure = Sniffer_configure,
.init = Sniffer_init,
.exit = Sniffer_exit,
.run = Sniffer_run,
.usart0_irq = Sniffer_usart0_irq,
.usart1_irq = Sniffer_usart1_irq,
},
#endif
#ifdef HAVE_CCID
[CFG_NUM_CCID] = {
.configure = CCID_configure,
.init = CCID_init,
.exit = CCID_exit,
.run = CCID_run,
},
#endif
#ifdef HAVE_CARDEM
[CFG_NUM_PHONE] = {
.configure = mode_cardemu_configure,
.init = mode_cardemu_init,
.exit = mode_cardemu_exit,
.run = mode_cardemu_run,
.usart0_irq = mode_cardemu_usart0_irq,
.usart1_irq = mode_cardemu_usart1_irq,
},
#endif
#ifdef HAVE_MITM
[CFG_NUM_MITM] = {
.configure = MITM_configure,
.init = MITM_init,
.exit = MITM_exit,
.run = MITM_run,
},
#endif
};
/*------------------------------------------------------------------------------
* Internal variables
*------------------------------------------------------------------------------*/
#if defined(HAVE_SNIFFER)
static volatile enum confNum simtrace_config = CFG_NUM_SNIFF;
#elif defined(HAVE_CARDEM)
static volatile enum confNum simtrace_config = CFG_NUM_PHONE;
#elif defined(HAVE_CCID)
static volatile enum confNum simtrace_config = CFG_NUM_CCID;
#endif
/*----------------------------------------------------------------------------
* Callbacks
*----------------------------------------------------------------------------*/
void USBDDriverCallbacks_ConfigurationChanged(uint8_t cfgnum)
{
TRACE_INFO_WP("cfgChanged%d ", cfgnum);
simtrace_config = cfgnum;
}
void USART1_IrqHandler(void)
{
if (config_func_ptrs[simtrace_config].usart1_irq)
config_func_ptrs[simtrace_config].usart1_irq();
}
void USART0_IrqHandler(void)
{
if (config_func_ptrs[simtrace_config].usart0_irq)
config_func_ptrs[simtrace_config].usart0_irq();
}
/* returns '1' in case we should break any endless loop */
static void check_exec_dbg_cmd(void)
{
int ch;
if (!UART_IsRxReady())
return;
ch = UART_GetChar();
board_exec_dbg_cmd(ch);
}
/*------------------------------------------------------------------------------
* Main
*------------------------------------------------------------------------------*/
#define MAX_USB_ITER BOARD_MCK/72 // This should be around a second
extern int main(void)
{
uint8_t isUsbConnected = 0;
enum confNum last_simtrace_config = simtrace_config;
unsigned int i = 0;
/* Configure LED output
* red on = power
* red blink = error
* green on = running
* green blink = activity
*/
led_init();
led_blink(LED_RED, BLINK_ALWAYS_ON);
led_blink(LED_GREEN, BLINK_ALWAYS_ON);
/* Enable watchdog for 2000 ms, with no window */
WDT_Enable(WDT, WDT_MR_WDRSTEN | WDT_MR_WDDBGHLT | WDT_MR_WDIDLEHLT |
(WDT_GetPeriod(2000) << 16) | WDT_GetPeriod(2000));
PIO_InitializeInterrupts(0);
EEFC_ReadUniqueID(g_unique_id);
printf("\n\r\n\r"
"=============================================================================\n\r"
"SIMtrace2 firmware " GIT_VERSION " (C) 2010-2016 by Harald Welte\n\r"
"=============================================================================\n\r");
TRACE_INFO("Chip ID: 0x%08lx (Ext 0x%08lx)\n\r", CHIPID->CHIPID_CIDR, CHIPID->CHIPID_EXID);
TRACE_INFO("Serial Nr. %08x-%08x-%08x-%08x\n\r",
g_unique_id[0], g_unique_id[1],
g_unique_id[2], g_unique_id[3]);
TRACE_INFO("Reset Cause: 0x%lx\n\r", (RSTC->RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Pos);
TRACE_INFO("USB configuration used: %d\n\r", simtrace_config);
board_main_top();
TRACE_INFO("USB init...\n\r");
SIMtrace_USB_Initialize();
while (USBD_GetState() < USBD_STATE_CONFIGURED) {
WDT_Restart(WDT);
check_exec_dbg_cmd();
#if 0
if (i >= MAX_USB_ITER * 3) {
TRACE_ERROR("Resetting board (USB could "
"not be configured)\n\r");
USBD_Disconnect();
NVIC_SystemReset();
}
#endif
i++;
}
TRACE_INFO("calling configure of all configurations...\n\r");
for (i = 1; i < ARRAY_SIZE(config_func_ptrs); i++) {
if (config_func_ptrs[i].configure)
config_func_ptrs[i].configure();
}
TRACE_INFO("calling init of config %u...\n\r", simtrace_config);
config_func_ptrs[simtrace_config].init();
last_simtrace_config = simtrace_config;
TRACE_INFO("entering main loop...\n\r");
while (1) {
WDT_Restart(WDT);
#if TRACE_LEVEL >= TRACE_LEVEL_DEBUG
const char rotor[] = { '-', '\\', '|', '/' };
putchar('\b');
putchar(rotor[i++ % ARRAY_SIZE(rotor)]);
#endif
check_exec_dbg_cmd();
osmo_timers_prepare();
osmo_timers_update();
if (USBD_GetState() < USBD_STATE_CONFIGURED) {
if (isUsbConnected) {
isUsbConnected = 0;
}
} else if (isUsbConnected == 0) {
TRACE_INFO("USB is now configured\n\r");
isUsbConnected = 1;
}
if (last_simtrace_config != simtrace_config) {
TRACE_INFO("USB config chg %u -> %u\n\r",
last_simtrace_config, simtrace_config);
config_func_ptrs[last_simtrace_config].exit();
config_func_ptrs[simtrace_config].init();
last_simtrace_config = simtrace_config;
} else {
config_func_ptrs[simtrace_config].run();
}
}
}

View File

@@ -0,0 +1,10 @@
sysmocom - s.f.m.c. GmbH
SIMtrace 2 compatible device
SIMtrace Sniffer
SIMtrace CCID
SIMtrace Phone
SIMtrace MITM
CardEmulator Modem 1
CardEmulator Modem 2
CardEmulator Modem 3
CardEmulator Modem 4

View File

@@ -1,3 +1,3 @@
C_FILES += $(C_LIBUSB_RT) C_FILES += $(C_LIBUSB_RT)
C_FILES += card_emu.c ccid.c iso7816_4.c iso7816_fidi.c mitm.c mode_cardemu.c simtrace_iso7816.c sniffer.c tc_etu.c usb.c C_FILES += card_emu.c iso7816_4.c iso7816_fidi.c mitm.c mode_cardemu.c mode_ccid.c simtrace_iso7816.c sniffer.c tc_etu.c usb.c

View File

@@ -1,4 +1,21 @@
// FIXME: Copyright license here /* SIMtrace 2 firmware card emulation, CCID, and sniffer application
*
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
* Headers * Headers
*------------------------------------------------------------------------------*/ *------------------------------------------------------------------------------*/
@@ -7,7 +24,7 @@
#include "simtrace.h" #include "simtrace.h"
#include "utils.h" #include "utils.h"
#include "req_ctx.h" #include "req_ctx.h"
#include "osmocom/core/timer.h" #include <osmocom/core/timer.h>
unsigned int g_unique_id[4]; unsigned int g_unique_id[4];
@@ -134,7 +151,7 @@ extern int main(void)
EEFC_ReadUniqueID(g_unique_id); EEFC_ReadUniqueID(g_unique_id);
printf("\r\n\r\n" printf("\r\n\r\n"
"=============================================================================\r\n" "=============================================================================\r\n"
"SIMtrace2 firmware " GIT_REVISION " (C) 2010-2017 by Harald Welte\r\n" "SIMtrace2 firmware " GIT_REVISION " (C) 2010-2017 by Harald Welte\r\n"
"=============================================================================\r\n"); "=============================================================================\r\n");

View File

@@ -1,113 +1,113 @@
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support * ATMEL Microcontroller Software Support
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* Copyright (c) 2009, Atmel Corporation * Copyright (c) 2009, Atmel Corporation
* *
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* *
* - Redistributions of source code must retain the above copyright notice, * - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below. * this list of conditions and the disclaimer below.
* *
* Atmel's name may not be used to endorse or promote products derived from * Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission. * this software without specific prior written permission.
* *
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
/** /**
* \file * \file
* *
* \section Purpose * \section Purpose
* *
* Interface for configuration the Enhanced Embedded Flash Controller (EEFC) peripheral. * Interface for configuration the Enhanced Embedded Flash Controller (EEFC) peripheral.
* *
* \section Usage * \section Usage
* *
* -# Enable/disable %flash ready interrupt sources using EFC_EnableFrdyIt() * -# Enable/disable %flash ready interrupt sources using EFC_EnableFrdyIt()
* and EFC_DisableFrdyIt(). * and EFC_DisableFrdyIt().
* -# Translates the given address into which EEFC, page and offset values * -# Translates the given address into which EEFC, page and offset values
* for difference density %flash memory using EFC_TranslateAddress(). * for difference density %flash memory using EFC_TranslateAddress().
* -# Computes the address of a %flash access given the EFC, page and offset * -# Computes the address of a %flash access given the EFC, page and offset
* for difference density %flash memory using EFC_ComputeAddress(). * for difference density %flash memory using EFC_ComputeAddress().
* -# Start the executing command with EFC_StartCommand() * -# Start the executing command with EFC_StartCommand()
* -# Retrieve the current status of the EFC using EFC_GetStatus(). * -# Retrieve the current status of the EFC using EFC_GetStatus().
* -# Retrieve the result of the last executed command with EFC_GetResult(). * -# Retrieve the result of the last executed command with EFC_GetResult().
*/ */
#ifndef _EEFC_ #ifndef _EEFC_
#define _EEFC_ #define _EEFC_
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
* Headers * Headers
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#include "chip.h" #include "chip.h"
#include <stdint.h> #include <stdint.h>
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
* Definitions * Definitions
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
/* EFC command */ /* EFC command */
#define EFC_FCMD_GETD 0x00 #define EFC_FCMD_GETD 0x00
#define EFC_FCMD_WP 0x01 #define EFC_FCMD_WP 0x01
#define EFC_FCMD_WPL 0x02 #define EFC_FCMD_WPL 0x02
#define EFC_FCMD_EWP 0x03 #define EFC_FCMD_EWP 0x03
#define EFC_FCMD_EWPL 0x04 #define EFC_FCMD_EWPL 0x04
#define EFC_FCMD_EA 0x05 #define EFC_FCMD_EA 0x05
#define EFC_FCMD_SLB 0x08 #define EFC_FCMD_SLB 0x08
#define EFC_FCMD_CLB 0x09 #define EFC_FCMD_CLB 0x09
#define EFC_FCMD_GLB 0x0A #define EFC_FCMD_GLB 0x0A
#define EFC_FCMD_SFB 0x0B #define EFC_FCMD_SFB 0x0B
#define EFC_FCMD_CFB 0x0C #define EFC_FCMD_CFB 0x0C
#define EFC_FCMD_GFB 0x0D #define EFC_FCMD_GFB 0x0D
#define EFC_FCMD_STUI 0x0E /* Start unique ID */ #define EFC_FCMD_STUI 0x0E /* Start unique ID */
#define EFC_FCMD_SPUI 0x0F /* Stop unique ID */ #define EFC_FCMD_SPUI 0x0F /* Stop unique ID */
/* The IAP function entry addreass */ /* The IAP function entry addreass */
#define CHIP_FLASH_IAP_ADDRESS (0x00800008) #define CHIP_FLASH_IAP_ADDRESS (0x00800008)
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
* Exported functions * Exported functions
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
extern void EFC_EnableFrdyIt( Efc* efc ) ; extern void EFC_EnableFrdyIt( Efc* efc ) ;
extern void EFC_DisableFrdyIt( Efc* efc ) ; extern void EFC_DisableFrdyIt( Efc* efc ) ;
extern void EFC_SetWaitState( Efc* efc, uint8_t cycles ) ; extern void EFC_SetWaitState( Efc* efc, uint8_t cycles ) ;
extern void EFC_TranslateAddress( Efc** pEfc, uint32_t dwAddress, uint16_t *pwPage, uint16_t *pwOffset ) ; extern void EFC_TranslateAddress( Efc** pEfc, uint32_t dwAddress, uint16_t *pwPage, uint16_t *pwOffset ) ;
extern void EFC_ComputeAddress( Efc* efc, uint16_t wPage, uint16_t wOffset, uint32_t *pdwAddress ) ; extern void EFC_ComputeAddress( Efc* efc, uint16_t wPage, uint16_t wOffset, uint32_t *pdwAddress ) ;
extern void EFC_StartCommand( Efc* efc, uint32_t dwCommand, uint32_t dwArgument ) ; extern void EFC_StartCommand( Efc* efc, uint32_t dwCommand, uint32_t dwArgument ) ;
extern uint32_t EFC_PerformCommand( Efc* efc, uint32_t dwCommand, uint32_t dwArgument, uint32_t dwUseIAP ) ; extern uint32_t EFC_PerformCommand( Efc* efc, uint32_t dwCommand, uint32_t dwArgument, uint32_t dwUseIAP ) ;
extern uint32_t EFC_GetStatus( Efc* efc ) ; extern uint32_t EFC_GetStatus( Efc* efc ) ;
extern uint32_t EFC_GetResult( Efc* efc ) ; extern uint32_t EFC_GetResult( Efc* efc ) ;
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* #ifndef _EEFC_ */ #endif /* #ifndef _EEFC_ */

View File

@@ -1,79 +1,79 @@
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support * ATMEL Microcontroller Software Support
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* Copyright (c) 2009, Atmel Corporation * Copyright (c) 2009, Atmel Corporation
* *
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* *
* - Redistributions of source code must retain the above copyright notice, * - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below. * this list of conditions and the disclaimer below.
* *
* Atmel's name may not be used to endorse or promote products derived from * Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission. * this software without specific prior written permission.
* *
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
/** /**
* \file * \file
* *
* The flash driver provides the unified interface for flash program operations. * The flash driver provides the unified interface for flash program operations.
* *
*/ */
#ifndef _FLASHD_ #ifndef _FLASHD_
#define _FLASHD_ #define _FLASHD_
#include <stdint.h> #include <stdint.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
* Exported functions * Exported functions
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
extern void FLASHD_Initialize( uint32_t dwMCk, uint32_t dwUseIAP ) ; extern void FLASHD_Initialize( uint32_t dwMCk, uint32_t dwUseIAP ) ;
extern uint32_t FLASHD_Erase( uint32_t dwAddress ) ; extern uint32_t FLASHD_Erase( uint32_t dwAddress ) ;
extern uint32_t FLASHD_Write( uint32_t dwAddress, const void *pvBuffer, uint32_t dwSize ) ; extern uint32_t FLASHD_Write( uint32_t dwAddress, const void *pvBuffer, uint32_t dwSize ) ;
extern uint32_t FLASHD_Lock( uint32_t dwStart, uint32_t dwEnd, uint32_t *pdwActualStart, uint32_t *pdwActualEnd ) ; extern uint32_t FLASHD_Lock( uint32_t dwStart, uint32_t dwEnd, uint32_t *pdwActualStart, uint32_t *pdwActualEnd ) ;
extern uint32_t FLASHD_Unlock( uint32_t dwStart, uint32_t dwEnd, uint32_t *pdwActualStart, uint32_t *pdwActualEnd ) ; extern uint32_t FLASHD_Unlock( uint32_t dwStart, uint32_t dwEnd, uint32_t *pdwActualStart, uint32_t *pdwActualEnd ) ;
extern uint32_t FLASHD_IsLocked( uint32_t dwStart, uint32_t dwEnd ) ; extern uint32_t FLASHD_IsLocked( uint32_t dwStart, uint32_t dwEnd ) ;
extern uint32_t FLASHD_SetGPNVM( uint8_t gpnvm ) ; extern uint32_t FLASHD_SetGPNVM( uint8_t gpnvm ) ;
extern uint32_t FLASHD_ClearGPNVM( uint8_t gpnvm ) ; extern uint32_t FLASHD_ClearGPNVM( uint8_t gpnvm ) ;
extern uint32_t FLASHD_IsGPNVMSet( uint8_t gpnvm ) ; extern uint32_t FLASHD_IsGPNVMSet( uint8_t gpnvm ) ;
#define FLASHD_IsSecurityBitSet() FLASHD_IsGPNVMSet( 0 ) #define FLASHD_IsSecurityBitSet() FLASHD_IsGPNVMSet( 0 )
#define FLASHD_SetSecurityBit() FLASHD_SetGPNVM( 0 ) #define FLASHD_SetSecurityBit() FLASHD_SetGPNVM( 0 )
extern uint32_t FLASHD_ReadUniqueID( uint32_t* pdwUniqueID ) ; extern uint32_t FLASHD_ReadUniqueID( uint32_t* pdwUniqueID ) ;
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* #ifndef _FLASHD_ */ #endif /* #ifndef _FLASHD_ */

View File

@@ -1,290 +1,290 @@
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support * ATMEL Microcontroller Software Support
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* Copyright (c) 2009, Atmel Corporation * Copyright (c) 2009, Atmel Corporation
* *
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* *
* - Redistributions of source code must retain the above copyright notice, * - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below. * this list of conditions and the disclaimer below.
* *
* Atmel's name may not be used to endorse or promote products derived from * Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission. * this software without specific prior written permission.
* *
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
/** \addtogroup efc_module Working with EEFC /** \addtogroup efc_module Working with EEFC
* The EEFC driver provides the interface to configure and use the EEFC * The EEFC driver provides the interface to configure and use the EEFC
* peripheral. * peripheral.
* *
* The user needs to set the number of wait states depending on the frequency used.\n * The user needs to set the number of wait states depending on the frequency used.\n
* Configure number of cycles for flash read/write operations in the FWS field of EEFC_FMR. * Configure number of cycles for flash read/write operations in the FWS field of EEFC_FMR.
* *
* It offers a function to send flash command to EEFC and waits for the * It offers a function to send flash command to EEFC and waits for the
* flash to be ready. * flash to be ready.
* *
* To send flash command, the user could do in either of following way: * To send flash command, the user could do in either of following way:
* <ul> * <ul>
* <li>Write a correct key, command and argument in EEFC_FCR. </li> * <li>Write a correct key, command and argument in EEFC_FCR. </li>
* <li>Or, Use IAP (In Application Programming) function which is executed from * <li>Or, Use IAP (In Application Programming) function which is executed from
* ROM directly, this allows flash programming to be done by code running in flash.</li> * ROM directly, this allows flash programming to be done by code running in flash.</li>
* <li>Once the command is achieved, it can be detected even by polling EEFC_FSR or interrupt. * <li>Once the command is achieved, it can be detected even by polling EEFC_FSR or interrupt.
* </ul> * </ul>
* *
* The command argument could be a page number,GPNVM number or nothing, it depends on * The command argument could be a page number,GPNVM number or nothing, it depends on
* the command itself. Some useful functions in this driver could help user tranlate physical * the command itself. Some useful functions in this driver could help user tranlate physical
* flash address into a page number and vice verse. * flash address into a page number and vice verse.
* *
* For more accurate information, please look at the EEFC section of the * For more accurate information, please look at the EEFC section of the
* Datasheet. * Datasheet.
* *
* Related files :\n * Related files :\n
* \ref efc.c\n * \ref efc.c\n
* \ref efc.h.\n * \ref efc.h.\n
*/ */
/*@{*/ /*@{*/
/*@}*/ /*@}*/
/** /**
* \file * \file
* *
* Implementation of Enhanced Embedded Flash Controller (EEFC). * Implementation of Enhanced Embedded Flash Controller (EEFC).
* *
*/ */
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
* Headers * Headers
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#include "chip.h" #include "chip.h"
#include "efc.h" #include "efc.h"
#include <assert.h> #include <assert.h>
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
* Exported functions * Exported functions
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
/** /**
* \brief Enables the flash ready interrupt source on the EEFC peripheral. * \brief Enables the flash ready interrupt source on the EEFC peripheral.
* *
* \param efc Pointer to a Efc instance * \param efc Pointer to a Efc instance
*/ */
extern void EFC_EnableFrdyIt( Efc* efc ) extern void EFC_EnableFrdyIt( Efc* efc )
{ {
efc->EEFC_FMR |= EEFC_FMR_FRDY ; efc->EEFC_FMR |= EEFC_FMR_FRDY ;
} }
/** /**
* \brief Disables the flash ready interrupt source on the EEFC peripheral. * \brief Disables the flash ready interrupt source on the EEFC peripheral.
* *
* \param efc Pointer to a Efc instance * \param efc Pointer to a Efc instance
*/ */
extern void EFC_DisableFrdyIt( Efc* efc ) extern void EFC_DisableFrdyIt( Efc* efc )
{ {
efc->EEFC_FMR &= ~((uint32_t)EEFC_FMR_FRDY) ; efc->EEFC_FMR &= ~((uint32_t)EEFC_FMR_FRDY) ;
} }
/** /**
* \brief Set read/write wait state on the EEFC perpherial. * \brief Set read/write wait state on the EEFC perpherial.
* *
* \param efc Pointer to a Efc instance * \param efc Pointer to a Efc instance
* \param cycles the number of wait states in cycle. * \param cycles the number of wait states in cycle.
*/ */
extern void EFC_SetWaitState( Efc* efc, uint8_t ucCycles ) extern void EFC_SetWaitState( Efc* efc, uint8_t ucCycles )
{ {
uint32_t dwValue ; uint32_t dwValue ;
dwValue = efc->EEFC_FMR ; dwValue = efc->EEFC_FMR ;
dwValue &= ~((uint32_t)EEFC_FMR_FWS_Msk) ; dwValue &= ~((uint32_t)EEFC_FMR_FWS_Msk) ;
dwValue |= EEFC_FMR_FWS(ucCycles); dwValue |= EEFC_FMR_FWS(ucCycles);
efc->EEFC_FMR = dwValue ; efc->EEFC_FMR = dwValue ;
} }
/** /**
* \brief Returns the current status of the EEFC. * \brief Returns the current status of the EEFC.
* *
* \note Keep in mind that this function clears the value of some status bits (LOCKE, PROGE). * \note Keep in mind that this function clears the value of some status bits (LOCKE, PROGE).
* *
* \param efc Pointer to a Efc instance * \param efc Pointer to a Efc instance
*/ */
extern uint32_t EFC_GetStatus( Efc* efc ) extern uint32_t EFC_GetStatus( Efc* efc )
{ {
return efc->EEFC_FSR ; return efc->EEFC_FSR ;
} }
/** /**
* \brief Returns the result of the last executed command. * \brief Returns the result of the last executed command.
* *
* \param efc Pointer to a Efc instance * \param efc Pointer to a Efc instance
*/ */
extern uint32_t EFC_GetResult( Efc* efc ) extern uint32_t EFC_GetResult( Efc* efc )
{ {
return efc->EEFC_FRR ; return efc->EEFC_FRR ;
} }
/** /**
* \brief Translates the given address page and offset values. * \brief Translates the given address page and offset values.
* \note The resulting values are stored in the provided variables if they are not null. * \note The resulting values are stored in the provided variables if they are not null.
* *
* \param efc Pointer to a Efc instance * \param efc Pointer to a Efc instance
* \param address Address to translate. * \param address Address to translate.
* \param pPage First page accessed. * \param pPage First page accessed.
* \param pOffset Byte offset in first page. * \param pOffset Byte offset in first page.
*/ */
extern void EFC_TranslateAddress( Efc** ppEfc, uint32_t dwAddress, uint16_t* pwPage, uint16_t* pwOffset ) extern void EFC_TranslateAddress( Efc** ppEfc, uint32_t dwAddress, uint16_t* pwPage, uint16_t* pwOffset )
{ {
Efc *pEfc ; Efc *pEfc ;
uint16_t wPage ; uint16_t wPage ;
uint16_t wOffset ; uint16_t wOffset ;
assert( dwAddress >= IFLASH_ADDR ) ; assert( dwAddress >= IFLASH_ADDR ) ;
assert( dwAddress <= (IFLASH_ADDR + IFLASH_SIZE) ) ; assert( dwAddress <= (IFLASH_ADDR + IFLASH_SIZE) ) ;
pEfc = EFC ; pEfc = EFC ;
wPage = (dwAddress - IFLASH_ADDR) / IFLASH_PAGE_SIZE; wPage = (dwAddress - IFLASH_ADDR) / IFLASH_PAGE_SIZE;
wOffset = (dwAddress - IFLASH_ADDR) % IFLASH_PAGE_SIZE; wOffset = (dwAddress - IFLASH_ADDR) % IFLASH_PAGE_SIZE;
TRACE_DEBUG( "Translated 0x%08X to page=%d and offset=%d\n\r", dwAddress, wPage, wOffset ) ; TRACE_DEBUG( "Translated 0x%08X to page=%d and offset=%d\n\r", dwAddress, wPage, wOffset ) ;
/* Store values */ /* Store values */
if ( pEfc ) if ( pEfc )
{ {
*ppEfc = pEfc ; *ppEfc = pEfc ;
} }
if ( pwPage ) if ( pwPage )
{ {
*pwPage = wPage ; *pwPage = wPage ;
} }
if ( pwOffset ) if ( pwOffset )
{ {
*pwOffset = wOffset ; *pwOffset = wOffset ;
} }
} }
/** /**
* \brief Computes the address of a flash access given the page and offset. * \brief Computes the address of a flash access given the page and offset.
* *
* \param efc Pointer to a Efc instance * \param efc Pointer to a Efc instance
* \param page Page number. * \param page Page number.
* \param offset Byte offset inside page. * \param offset Byte offset inside page.
* \param pAddress Computed address (optional). * \param pAddress Computed address (optional).
*/ */
extern void EFC_ComputeAddress( Efc *efc, uint16_t wPage, uint16_t wOffset, uint32_t *pdwAddress ) extern void EFC_ComputeAddress( Efc *efc, uint16_t wPage, uint16_t wOffset, uint32_t *pdwAddress )
{ {
uint32_t dwAddress ; uint32_t dwAddress ;
assert( efc ) ; assert( efc ) ;
assert( wPage <= IFLASH_NB_OF_PAGES ) ; assert( wPage <= IFLASH_NB_OF_PAGES ) ;
assert( wOffset < IFLASH_PAGE_SIZE ) ; assert( wOffset < IFLASH_PAGE_SIZE ) ;
/* Compute address */ /* Compute address */
dwAddress = IFLASH_ADDR + wPage * IFLASH_PAGE_SIZE + wOffset ; dwAddress = IFLASH_ADDR + wPage * IFLASH_PAGE_SIZE + wOffset ;
/* Store result */ /* Store result */
if ( pdwAddress != NULL ) if ( pdwAddress != NULL )
{ {
*pdwAddress = dwAddress ; *pdwAddress = dwAddress ;
} }
} }
/** /**
* \brief Starts the executing the given command on the EEFC and returns as soon as the command is started. * \brief Starts the executing the given command on the EEFC and returns as soon as the command is started.
* *
* \note It does NOT set the FMCN field automatically. * \note It does NOT set the FMCN field automatically.
* \param efc Pointer to a Efc instance * \param efc Pointer to a Efc instance
* \param command Command to execute. * \param command Command to execute.
* \param argument Command argument (should be 0 if not used). * \param argument Command argument (should be 0 if not used).
*/ */
extern void EFC_StartCommand( Efc* efc, uint32_t dwCommand, uint32_t dwArgument ) extern void EFC_StartCommand( Efc* efc, uint32_t dwCommand, uint32_t dwArgument )
{ {
/* Check command & argument */ /* Check command & argument */
switch ( dwCommand ) switch ( dwCommand )
{ {
case EFC_FCMD_WP: case EFC_FCMD_WP:
case EFC_FCMD_WPL: case EFC_FCMD_WPL:
case EFC_FCMD_EWP: case EFC_FCMD_EWP:
case EFC_FCMD_EWPL: case EFC_FCMD_EWPL:
case EFC_FCMD_SLB: case EFC_FCMD_SLB:
case EFC_FCMD_CLB: case EFC_FCMD_CLB:
assert( dwArgument < IFLASH_NB_OF_PAGES ) ; assert( dwArgument < IFLASH_NB_OF_PAGES ) ;
break ; break ;
case EFC_FCMD_SFB: case EFC_FCMD_SFB:
case EFC_FCMD_CFB: case EFC_FCMD_CFB:
assert( dwArgument < 2 ) ; assert( dwArgument < 2 ) ;
break; break;
case EFC_FCMD_GETD: case EFC_FCMD_GETD:
case EFC_FCMD_EA: case EFC_FCMD_EA:
case EFC_FCMD_GLB: case EFC_FCMD_GLB:
case EFC_FCMD_GFB: case EFC_FCMD_GFB:
case EFC_FCMD_STUI: case EFC_FCMD_STUI:
assert( dwArgument == 0 ) ; assert( dwArgument == 0 ) ;
break; break;
default: assert( 0 ) ; default: assert( 0 ) ;
} }
/* Start command Embedded flash */ /* Start command Embedded flash */
assert( (efc->EEFC_FSR & EEFC_FMR_FRDY) == EEFC_FMR_FRDY ) ; assert( (efc->EEFC_FSR & EEFC_FMR_FRDY) == EEFC_FMR_FRDY ) ;
efc->EEFC_FCR = EEFC_FCR_FKEY(0x5A) | EEFC_FCR_FARG(dwArgument) | EEFC_FCR_FCMD(dwCommand) ; efc->EEFC_FCR = EEFC_FCR_FKEY(0x5A) | EEFC_FCR_FARG(dwArgument) | EEFC_FCR_FCMD(dwCommand) ;
} }
/** /**
* \brief Performs the given command and wait until its completion (or an error). * \brief Performs the given command and wait until its completion (or an error).
* *
* \param efc Pointer to a Efc instance * \param efc Pointer to a Efc instance
* \param command Command to perform. * \param command Command to perform.
* \param argument Optional command argument. * \param argument Optional command argument.
* *
* \return 0 if successful, otherwise returns an error code. * \return 0 if successful, otherwise returns an error code.
*/ */
extern uint32_t EFC_PerformCommand( Efc* efc, uint32_t dwCommand, uint32_t dwArgument, uint32_t dwUseIAP ) extern uint32_t EFC_PerformCommand( Efc* efc, uint32_t dwCommand, uint32_t dwArgument, uint32_t dwUseIAP )
{ {
if ( dwUseIAP != 0 ) if ( dwUseIAP != 0 )
{ {
/* Pointer on IAP function in ROM */ /* Pointer on IAP function in ROM */
static uint32_t (*IAP_PerformCommand)( uint32_t, uint32_t ) ; static uint32_t (*IAP_PerformCommand)( uint32_t, uint32_t ) ;
IAP_PerformCommand = (uint32_t (*)( uint32_t, uint32_t )) *((uint32_t*)CHIP_FLASH_IAP_ADDRESS ) ; IAP_PerformCommand = (uint32_t (*)( uint32_t, uint32_t )) *((uint32_t*)CHIP_FLASH_IAP_ADDRESS ) ;
IAP_PerformCommand( 0, EEFC_FCR_FKEY(0x5A) | EEFC_FCR_FARG(dwArgument) | EEFC_FCR_FCMD(dwCommand) ) ; IAP_PerformCommand( 0, EEFC_FCR_FKEY(0x5A) | EEFC_FCR_FARG(dwArgument) | EEFC_FCR_FCMD(dwCommand) ) ;
return (efc->EEFC_FSR & (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE)) ; return (efc->EEFC_FSR & (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE)) ;
} }
else else
{ {
uint32_t dwStatus ; uint32_t dwStatus ;
efc->EEFC_FCR = EEFC_FCR_FKEY(0x5A) | EEFC_FCR_FARG(dwArgument) | EEFC_FCR_FCMD(dwCommand) ; efc->EEFC_FCR = EEFC_FCR_FKEY(0x5A) | EEFC_FCR_FARG(dwArgument) | EEFC_FCR_FCMD(dwCommand) ;
do do
{ {
dwStatus = efc->EEFC_FSR ; dwStatus = efc->EEFC_FSR ;
} }
while ( (dwStatus & EEFC_FSR_FRDY) != EEFC_FSR_FRDY ) ; while ( (dwStatus & EEFC_FSR_FRDY) != EEFC_FSR_FRDY ) ;
return ( dwStatus & (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE) ) ; return ( dwStatus & (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE) ) ;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,453 +1,453 @@
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support * ATMEL Microcontroller Software Support
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* Copyright (c) 2010, Atmel Corporation * Copyright (c) 2010, Atmel Corporation
* *
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* *
* - Redistributions of source code must retain the above copyright notice, * - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below. * this list of conditions and the disclaimer below.
* *
* Atmel's name may not be used to endorse or promote products derived from * Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission. * this software without specific prior written permission.
* *
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
/** \file */ /** \file */
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
* Headers * Headers
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#include "chip.h" #include "chip.h"
#include "pio.h" #include "pio.h"
#include "pmc.h" #include "pmc.h"
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
* Local functions * Local functions
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
/** /**
* \brief Configures one or more pin(s) of a PIO controller as being controlled by * \brief Configures one or more pin(s) of a PIO controller as being controlled by
* peripheral A. Optionally, the corresponding internal pull-up(s) can be enabled. * peripheral A. Optionally, the corresponding internal pull-up(s) can be enabled.
* *
* \param pio Pointer to a PIO controller. * \param pio Pointer to a PIO controller.
* \param mask Bitmask of one or more pin(s) to configure. * \param mask Bitmask of one or more pin(s) to configure.
* \param enablePullUp Indicates if the pin(s) internal pull-up shall be * \param enablePullUp Indicates if the pin(s) internal pull-up shall be
* configured. * configured.
*/ */
static void PIO_SetPeripheralA( static void PIO_SetPeripheralA(
Pio *pio, Pio *pio,
unsigned int mask, unsigned int mask,
unsigned char enablePullUp) unsigned char enablePullUp)
{ {
unsigned int abcdsr; unsigned int abcdsr;
/* Disable interrupts on the pin(s) */ /* Disable interrupts on the pin(s) */
pio->PIO_IDR = mask; pio->PIO_IDR = mask;
/* Enable the pull-up(s) if necessary */ /* Enable the pull-up(s) if necessary */
if (enablePullUp) { if (enablePullUp) {
pio->PIO_PUER = mask; pio->PIO_PUER = mask;
} }
else { else {
pio->PIO_PUDR = mask; pio->PIO_PUDR = mask;
} }
abcdsr = pio->PIO_ABCDSR[0]; abcdsr = pio->PIO_ABCDSR[0];
pio->PIO_ABCDSR[0] &= (~mask & abcdsr); pio->PIO_ABCDSR[0] &= (~mask & abcdsr);
abcdsr = pio->PIO_ABCDSR[1]; abcdsr = pio->PIO_ABCDSR[1];
pio->PIO_ABCDSR[1] &= (~mask & abcdsr); pio->PIO_ABCDSR[1] &= (~mask & abcdsr);
pio->PIO_PDR = mask; pio->PIO_PDR = mask;
} }
/** /**
* \brief Configures one or more pin(s) of a PIO controller as being controlled by * \brief Configures one or more pin(s) of a PIO controller as being controlled by
* peripheral B. Optionally, the corresponding internal pull-up(s) can be enabled. * peripheral B. Optionally, the corresponding internal pull-up(s) can be enabled.
* *
* \param pio Pointer to a PIO controller. * \param pio Pointer to a PIO controller.
* \param mask Bitmask of one or more pin(s) to configure. * \param mask Bitmask of one or more pin(s) to configure.
* \param enablePullUp Indicates if the pin(s) internal pull-up shall be * \param enablePullUp Indicates if the pin(s) internal pull-up shall be
* configured. * configured.
*/ */
static void PIO_SetPeripheralB( static void PIO_SetPeripheralB(
Pio *pio, Pio *pio,
unsigned int mask, unsigned int mask,
unsigned char enablePullUp) unsigned char enablePullUp)
{ {
unsigned int abcdsr; unsigned int abcdsr;
/* Disable interrupts on the pin(s) */ /* Disable interrupts on the pin(s) */
pio->PIO_IDR = mask; pio->PIO_IDR = mask;
/* Enable the pull-up(s) if necessary */ /* Enable the pull-up(s) if necessary */
if (enablePullUp) { if (enablePullUp) {
pio->PIO_PUER = mask; pio->PIO_PUER = mask;
} }
else { else {
pio->PIO_PUDR = mask; pio->PIO_PUDR = mask;
} }
abcdsr = pio->PIO_ABCDSR[0]; abcdsr = pio->PIO_ABCDSR[0];
pio->PIO_ABCDSR[0] = (mask | abcdsr); pio->PIO_ABCDSR[0] = (mask | abcdsr);
abcdsr = pio->PIO_ABCDSR[1]; abcdsr = pio->PIO_ABCDSR[1];
pio->PIO_ABCDSR[1] &= (~mask & abcdsr); pio->PIO_ABCDSR[1] &= (~mask & abcdsr);
pio->PIO_PDR = mask; pio->PIO_PDR = mask;
} }
/** /**
* \brief Configures one or more pin(s) of a PIO controller as being controlled by * \brief Configures one or more pin(s) of a PIO controller as being controlled by
* peripheral C. Optionally, the corresponding internal pull-up(s) can be enabled. * peripheral C. Optionally, the corresponding internal pull-up(s) can be enabled.
* *
* \param pio Pointer to a PIO controller. * \param pio Pointer to a PIO controller.
* \param mask Bitmask of one or more pin(s) to configure. * \param mask Bitmask of one or more pin(s) to configure.
* \param enablePullUp Indicates if the pin(s) internal pull-up shall be * \param enablePullUp Indicates if the pin(s) internal pull-up shall be
* configured. * configured.
*/ */
static void PIO_SetPeripheralC( static void PIO_SetPeripheralC(
Pio *pio, Pio *pio,
unsigned int mask, unsigned int mask,
unsigned char enablePullUp) unsigned char enablePullUp)
{ {
unsigned int abcdsr; unsigned int abcdsr;
/* Disable interrupts on the pin(s) */ /* Disable interrupts on the pin(s) */
pio->PIO_IDR = mask; pio->PIO_IDR = mask;
/* Enable the pull-up(s) if necessary */ /* Enable the pull-up(s) if necessary */
if (enablePullUp) { if (enablePullUp) {
pio->PIO_PUER = mask; pio->PIO_PUER = mask;
} }
else { else {
pio->PIO_PUDR = mask; pio->PIO_PUDR = mask;
} }
abcdsr = pio->PIO_ABCDSR[0]; abcdsr = pio->PIO_ABCDSR[0];
pio->PIO_ABCDSR[0] &= (~mask & abcdsr); pio->PIO_ABCDSR[0] &= (~mask & abcdsr);
abcdsr = pio->PIO_ABCDSR[1]; abcdsr = pio->PIO_ABCDSR[1];
pio->PIO_ABCDSR[1] = (mask | abcdsr); pio->PIO_ABCDSR[1] = (mask | abcdsr);
pio->PIO_PDR = mask; pio->PIO_PDR = mask;
} }
/** /**
* \brief Configures one or more pin(s) of a PIO controller as being controlled by * \brief Configures one or more pin(s) of a PIO controller as being controlled by
* peripheral D. Optionally, the corresponding internal pull-up(s) can be enabled. * peripheral D. Optionally, the corresponding internal pull-up(s) can be enabled.
* *
* \param pio Pointer to a PIO controller. * \param pio Pointer to a PIO controller.
* \param mask Bitmask of one or more pin(s) to configure. * \param mask Bitmask of one or more pin(s) to configure.
* \param enablePullUp Indicates if the pin(s) internal pull-up shall be * \param enablePullUp Indicates if the pin(s) internal pull-up shall be
* configured. * configured.
*/ */
static void PIO_SetPeripheralD( static void PIO_SetPeripheralD(
Pio *pio, Pio *pio,
unsigned int mask, unsigned int mask,
unsigned char enablePullUp) unsigned char enablePullUp)
{ {
unsigned int abcdsr; unsigned int abcdsr;
/* Disable interrupts on the pin(s) */ /* Disable interrupts on the pin(s) */
pio->PIO_IDR = mask; pio->PIO_IDR = mask;
/* Enable the pull-up(s) if necessary */ /* Enable the pull-up(s) if necessary */
if (enablePullUp) { if (enablePullUp) {
pio->PIO_PUER = mask; pio->PIO_PUER = mask;
} }
else { else {
pio->PIO_PUDR = mask; pio->PIO_PUDR = mask;
} }
abcdsr = pio->PIO_ABCDSR[0]; abcdsr = pio->PIO_ABCDSR[0];
pio->PIO_ABCDSR[0] = (mask | abcdsr); pio->PIO_ABCDSR[0] = (mask | abcdsr);
abcdsr = pio->PIO_ABCDSR[1]; abcdsr = pio->PIO_ABCDSR[1];
pio->PIO_ABCDSR[1] = (mask | abcdsr); pio->PIO_ABCDSR[1] = (mask | abcdsr);
pio->PIO_PDR = mask; pio->PIO_PDR = mask;
} }
/** /**
* \brief Configures one or more pin(s) or a PIO controller as inputs. Optionally, * \brief Configures one or more pin(s) or a PIO controller as inputs. Optionally,
* the corresponding internal pull-up(s) and glitch filter(s) can be enabled. * the corresponding internal pull-up(s) and glitch filter(s) can be enabled.
* *
* \param pio Pointer to a PIO controller. * \param pio Pointer to a PIO controller.
* \param mask Bitmask indicating which pin(s) to configure as input(s). * \param mask Bitmask indicating which pin(s) to configure as input(s).
* \param enablePullUp Indicates if the internal pull-up(s) must be enabled. * \param enablePullUp Indicates if the internal pull-up(s) must be enabled.
* \param enableFilter Indicates if the glitch filter(s) must be enabled. * \param enableFilter Indicates if the glitch filter(s) must be enabled.
*/ */
static void PIO_SetInput( static void PIO_SetInput(
Pio *pio, Pio *pio,
unsigned int mask, unsigned int mask,
unsigned char attribute) unsigned char attribute)
{ {
/* Disable interrupts */ /* Disable interrupts */
pio->PIO_IDR = mask; pio->PIO_IDR = mask;
/* Enable pull-up(s) if necessary */ /* Enable pull-up(s) if necessary */
if (attribute & PIO_PULLUP) if (attribute & PIO_PULLUP)
pio->PIO_PUER = mask; pio->PIO_PUER = mask;
else else
pio->PIO_PUDR = mask; pio->PIO_PUDR = mask;
/* Enable Input Filter if necessary */ /* Enable Input Filter if necessary */
if (attribute & (PIO_DEGLITCH | PIO_DEBOUNCE)) if (attribute & (PIO_DEGLITCH | PIO_DEBOUNCE))
pio->PIO_IFER = mask; pio->PIO_IFER = mask;
else else
pio->PIO_IFDR = mask; pio->PIO_IFDR = mask;
/* Enable de-glitch or de-bounce if necessary */ /* Enable de-glitch or de-bounce if necessary */
if (attribute & PIO_DEGLITCH) if (attribute & PIO_DEGLITCH)
{ {
pio->PIO_IFSCDR = mask; pio->PIO_IFSCDR = mask;
} }
else else
{ {
if (attribute & PIO_DEBOUNCE) if (attribute & PIO_DEBOUNCE)
{ {
pio->PIO_IFSCER = mask; pio->PIO_IFSCER = mask;
} }
} }
/* Configure pin as input */ /* Configure pin as input */
pio->PIO_ODR = mask; pio->PIO_ODR = mask;
pio->PIO_PER = mask; pio->PIO_PER = mask;
} }
/** /**
* \brief Configures one or more pin(s) of a PIO controller as outputs, with the * \brief Configures one or more pin(s) of a PIO controller as outputs, with the
* given default value. Optionally, the multi-drive feature can be enabled * given default value. Optionally, the multi-drive feature can be enabled
* on the pin(s). * on the pin(s).
* *
* \param pio Pointer to a PIO controller. * \param pio Pointer to a PIO controller.
* \param mask Bitmask indicating which pin(s) to configure. * \param mask Bitmask indicating which pin(s) to configure.
* \param defaultValue Default level on the pin(s). * \param defaultValue Default level on the pin(s).
* \param enableMultiDrive Indicates if the pin(s) shall be configured as * \param enableMultiDrive Indicates if the pin(s) shall be configured as
* open-drain. * open-drain.
* \param enablePullUp Indicates if the pin shall have its pull-up activated. * \param enablePullUp Indicates if the pin shall have its pull-up activated.
*/ */
static void PIO_SetOutput( static void PIO_SetOutput(
Pio *pio, Pio *pio,
unsigned int mask, unsigned int mask,
unsigned char defaultValue, unsigned char defaultValue,
unsigned char enableMultiDrive, unsigned char enableMultiDrive,
unsigned char enablePullUp) unsigned char enablePullUp)
{ {
/* Disable interrupts */ /* Disable interrupts */
pio->PIO_IDR = mask; pio->PIO_IDR = mask;
/* Enable pull-up(s) if necessary */ /* Enable pull-up(s) if necessary */
if (enablePullUp) { if (enablePullUp) {
pio->PIO_PUER = mask; pio->PIO_PUER = mask;
} }
else { else {
pio->PIO_PUDR = mask; pio->PIO_PUDR = mask;
} }
/* Enable multi-drive if necessary */ /* Enable multi-drive if necessary */
if (enableMultiDrive) { if (enableMultiDrive) {
pio->PIO_MDER = mask; pio->PIO_MDER = mask;
} }
else { else {
pio->PIO_MDDR = mask; pio->PIO_MDDR = mask;
} }
/* Set default value */ /* Set default value */
if (defaultValue) { if (defaultValue) {
pio->PIO_SODR = mask; pio->PIO_SODR = mask;
} }
else { else {
pio->PIO_CODR = mask; pio->PIO_CODR = mask;
} }
/* Configure pin(s) as output(s) */ /* Configure pin(s) as output(s) */
pio->PIO_OER = mask; pio->PIO_OER = mask;
pio->PIO_PER = mask; pio->PIO_PER = mask;
} }
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
* Global functions * Global functions
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
/** /**
* \brief Configures a list of Pin instances, each of which can either hold a single * \brief Configures a list of Pin instances, each of which can either hold a single
* pin or a group of pins, depending on the mask value; all pins are configured * pin or a group of pins, depending on the mask value; all pins are configured
* by this function. The size of the array must also be provided and is easily * by this function. The size of the array must also be provided and is easily
* computed using PIO_LISTSIZE whenever its length is not known in advance. * computed using PIO_LISTSIZE whenever its length is not known in advance.
* *
* \param list Pointer to a list of Pin instances. * \param list Pointer to a list of Pin instances.
* \param size Size of the Pin list (calculated using PIO_LISTSIZE). * \param size Size of the Pin list (calculated using PIO_LISTSIZE).
* *
* \return 1 if the pins have been configured properly; otherwise 0. * \return 1 if the pins have been configured properly; otherwise 0.
*/ */
uint8_t PIO_Configure( const Pin *list, uint32_t size ) uint8_t PIO_Configure( const Pin *list, uint32_t size )
{ {
/* Configure pins */ /* Configure pins */
while ( size > 0 ) while ( size > 0 )
{ {
switch ( list->type ) switch ( list->type )
{ {
case PIO_PERIPH_A: case PIO_PERIPH_A:
PIO_SetPeripheralA(list->pio, PIO_SetPeripheralA(list->pio,
list->mask, list->mask,
(list->attribute & PIO_PULLUP) ? 1 : 0); (list->attribute & PIO_PULLUP) ? 1 : 0);
break; break;
case PIO_PERIPH_B: case PIO_PERIPH_B:
PIO_SetPeripheralB(list->pio, PIO_SetPeripheralB(list->pio,
list->mask, list->mask,
(list->attribute & PIO_PULLUP) ? 1 : 0); (list->attribute & PIO_PULLUP) ? 1 : 0);
break; break;
case PIO_PERIPH_C: case PIO_PERIPH_C:
PIO_SetPeripheralC(list->pio, PIO_SetPeripheralC(list->pio,
list->mask, list->mask,
(list->attribute & PIO_PULLUP) ? 1 : 0); (list->attribute & PIO_PULLUP) ? 1 : 0);
break; break;
case PIO_PERIPH_D: case PIO_PERIPH_D:
PIO_SetPeripheralD(list->pio, PIO_SetPeripheralD(list->pio,
list->mask, list->mask,
(list->attribute & PIO_PULLUP) ? 1 : 0); (list->attribute & PIO_PULLUP) ? 1 : 0);
break; break;
case PIO_INPUT: case PIO_INPUT:
PMC_EnablePeripheral(list->id); PMC_EnablePeripheral(list->id);
PIO_SetInput(list->pio, PIO_SetInput(list->pio,
list->mask, list->mask,
list->attribute); list->attribute);
break; break;
case PIO_OUTPUT_0: case PIO_OUTPUT_0:
case PIO_OUTPUT_1: case PIO_OUTPUT_1:
PIO_SetOutput(list->pio, PIO_SetOutput(list->pio,
list->mask, list->mask,
(list->type == PIO_OUTPUT_1), (list->type == PIO_OUTPUT_1),
(list->attribute & PIO_OPENDRAIN) ? 1 : 0, (list->attribute & PIO_OPENDRAIN) ? 1 : 0,
(list->attribute & PIO_PULLUP) ? 1 : 0); (list->attribute & PIO_PULLUP) ? 1 : 0);
break; break;
default: return 0; default: return 0;
} }
list++; list++;
size--; size--;
} }
return 1; return 1;
} }
/** /**
* \brief Sets a high output level on all the PIOs defined in the given Pin instance. * \brief Sets a high output level on all the PIOs defined in the given Pin instance.
* This has no immediate effects on PIOs that are not output, but the PIO * This has no immediate effects on PIOs that are not output, but the PIO
* controller will memorize the value they are changed to outputs. * controller will memorize the value they are changed to outputs.
* *
* \param pin Pointer to a Pin instance describing one or more pins. * \param pin Pointer to a Pin instance describing one or more pins.
*/ */
void PIO_Set(const Pin *pin) void PIO_Set(const Pin *pin)
{ {
pin->pio->PIO_SODR = pin->mask; pin->pio->PIO_SODR = pin->mask;
} }
/** /**
* \brief Sets a low output level on all the PIOs defined in the given Pin instance. * \brief Sets a low output level on all the PIOs defined in the given Pin instance.
* This has no immediate effects on PIOs that are not output, but the PIO * This has no immediate effects on PIOs that are not output, but the PIO
* controller will memorize the value they are changed to outputs. * controller will memorize the value they are changed to outputs.
* *
* \param pin Pointer to a Pin instance describing one or more pins. * \param pin Pointer to a Pin instance describing one or more pins.
*/ */
void PIO_Clear(const Pin *pin) void PIO_Clear(const Pin *pin)
{ {
pin->pio->PIO_CODR = pin->mask; pin->pio->PIO_CODR = pin->mask;
} }
/** /**
* \brief Returns 1 if one or more PIO of the given Pin instance currently have * \brief Returns 1 if one or more PIO of the given Pin instance currently have
* a high level; otherwise returns 0. This method returns the actual value that * a high level; otherwise returns 0. This method returns the actual value that
* is being read on the pin. To return the supposed output value of a pin, use * is being read on the pin. To return the supposed output value of a pin, use
* PIO_GetOutputDataStatus() instead. * PIO_GetOutputDataStatus() instead.
* *
* \param pin Pointer to a Pin instance describing one or more pins. * \param pin Pointer to a Pin instance describing one or more pins.
* *
* \return 1 if the Pin instance contains at least one PIO that currently has * \return 1 if the Pin instance contains at least one PIO that currently has
* a high level; otherwise 0. * a high level; otherwise 0.
*/ */
unsigned char PIO_Get( const Pin *pin ) unsigned char PIO_Get( const Pin *pin )
{ {
unsigned int reg ; unsigned int reg ;
if ( (pin->type == PIO_OUTPUT_0) || (pin->type == PIO_OUTPUT_1) ) if ( (pin->type == PIO_OUTPUT_0) || (pin->type == PIO_OUTPUT_1) )
{ {
reg = pin->pio->PIO_ODSR ; reg = pin->pio->PIO_ODSR ;
} }
else else
{ {
reg = pin->pio->PIO_PDSR ; reg = pin->pio->PIO_PDSR ;
} }
if ( (reg & pin->mask) == 0 ) if ( (reg & pin->mask) == 0 )
{ {
return 0 ; return 0 ;
} }
else else
{ {
return 1 ; return 1 ;
} }
} }
/** /**
* \brief Returns 1 if one or more PIO of the given Pin are configured to output a * \brief Returns 1 if one or more PIO of the given Pin are configured to output a
* high level (even if they are not output). * high level (even if they are not output).
* To get the actual value of the pin, use PIO_Get() instead. * To get the actual value of the pin, use PIO_Get() instead.
* *
* \param pin Pointer to a Pin instance describing one or more pins. * \param pin Pointer to a Pin instance describing one or more pins.
* *
* \return 1 if the Pin instance contains at least one PIO that is configured * \return 1 if the Pin instance contains at least one PIO that is configured
* to output a high level; otherwise 0. * to output a high level; otherwise 0.
*/ */
unsigned char PIO_GetOutputDataStatus(const Pin *pin) unsigned char PIO_GetOutputDataStatus(const Pin *pin)
{ {
if ((pin->pio->PIO_ODSR & pin->mask) == 0) { if ((pin->pio->PIO_ODSR & pin->mask) == 0) {
return 0; return 0;
} }
else { else {
return 1; return 1;
} }
} }
/* /*
* \brief Configures Glitch or Debouncing filter for input. * \brief Configures Glitch or Debouncing filter for input.
* *
* \param pin Pointer to a Pin instance describing one or more pins. * \param pin Pointer to a Pin instance describing one or more pins.
* \param cuttoff Cutt off frequency for debounce filter. * \param cuttoff Cutt off frequency for debounce filter.
*/ */
void PIO_SetDebounceFilter( const Pin *pin, uint32_t cuttoff ) void PIO_SetDebounceFilter( const Pin *pin, uint32_t cuttoff )
{ {
Pio *pio = pin->pio; Pio *pio = pin->pio;
pio->PIO_IFSCER = pin->mask; /* set Debouncing, 0 bit field no effect */ pio->PIO_IFSCER = pin->mask; /* set Debouncing, 0 bit field no effect */
pio->PIO_SCDR = ((32678/(2*(cuttoff))) - 1) & 0x3FFF; /* the lowest 14 bits work */ pio->PIO_SCDR = ((32678/(2*(cuttoff))) - 1) & 0x3FFF; /* the lowest 14 bits work */
} }

View File

@@ -1,315 +1,315 @@
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support * ATMEL Microcontroller Software Support
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* Copyright (c) 2008, Atmel Corporation * Copyright (c) 2008, Atmel Corporation
* *
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* *
* - Redistributions of source code must retain the above copyright notice, * - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below. * this list of conditions and the disclaimer below.
* *
* Atmel's name may not be used to endorse or promote products derived from * Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission. * this software without specific prior written permission.
* *
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
/* /*
* \file * \file
*/ */
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
* Headers * Headers
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#include "chip.h" #include "chip.h"
#include <assert.h> #include <assert.h>
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
* Local definitions * Local definitions
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
/* Maximum number of interrupt sources that can be defined. This /* Maximum number of interrupt sources that can be defined. This
* constant can be increased, but the current value is the smallest possible * constant can be increased, but the current value is the smallest possible
* that will be compatible with all existing projects. */ * that will be compatible with all existing projects. */
#define MAX_INTERRUPT_SOURCES 7 #define MAX_INTERRUPT_SOURCES 7
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
* Local types * Local types
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
/** /**
* Describes a PIO interrupt source, including the PIO instance triggering the * Describes a PIO interrupt source, including the PIO instance triggering the
* interrupt and the associated interrupt handler. * interrupt and the associated interrupt handler.
*/ */
typedef struct _InterruptSource typedef struct _InterruptSource
{ {
/* Pointer to the source pin instance. */ /* Pointer to the source pin instance. */
const Pin *pPin; const Pin *pPin;
/* Interrupt handler. */ /* Interrupt handler. */
void (*handler)( const Pin* ) ; void (*handler)( const Pin* ) ;
} InterruptSource ; } InterruptSource ;
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
* Local variables * Local variables
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
/* List of interrupt sources. */ /* List of interrupt sources. */
static InterruptSource _aIntSources[MAX_INTERRUPT_SOURCES] ; static InterruptSource _aIntSources[MAX_INTERRUPT_SOURCES] ;
/* Number of currently defined interrupt sources. */ /* Number of currently defined interrupt sources. */
static uint32_t _dwNumSources = 0; static uint32_t _dwNumSources = 0;
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
* Local Functions * Local Functions
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
/** /**
* \brief Stub, to handling all PIO Capture interrupts, if not defined. * \brief Stub, to handling all PIO Capture interrupts, if not defined.
*/ */
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
extern WEAK void PIO_CaptureHandler( void ) extern WEAK void PIO_CaptureHandler( void )
{ {
} }
/** /**
* \brief Handles all interrupts on the given PIO controller. * \brief Handles all interrupts on the given PIO controller.
* \param id PIO controller ID. * \param id PIO controller ID.
* \param pPio PIO controller base address. * \param pPio PIO controller base address.
*/ */
extern void PioInterruptHandler( uint32_t id, Pio *pPio ) extern void PioInterruptHandler( uint32_t id, Pio *pPio )
{ {
uint32_t status; uint32_t status;
uint32_t i; uint32_t i;
/* Read PIO controller status */ /* Read PIO controller status */
status = pPio->PIO_ISR; status = pPio->PIO_ISR;
status &= pPio->PIO_IMR; status &= pPio->PIO_IMR;
/* Check pending events */ /* Check pending events */
if ( status != 0 ) if ( status != 0 )
{ {
TRACE_DEBUG( "PIO interrupt on PIO controller #%" PRIu32 "\n\r", id ) ; TRACE_DEBUG( "PIO interrupt on PIO controller #%" PRIu32 "\n\r", id ) ;
/* Find triggering source */ /* Find triggering source */
i = 0; i = 0;
while ( status != 0 ) while ( status != 0 )
{ {
/* There cannot be an unconfigured source enabled. */ /* There cannot be an unconfigured source enabled. */
assert(i < _dwNumSources); assert(i < _dwNumSources);
/* Source is configured on the same controller */ /* Source is configured on the same controller */
if (_aIntSources[i].pPin->id == id) if (_aIntSources[i].pPin->id == id)
{ {
/* Source has PIOs whose statuses have changed */ /* Source has PIOs whose statuses have changed */
if ( (status & _aIntSources[i].pPin->mask) != 0 ) if ( (status & _aIntSources[i].pPin->mask) != 0 )
{ {
TRACE_DEBUG( "Interrupt source #%" PRIu32 " triggered\n\r", i ) ; TRACE_DEBUG( "Interrupt source #%" PRIu32 " triggered\n\r", i ) ;
_aIntSources[i].handler(_aIntSources[i].pPin); _aIntSources[i].handler(_aIntSources[i].pPin);
status &= ~(_aIntSources[i].pPin->mask); status &= ~(_aIntSources[i].pPin->mask);
} }
} }
i++; i++;
} }
} }
} }
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
* Global Functions * Global Functions
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
/** /**
* \brief Parallel IO Controller A interrupt handler * \brief Parallel IO Controller A interrupt handler
* \Redefined PIOA interrupt handler for NVIC interrupt table. * \Redefined PIOA interrupt handler for NVIC interrupt table.
*/ */
extern void PIOA_IrqHandler( void ) extern void PIOA_IrqHandler( void )
{ {
if ( PIOA->PIO_PCISR != 0 ) if ( PIOA->PIO_PCISR != 0 )
{ {
PIO_CaptureHandler() ; PIO_CaptureHandler() ;
} }
PioInterruptHandler( ID_PIOA, PIOA ) ; PioInterruptHandler( ID_PIOA, PIOA ) ;
} }
/** /**
* \brief Parallel IO Controller B interrupt handler * \brief Parallel IO Controller B interrupt handler
* \Redefined PIOB interrupt handler for NVIC interrupt table. * \Redefined PIOB interrupt handler for NVIC interrupt table.
*/ */
extern void PIOB_IrqHandler( void ) extern void PIOB_IrqHandler( void )
{ {
PioInterruptHandler( ID_PIOB, PIOB ) ; PioInterruptHandler( ID_PIOB, PIOB ) ;
} }
/** /**
* \brief Parallel IO Controller C interrupt handler * \brief Parallel IO Controller C interrupt handler
* \Redefined PIOC interrupt handler for NVIC interrupt table. * \Redefined PIOC interrupt handler for NVIC interrupt table.
*/ */
extern void PIOC_IrqHandler( void ) extern void PIOC_IrqHandler( void )
{ {
PioInterruptHandler( ID_PIOC, PIOC ) ; PioInterruptHandler( ID_PIOC, PIOC ) ;
} }
/** /**
* \brief Initializes the PIO interrupt management logic * \brief Initializes the PIO interrupt management logic
* *
* The desired priority of PIO interrupts must be provided. * The desired priority of PIO interrupts must be provided.
* Calling this function multiple times result in the reset of currently * Calling this function multiple times result in the reset of currently
* configured interrupts. * configured interrupts.
* *
* \param priority PIO controller interrupts priority. * \param priority PIO controller interrupts priority.
*/ */
extern void PIO_InitializeInterrupts( uint32_t dwPriority ) extern void PIO_InitializeInterrupts( uint32_t dwPriority )
{ {
TRACE_DEBUG( "PIO_Initialize()\n\r" ) ; TRACE_DEBUG( "PIO_Initialize()\n\r" ) ;
/* Reset sources */ /* Reset sources */
_dwNumSources = 0 ; _dwNumSources = 0 ;
/* Configure PIO interrupt sources */ /* Configure PIO interrupt sources */
TRACE_DEBUG( "PIO_Initialize: Configuring PIOA\n\r" ) ; TRACE_DEBUG( "PIO_Initialize: Configuring PIOA\n\r" ) ;
PMC_EnablePeripheral( ID_PIOA ) ; PMC_EnablePeripheral( ID_PIOA ) ;
PIOA->PIO_ISR ; PIOA->PIO_ISR ;
PIOA->PIO_IDR = 0xFFFFFFFF ; PIOA->PIO_IDR = 0xFFFFFFFF ;
NVIC_DisableIRQ( PIOA_IRQn ) ; NVIC_DisableIRQ( PIOA_IRQn ) ;
NVIC_ClearPendingIRQ( PIOA_IRQn ) ; NVIC_ClearPendingIRQ( PIOA_IRQn ) ;
NVIC_SetPriority( PIOA_IRQn, dwPriority ) ; NVIC_SetPriority( PIOA_IRQn, dwPriority ) ;
NVIC_EnableIRQ( PIOA_IRQn ) ; NVIC_EnableIRQ( PIOA_IRQn ) ;
TRACE_DEBUG( "PIO_Initialize: Configuring PIOB\n\r" ) ; TRACE_DEBUG( "PIO_Initialize: Configuring PIOB\n\r" ) ;
PMC_EnablePeripheral( ID_PIOB ) ; PMC_EnablePeripheral( ID_PIOB ) ;
PIOB->PIO_ISR ; PIOB->PIO_ISR ;
PIOB->PIO_IDR = 0xFFFFFFFF ; PIOB->PIO_IDR = 0xFFFFFFFF ;
NVIC_DisableIRQ( PIOB_IRQn ) ; NVIC_DisableIRQ( PIOB_IRQn ) ;
NVIC_ClearPendingIRQ( PIOB_IRQn ) ; NVIC_ClearPendingIRQ( PIOB_IRQn ) ;
NVIC_SetPriority( PIOB_IRQn, dwPriority ) ; NVIC_SetPriority( PIOB_IRQn, dwPriority ) ;
NVIC_EnableIRQ( PIOB_IRQn ) ; NVIC_EnableIRQ( PIOB_IRQn ) ;
TRACE_DEBUG( "PIO_Initialize: Configuring PIOC\n\r" ) ; TRACE_DEBUG( "PIO_Initialize: Configuring PIOC\n\r" ) ;
PMC_EnablePeripheral( ID_PIOC ) ; PMC_EnablePeripheral( ID_PIOC ) ;
PIOC->PIO_ISR ; PIOC->PIO_ISR ;
PIOC->PIO_IDR = 0xFFFFFFFF ; PIOC->PIO_IDR = 0xFFFFFFFF ;
NVIC_DisableIRQ( PIOC_IRQn ) ; NVIC_DisableIRQ( PIOC_IRQn ) ;
NVIC_ClearPendingIRQ( PIOC_IRQn ) ; NVIC_ClearPendingIRQ( PIOC_IRQn ) ;
NVIC_SetPriority( PIOC_IRQn, dwPriority ) ; NVIC_SetPriority( PIOC_IRQn, dwPriority ) ;
NVIC_EnableIRQ( PIOC_IRQn ) ; NVIC_EnableIRQ( PIOC_IRQn ) ;
} }
/** /**
* Configures a PIO or a group of PIO to generate an interrupt on status * Configures a PIO or a group of PIO to generate an interrupt on status
* change. The provided interrupt handler will be called with the triggering * change. The provided interrupt handler will be called with the triggering
* pin as its parameter (enabling different pin instances to share the same * pin as its parameter (enabling different pin instances to share the same
* handler). * handler).
* \param pPin Pointer to a Pin instance. * \param pPin Pointer to a Pin instance.
* \param handler Interrupt handler function pointer. * \param handler Interrupt handler function pointer.
*/ */
extern void PIO_ConfigureIt( const Pin *pPin, void (*handler)( const Pin* ) ) extern void PIO_ConfigureIt( const Pin *pPin, void (*handler)( const Pin* ) )
{ {
Pio* pio ; Pio* pio ;
InterruptSource* pSource ; InterruptSource* pSource ;
TRACE_DEBUG( "PIO_ConfigureIt()\n\r" ) ; TRACE_DEBUG( "PIO_ConfigureIt()\n\r" ) ;
assert( pPin ) ; assert( pPin ) ;
pio = pPin->pio ; pio = pPin->pio ;
assert( _dwNumSources < MAX_INTERRUPT_SOURCES ) ; assert( _dwNumSources < MAX_INTERRUPT_SOURCES ) ;
/* Define new source */ /* Define new source */
TRACE_DEBUG( "PIO_ConfigureIt: Defining new source #%" PRIu32 ".\n\r", _dwNumSources ) ; TRACE_DEBUG( "PIO_ConfigureIt: Defining new source #%" PRIu32 ".\n\r", _dwNumSources ) ;
pSource = &(_aIntSources[_dwNumSources]) ; pSource = &(_aIntSources[_dwNumSources]) ;
pSource->pPin = pPin ; pSource->pPin = pPin ;
pSource->handler = handler ; pSource->handler = handler ;
_dwNumSources++ ; _dwNumSources++ ;
/* PIO3 with additional interrupt support /* PIO3 with additional interrupt support
* Configure additional interrupt mode registers */ * Configure additional interrupt mode registers */
if ( pPin->attribute & PIO_IT_AIME ) if ( pPin->attribute & PIO_IT_AIME )
{ {
// enable additional interrupt mode // enable additional interrupt mode
pio->PIO_AIMER = pPin->mask ; pio->PIO_AIMER = pPin->mask ;
// if bit field of selected pin is 1, set as Rising Edge/High level detection event // if bit field of selected pin is 1, set as Rising Edge/High level detection event
if ( pPin->attribute & PIO_IT_RE_OR_HL ) if ( pPin->attribute & PIO_IT_RE_OR_HL )
{ {
pio->PIO_REHLSR = pPin->mask ; pio->PIO_REHLSR = pPin->mask ;
} }
else else
{ {
pio->PIO_FELLSR = pPin->mask; pio->PIO_FELLSR = pPin->mask;
} }
/* if bit field of selected pin is 1, set as edge detection source */ /* if bit field of selected pin is 1, set as edge detection source */
if (pPin->attribute & PIO_IT_EDGE) if (pPin->attribute & PIO_IT_EDGE)
pio->PIO_ESR = pPin->mask; pio->PIO_ESR = pPin->mask;
else else
pio->PIO_LSR = pPin->mask; pio->PIO_LSR = pPin->mask;
} }
else else
{ {
/* disable additional interrupt mode */ /* disable additional interrupt mode */
pio->PIO_AIMDR = pPin->mask; pio->PIO_AIMDR = pPin->mask;
} }
} }
/** /**
* Enables the given interrupt source if it has been configured. The status * Enables the given interrupt source if it has been configured. The status
* register of the corresponding PIO controller is cleared prior to enabling * register of the corresponding PIO controller is cleared prior to enabling
* the interrupt. * the interrupt.
* \param pPin Interrupt source to enable. * \param pPin Interrupt source to enable.
*/ */
extern void PIO_EnableIt( const Pin *pPin ) extern void PIO_EnableIt( const Pin *pPin )
{ {
TRACE_DEBUG( "PIO_EnableIt()\n\r" ) ; TRACE_DEBUG( "PIO_EnableIt()\n\r" ) ;
assert( pPin != NULL ) ; assert( pPin != NULL ) ;
#ifndef NOASSERT #ifndef NOASSERT
uint32_t i = 0; uint32_t i = 0;
uint32_t dwFound = 0; uint32_t dwFound = 0;
while ( (i < _dwNumSources) && !dwFound ) while ( (i < _dwNumSources) && !dwFound )
{ {
if ( _aIntSources[i].pPin == pPin ) if ( _aIntSources[i].pPin == pPin )
{ {
dwFound = 1 ; dwFound = 1 ;
} }
i++ ; i++ ;
} }
assert( dwFound != 0 ) ; assert( dwFound != 0 ) ;
#endif #endif
pPin->pio->PIO_ISR; pPin->pio->PIO_ISR;
pPin->pio->PIO_IER = pPin->mask ; pPin->pio->PIO_IER = pPin->mask ;
} }
/** /**
* Disables a given interrupt source, with no added side effects. * Disables a given interrupt source, with no added side effects.
* *
* \param pPin Interrupt source to disable. * \param pPin Interrupt source to disable.
*/ */
extern void PIO_DisableIt( const Pin *pPin ) extern void PIO_DisableIt( const Pin *pPin )
{ {
assert( pPin != NULL ) ; assert( pPin != NULL ) ;
TRACE_DEBUG( "PIO_DisableIt()\n\r" ) ; TRACE_DEBUG( "PIO_DisableIt()\n\r" ) ;
pPin->pio->PIO_IDR = pPin->mask; pPin->pio->PIO_IDR = pPin->mask;
} }

View File

@@ -1,168 +1,168 @@
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support * ATMEL Microcontroller Software Support
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* Copyright (c) 2009, Atmel Corporation * Copyright (c) 2009, Atmel Corporation
* *
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* *
* - Redistributions of source code must retain the above copyright notice, * - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below. * this list of conditions and the disclaimer below.
* *
* Atmel's name may not be used to endorse or promote products derived from * Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission. * this software without specific prior written permission.
* *
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
* Headers * Headers
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#include "chip.h" #include "chip.h"
#include "trace.h" #include "trace.h"
#include <assert.h> #include <assert.h>
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
* Local definitions * Local definitions
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#define MASK_STATUS0 0xFFFFFFFC #define MASK_STATUS0 0xFFFFFFFC
#define MASK_STATUS1 0xFFFFFFFF #define MASK_STATUS1 0xFFFFFFFF
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
* Exported functions * Exported functions
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
/** /**
* \brief Enables the clock of a peripheral. The peripheral ID is used * \brief Enables the clock of a peripheral. The peripheral ID is used
* to identify which peripheral is targetted. * to identify which peripheral is targetted.
* *
* \note The ID must NOT be shifted (i.e. 1 << ID_xxx). * \note The ID must NOT be shifted (i.e. 1 << ID_xxx).
* *
* \param id Peripheral ID (ID_xxx). * \param id Peripheral ID (ID_xxx).
*/ */
extern void PMC_EnablePeripheral( uint32_t dwId ) extern void PMC_EnablePeripheral( uint32_t dwId )
{ {
assert( dwId < 35 ) ; assert( dwId < 35 ) ;
if ( dwId < 32 ) if ( dwId < 32 )
{ {
if ( (PMC->PMC_PCSR0 & ((uint32_t)1 << dwId)) == ((uint32_t)1 << dwId) ) if ( (PMC->PMC_PCSR0 & ((uint32_t)1 << dwId)) == ((uint32_t)1 << dwId) )
{ {
TRACE_DEBUG( "PMC_EnablePeripheral: clock of peripheral" " %" PRIu32 " is already enabled\n\r", dwId ) ; TRACE_DEBUG( "PMC_EnablePeripheral: clock of peripheral" " %" PRIu32 " is already enabled\n\r", dwId ) ;
} }
else else
{ {
PMC->PMC_PCER0 = 1 << dwId ; PMC->PMC_PCER0 = 1 << dwId ;
} }
} }
else else
{ {
dwId -= 32; dwId -= 32;
if ((PMC->PMC_PCSR1 & ((uint32_t)1 << dwId)) == ((uint32_t)1 << dwId)) if ((PMC->PMC_PCSR1 & ((uint32_t)1 << dwId)) == ((uint32_t)1 << dwId))
{ {
TRACE_DEBUG( "PMC_EnablePeripheral: clock of peripheral" " %" PRIu32 " is already enabled\n\r", dwId + 32 ) ; TRACE_DEBUG( "PMC_EnablePeripheral: clock of peripheral" " %" PRIu32 " is already enabled\n\r", dwId + 32 ) ;
} }
else else
{ {
PMC->PMC_PCER1 = 1 << dwId ; PMC->PMC_PCER1 = 1 << dwId ;
} }
} }
} }
/** /**
* \brief Disables the clock of a peripheral. The peripheral ID is used * \brief Disables the clock of a peripheral. The peripheral ID is used
* to identify which peripheral is targetted. * to identify which peripheral is targetted.
* *
* \note The ID must NOT be shifted (i.e. 1 << ID_xxx). * \note The ID must NOT be shifted (i.e. 1 << ID_xxx).
* *
* \param id Peripheral ID (ID_xxx). * \param id Peripheral ID (ID_xxx).
*/ */
extern void PMC_DisablePeripheral( uint32_t dwId ) extern void PMC_DisablePeripheral( uint32_t dwId )
{ {
assert( dwId < 35 ) ; assert( dwId < 35 ) ;
if ( dwId < 32 ) if ( dwId < 32 )
{ {
if ( (PMC->PMC_PCSR0 & ((uint32_t)1 << dwId)) != ((uint32_t)1 << dwId) ) if ( (PMC->PMC_PCSR0 & ((uint32_t)1 << dwId)) != ((uint32_t)1 << dwId) )
{ {
TRACE_DEBUG("PMC_DisablePeripheral: clock of peripheral" " %" PRIu32 " is not enabled\n\r", dwId ) ; TRACE_DEBUG("PMC_DisablePeripheral: clock of peripheral" " %" PRIu32 " is not enabled\n\r", dwId ) ;
} }
else else
{ {
PMC->PMC_PCDR0 = 1 << dwId ; PMC->PMC_PCDR0 = 1 << dwId ;
} }
} }
else else
{ {
dwId -= 32 ; dwId -= 32 ;
if ( (PMC->PMC_PCSR1 & ((uint32_t)1 << dwId)) != ((uint32_t)1 << dwId) ) if ( (PMC->PMC_PCSR1 & ((uint32_t)1 << dwId)) != ((uint32_t)1 << dwId) )
{ {
TRACE_DEBUG( "PMC_DisablePeripheral: clock of peripheral" " %" PRIu32 " is not enabled\n\r", dwId + 32 ) ; TRACE_DEBUG( "PMC_DisablePeripheral: clock of peripheral" " %" PRIu32 " is not enabled\n\r", dwId + 32 ) ;
} }
else else
{ {
PMC->PMC_PCDR1 = 1 << dwId ; PMC->PMC_PCDR1 = 1 << dwId ;
} }
} }
} }
/** /**
* \brief Enable all the periph clock via PMC. * \brief Enable all the periph clock via PMC.
*/ */
extern void PMC_EnableAllPeripherals( void ) extern void PMC_EnableAllPeripherals( void )
{ {
PMC->PMC_PCER0 = MASK_STATUS0 ; PMC->PMC_PCER0 = MASK_STATUS0 ;
while ( (PMC->PMC_PCSR0 & MASK_STATUS0) != MASK_STATUS0 ) ; while ( (PMC->PMC_PCSR0 & MASK_STATUS0) != MASK_STATUS0 ) ;
PMC->PMC_PCER1 = MASK_STATUS1 ; PMC->PMC_PCER1 = MASK_STATUS1 ;
while ( (PMC->PMC_PCSR1 & MASK_STATUS1) != MASK_STATUS1 ) ; while ( (PMC->PMC_PCSR1 & MASK_STATUS1) != MASK_STATUS1 ) ;
TRACE_DEBUG( "Enable all periph clocks\n\r" ) ; TRACE_DEBUG( "Enable all periph clocks\n\r" ) ;
} }
/** /**
* \brief Disable all the periph clock via PMC. * \brief Disable all the periph clock via PMC.
*/ */
extern void PMC_DisableAllPeripherals( void ) extern void PMC_DisableAllPeripherals( void )
{ {
PMC->PMC_PCDR0 = MASK_STATUS0 ; PMC->PMC_PCDR0 = MASK_STATUS0 ;
while ( (PMC->PMC_PCSR0 & MASK_STATUS0) != 0 ) ; while ( (PMC->PMC_PCSR0 & MASK_STATUS0) != 0 ) ;
PMC->PMC_PCDR1 = MASK_STATUS1 ; PMC->PMC_PCDR1 = MASK_STATUS1 ;
while ( (PMC->PMC_PCSR1 & MASK_STATUS1) != 0 ) ; while ( (PMC->PMC_PCSR1 & MASK_STATUS1) != 0 ) ;
TRACE_DEBUG( "Disable all periph clocks\n\r" ) ; TRACE_DEBUG( "Disable all periph clocks\n\r" ) ;
} }
/** /**
* \brief Get Periph Status for the given peripheral ID. * \brief Get Periph Status for the given peripheral ID.
* *
* \param id Peripheral ID (ID_xxx). * \param id Peripheral ID (ID_xxx).
*/ */
extern uint32_t PMC_IsPeriphEnabled( uint32_t dwId ) extern uint32_t PMC_IsPeriphEnabled( uint32_t dwId )
{ {
assert( dwId < 35 ) ; assert( dwId < 35 ) ;
if ( dwId < 32 ) if ( dwId < 32 )
{ {
return ( PMC->PMC_PCSR0 & (1 << dwId) ) ; return ( PMC->PMC_PCSR0 & (1 << dwId) ) ;
} }
else { else {
return ( PMC->PMC_PCSR1 & (1 << (dwId - 32)) ) ; return ( PMC->PMC_PCSR1 & (1 << (dwId - 32)) ) ;
} }
} }

View File

@@ -1,352 +1,352 @@
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support * ATMEL Microcontroller Software Support
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* Copyright (c) 2009, Atmel Corporation * Copyright (c) 2009, Atmel Corporation
* *
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* *
* - Redistributions of source code must retain the above copyright notice, * - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below. * this list of conditions and the disclaimer below.
* *
* Atmel's name may not be used to endorse or promote products derived from * Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission. * this software without specific prior written permission.
* *
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
/** \addtogroup spi_module Working with SPI /** \addtogroup spi_module Working with SPI
* The SPI driver provides the interface to configure and use the SPI * The SPI driver provides the interface to configure and use the SPI
* peripheral. * peripheral.
* *
* The Serial Peripheral Interface (SPI) circuit is a synchronous serial * The Serial Peripheral Interface (SPI) circuit is a synchronous serial
* data link that provides communication with external devices in Master * data link that provides communication with external devices in Master
* or Slave Mode. * or Slave Mode.
* *
* To use the SPI, the user has to follow these few steps: * To use the SPI, the user has to follow these few steps:
* -# Enable the SPI pins required by the application (see pio.h). * -# Enable the SPI pins required by the application (see pio.h).
* -# Configure the SPI using the \ref SPI_Configure(). This enables the * -# Configure the SPI using the \ref SPI_Configure(). This enables the
* peripheral clock. The mode register is loaded with the given value. * peripheral clock. The mode register is loaded with the given value.
* -# Configure all the necessary chip selects with \ref SPI_ConfigureNPCS(). * -# Configure all the necessary chip selects with \ref SPI_ConfigureNPCS().
* -# Enable the SPI by calling \ref SPI_Enable(). * -# Enable the SPI by calling \ref SPI_Enable().
* -# Send/receive data using \ref SPI_Write() and \ref SPI_Read(). Note that \ref SPI_Read() * -# Send/receive data using \ref SPI_Write() and \ref SPI_Read(). Note that \ref SPI_Read()
* must be called after \ref SPI_Write() to retrieve the last value read. * must be called after \ref SPI_Write() to retrieve the last value read.
* -# Send/receive data using the PDC with the \ref SPI_WriteBuffer() and * -# Send/receive data using the PDC with the \ref SPI_WriteBuffer() and
* \ref SPI_ReadBuffer() functions. * \ref SPI_ReadBuffer() functions.
* -# Disable the SPI by calling \ref SPI_Disable(). * -# Disable the SPI by calling \ref SPI_Disable().
* *
* For more accurate information, please look at the SPI section of the * For more accurate information, please look at the SPI section of the
* Datasheet. * Datasheet.
* *
* Related files :\n * Related files :\n
* \ref spi.c\n * \ref spi.c\n
* \ref spi.h.\n * \ref spi.h.\n
*/ */
/*@{*/ /*@{*/
/*@}*/ /*@}*/
/** /**
* \file * \file
* *
* Implementation of Serial Peripheral Interface (SPI) controller. * Implementation of Serial Peripheral Interface (SPI) controller.
* *
*/ */
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
* Headers * Headers
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#include "chip.h" #include "chip.h"
#include "pmc.h" #include "pmc.h"
#include "spi.h" #include "spi.h"
#include <stdint.h> #include <stdint.h>
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
* Exported functions * Exported functions
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
/** /**
* \brief Enables a SPI peripheral. * \brief Enables a SPI peripheral.
* *
* \param spi Pointer to an Spi instance. * \param spi Pointer to an Spi instance.
*/ */
extern void SPI_Enable( Spi* spi ) extern void SPI_Enable( Spi* spi )
{ {
spi->SPI_CR = SPI_CR_SPIEN ; spi->SPI_CR = SPI_CR_SPIEN ;
} }
/** /**
* \brief Disables a SPI peripheral. * \brief Disables a SPI peripheral.
* *
* \param spi Pointer to an Spi instance. * \param spi Pointer to an Spi instance.
*/ */
extern void SPI_Disable( Spi* spi ) extern void SPI_Disable( Spi* spi )
{ {
spi->SPI_CR = SPI_CR_SPIDIS ; spi->SPI_CR = SPI_CR_SPIDIS ;
} }
/** /**
* \brief Enables one or more interrupt sources of a SPI peripheral. * \brief Enables one or more interrupt sources of a SPI peripheral.
* *
* \param spi Pointer to an Spi instance. * \param spi Pointer to an Spi instance.
* \param sources Bitwise OR of selected interrupt sources. * \param sources Bitwise OR of selected interrupt sources.
*/ */
extern void SPI_EnableIt( Spi* spi, uint32_t dwSources ) extern void SPI_EnableIt( Spi* spi, uint32_t dwSources )
{ {
spi->SPI_IER = dwSources ; spi->SPI_IER = dwSources ;
} }
/** /**
* \brief Disables one or more interrupt sources of a SPI peripheral. * \brief Disables one or more interrupt sources of a SPI peripheral.
* *
* \param spi Pointer to an Spi instance. * \param spi Pointer to an Spi instance.
* \param sources Bitwise OR of selected interrupt sources. * \param sources Bitwise OR of selected interrupt sources.
*/ */
extern void SPI_DisableIt( Spi* spi, uint32_t dwSources ) extern void SPI_DisableIt( Spi* spi, uint32_t dwSources )
{ {
spi->SPI_IDR = dwSources ; spi->SPI_IDR = dwSources ;
} }
/** /**
* \brief Configures a SPI peripheral as specified. The configuration can be computed * \brief Configures a SPI peripheral as specified. The configuration can be computed
* using several macros (see \ref spi_configuration_macros). * using several macros (see \ref spi_configuration_macros).
* *
* \param spi Pointer to an Spi instance. * \param spi Pointer to an Spi instance.
* \param id Peripheral ID of the SPI. * \param id Peripheral ID of the SPI.
* \param configuration Value of the SPI configuration register. * \param configuration Value of the SPI configuration register.
*/ */
extern void SPI_Configure( Spi* spi, uint32_t dwId, uint32_t dwConfiguration ) extern void SPI_Configure( Spi* spi, uint32_t dwId, uint32_t dwConfiguration )
{ {
PMC_EnablePeripheral( dwId ) ; PMC_EnablePeripheral( dwId ) ;
spi->SPI_CR = SPI_CR_SPIDIS ; spi->SPI_CR = SPI_CR_SPIDIS ;
/* Execute a software reset of the SPI twice */ /* Execute a software reset of the SPI twice */
spi->SPI_CR = SPI_CR_SWRST ; spi->SPI_CR = SPI_CR_SWRST ;
spi->SPI_CR = SPI_CR_SWRST ; spi->SPI_CR = SPI_CR_SWRST ;
spi->SPI_MR = dwConfiguration ; spi->SPI_MR = dwConfiguration ;
} }
/** /**
* \brief Configures a chip select of a SPI peripheral. The chip select configuration * \brief Configures a chip select of a SPI peripheral. The chip select configuration
* is computed using several macros (see \ref spi_configuration_macros). * is computed using several macros (see \ref spi_configuration_macros).
* *
* \param spi Pointer to an Spi instance. * \param spi Pointer to an Spi instance.
* \param npcs Chip select to configure (0, 1, 2 or 3). * \param npcs Chip select to configure (0, 1, 2 or 3).
* \param configuration Desired chip select configuration. * \param configuration Desired chip select configuration.
*/ */
void SPI_ConfigureNPCS( Spi* spi, uint32_t dwNpcs, uint32_t dwConfiguration ) void SPI_ConfigureNPCS( Spi* spi, uint32_t dwNpcs, uint32_t dwConfiguration )
{ {
spi->SPI_CSR[dwNpcs] = dwConfiguration ; spi->SPI_CSR[dwNpcs] = dwConfiguration ;
} }
/** /**
* \brief Get the current status register of the given SPI peripheral. * \brief Get the current status register of the given SPI peripheral.
* \note This resets the internal value of the status register, so further * \note This resets the internal value of the status register, so further
* read may yield different values. * read may yield different values.
* \param spi Pointer to a Spi instance. * \param spi Pointer to a Spi instance.
* \return SPI status register. * \return SPI status register.
*/ */
extern uint32_t SPI_GetStatus( Spi* spi ) extern uint32_t SPI_GetStatus( Spi* spi )
{ {
return spi->SPI_SR ; return spi->SPI_SR ;
} }
/** /**
* \brief Reads and returns the last word of data received by a SPI peripheral. This * \brief Reads and returns the last word of data received by a SPI peripheral. This
* method must be called after a successful SPI_Write call. * method must be called after a successful SPI_Write call.
* *
* \param spi Pointer to an Spi instance. * \param spi Pointer to an Spi instance.
* *
* \return readed data. * \return readed data.
*/ */
extern uint32_t SPI_Read( Spi* spi ) extern uint32_t SPI_Read( Spi* spi )
{ {
while ( (spi->SPI_SR & SPI_SR_RDRF) == 0 ) ; while ( (spi->SPI_SR & SPI_SR_RDRF) == 0 ) ;
return spi->SPI_RDR & 0xFFFF ; return spi->SPI_RDR & 0xFFFF ;
} }
/** /**
* \brief Sends data through a SPI peripheral. If the SPI is configured to use a fixed * \brief Sends data through a SPI peripheral. If the SPI is configured to use a fixed
* peripheral select, the npcs value is meaningless. Otherwise, it identifies * peripheral select, the npcs value is meaningless. Otherwise, it identifies
* the component which shall be addressed. * the component which shall be addressed.
* *
* \param spi Pointer to an Spi instance. * \param spi Pointer to an Spi instance.
* \param npcs Chip select of the component to address (0, 1, 2 or 3). * \param npcs Chip select of the component to address (0, 1, 2 or 3).
* \param data Word of data to send. * \param data Word of data to send.
*/ */
extern void SPI_Write( Spi* spi, uint32_t dwNpcs, uint16_t wData ) extern void SPI_Write( Spi* spi, uint32_t dwNpcs, uint16_t wData )
{ {
/* Send data */ /* Send data */
while ( (spi->SPI_SR & SPI_SR_TXEMPTY) == 0 ) ; while ( (spi->SPI_SR & SPI_SR_TXEMPTY) == 0 ) ;
spi->SPI_TDR = wData | SPI_PCS( dwNpcs ) ; spi->SPI_TDR = wData | SPI_PCS( dwNpcs ) ;
while ( (spi->SPI_SR & SPI_SR_TDRE) == 0 ) ; while ( (spi->SPI_SR & SPI_SR_TDRE) == 0 ) ;
} }
/** /**
* \brief Check if SPI transfer finish. * \brief Check if SPI transfer finish.
* *
* \param spi Pointer to an Spi instance. * \param spi Pointer to an Spi instance.
* *
* \return Returns 1 if there is no pending write operation on the SPI; otherwise * \return Returns 1 if there is no pending write operation on the SPI; otherwise
* returns 0. * returns 0.
*/ */
extern uint32_t SPI_IsFinished( Spi* spi ) extern uint32_t SPI_IsFinished( Spi* spi )
{ {
return ((spi->SPI_SR & SPI_SR_TXEMPTY) != 0) ; return ((spi->SPI_SR & SPI_SR_TXEMPTY) != 0) ;
} }
/** /**
* \brief Enable Spi PDC transmit * \brief Enable Spi PDC transmit
* \param spi Pointer to an Spi instance. * \param spi Pointer to an Spi instance.
*/ */
extern void SPI_PdcEnableTx( Spi* spi ) extern void SPI_PdcEnableTx( Spi* spi )
{ {
spi->SPI_PTCR = SPI_PTCR_TXTEN ; spi->SPI_PTCR = SPI_PTCR_TXTEN ;
} }
/** /**
* \brief Disable Spi PDC transmit * \brief Disable Spi PDC transmit
* \param spi Pointer to an Spi instance. * \param spi Pointer to an Spi instance.
*/ */
extern void SPI_PdcDisableTx( Spi* spi ) extern void SPI_PdcDisableTx( Spi* spi )
{ {
spi->SPI_PTCR = SPI_PTCR_TXTDIS ; spi->SPI_PTCR = SPI_PTCR_TXTDIS ;
} }
/** /**
* \brief Enable Spi PDC receive * \brief Enable Spi PDC receive
* \param spi Pointer to an Spi instance. * \param spi Pointer to an Spi instance.
*/ */
extern void SPI_PdcEnableRx( Spi* spi ) extern void SPI_PdcEnableRx( Spi* spi )
{ {
spi->SPI_PTCR = SPI_PTCR_RXTEN ; spi->SPI_PTCR = SPI_PTCR_RXTEN ;
} }
/** /**
* \brief Disable Spi PDC receive * \brief Disable Spi PDC receive
* \param spi Pointer to an Spi instance. * \param spi Pointer to an Spi instance.
*/ */
extern void SPI_PdcDisableRx( Spi* spi ) extern void SPI_PdcDisableRx( Spi* spi )
{ {
spi->SPI_PTCR = SPI_PTCR_RXTDIS ; spi->SPI_PTCR = SPI_PTCR_RXTDIS ;
} }
/** /**
* \brief Set PDC transmit and next transmit buffer address and size. * \brief Set PDC transmit and next transmit buffer address and size.
* *
* \param spi Pointer to an Spi instance. * \param spi Pointer to an Spi instance.
* \param txBuf PDC transmit buffer address. * \param txBuf PDC transmit buffer address.
* \param txCount Length in bytes of the transmit buffer. * \param txCount Length in bytes of the transmit buffer.
* \param txNextBuf PDC next transmit buffer address. * \param txNextBuf PDC next transmit buffer address.
* \param txNextCount Length in bytes of the next transmit buffer. * \param txNextCount Length in bytes of the next transmit buffer.
*/ */
extern void SPI_PdcSetTx( Spi* spi, void* pvTxBuf, uint32_t dwTxCount, void* pvTxNextBuf, uint32_t dwTxNextCount ) extern void SPI_PdcSetTx( Spi* spi, void* pvTxBuf, uint32_t dwTxCount, void* pvTxNextBuf, uint32_t dwTxNextCount )
{ {
spi->SPI_TPR = (uint32_t)pvTxBuf ; spi->SPI_TPR = (uint32_t)pvTxBuf ;
spi->SPI_TCR = dwTxCount ; spi->SPI_TCR = dwTxCount ;
spi->SPI_TNPR = (uint32_t)pvTxNextBuf ; spi->SPI_TNPR = (uint32_t)pvTxNextBuf ;
spi->SPI_TNCR = dwTxNextCount ; spi->SPI_TNCR = dwTxNextCount ;
} }
/** /**
* \brief Set PDC receive and next receive buffer address and size. * \brief Set PDC receive and next receive buffer address and size.
* *
* \param spi Pointer to an Spi instance. * \param spi Pointer to an Spi instance.
* \param rxBuf PDC receive buffer address. * \param rxBuf PDC receive buffer address.
* \param rxCount Length in bytes of the receive buffer. * \param rxCount Length in bytes of the receive buffer.
* \param rxNextBuf PDC next receive buffer address. * \param rxNextBuf PDC next receive buffer address.
* \param rxNextCount Length in bytes of the next receive buffer. * \param rxNextCount Length in bytes of the next receive buffer.
*/ */
extern void SPI_PdcSetRx( Spi* spi, void* pvRxBuf, uint32_t dwRxCount, void* pvRxNextBuf, uint32_t dwRxNextCount ) extern void SPI_PdcSetRx( Spi* spi, void* pvRxBuf, uint32_t dwRxCount, void* pvRxNextBuf, uint32_t dwRxNextCount )
{ {
spi->SPI_RPR = (uint32_t)pvRxBuf ; spi->SPI_RPR = (uint32_t)pvRxBuf ;
spi->SPI_RCR = dwRxCount ; spi->SPI_RCR = dwRxCount ;
spi->SPI_RNPR = (uint32_t)pvRxNextBuf ; spi->SPI_RNPR = (uint32_t)pvRxNextBuf ;
spi->SPI_RNCR = dwRxNextCount ; spi->SPI_RNCR = dwRxNextCount ;
} }
/** /**
* \brief Sends the contents of buffer through a SPI peripheral, using the PDC to * \brief Sends the contents of buffer through a SPI peripheral, using the PDC to
* take care of the transfer. * take care of the transfer.
* *
* \param spi Pointer to an Spi instance. * \param spi Pointer to an Spi instance.
* \param buffer Data buffer to send. * \param buffer Data buffer to send.
* \param length Length of the data buffer. * \param length Length of the data buffer.
*/ */
extern uint32_t SPI_WriteBuffer( Spi* spi, void* pvBuffer, uint32_t dwLength ) extern uint32_t SPI_WriteBuffer( Spi* spi, void* pvBuffer, uint32_t dwLength )
{ {
/* Check if first bank is free */ /* Check if first bank is free */
if ( spi->SPI_TCR == 0 ) if ( spi->SPI_TCR == 0 )
{ {
spi->SPI_TPR = (uint32_t)pvBuffer ; spi->SPI_TPR = (uint32_t)pvBuffer ;
spi->SPI_TCR = dwLength ; spi->SPI_TCR = dwLength ;
spi->SPI_PTCR = PERIPH_PTCR_TXTEN ; spi->SPI_PTCR = PERIPH_PTCR_TXTEN ;
return 1 ; return 1 ;
} }
/* Check if second bank is free */ /* Check if second bank is free */
else else
{ {
if ( spi->SPI_TNCR == 0 ) if ( spi->SPI_TNCR == 0 )
{ {
spi->SPI_TNPR = (uint32_t)pvBuffer ; spi->SPI_TNPR = (uint32_t)pvBuffer ;
spi->SPI_TNCR = dwLength ; spi->SPI_TNCR = dwLength ;
return 1 ; return 1 ;
} }
} }
/* No free banks */ /* No free banks */
return 0 ; return 0 ;
} }
/** /**
* \brief Reads data from a SPI peripheral until the provided buffer is filled. This * \brief Reads data from a SPI peripheral until the provided buffer is filled. This
* method does NOT need to be called after SPI_Write or SPI_WriteBuffer. * method does NOT need to be called after SPI_Write or SPI_WriteBuffer.
* *
* \param spi Pointer to an Spi instance. * \param spi Pointer to an Spi instance.
* \param buffer Data buffer to store incoming bytes. * \param buffer Data buffer to store incoming bytes.
* \param length Length in bytes of the data buffer. * \param length Length in bytes of the data buffer.
*/ */
extern uint32_t SPI_ReadBuffer( Spi* spi, void *pvBuffer, uint32_t dwLength ) extern uint32_t SPI_ReadBuffer( Spi* spi, void *pvBuffer, uint32_t dwLength )
{ {
/* Check if the first bank is free */ /* Check if the first bank is free */
if ( spi->SPI_RCR == 0 ) if ( spi->SPI_RCR == 0 )
{ {
spi->SPI_RPR = (uint32_t)pvBuffer ; spi->SPI_RPR = (uint32_t)pvBuffer ;
spi->SPI_RCR = dwLength ; spi->SPI_RCR = dwLength ;
spi->SPI_PTCR = PERIPH_PTCR_RXTEN ; spi->SPI_PTCR = PERIPH_PTCR_RXTEN ;
return 1 ; return 1 ;
} }
/* Check if second bank is free */ /* Check if second bank is free */
else else
{ {
if ( spi->SPI_RNCR == 0 ) if ( spi->SPI_RNCR == 0 )
{ {
spi->SPI_RNPR = (uint32_t)pvBuffer ; spi->SPI_RNPR = (uint32_t)pvBuffer ;
spi->SPI_RNCR = dwLength ; spi->SPI_RNCR = dwLength ;
return 1 ; return 1 ;
} }
} }
/* No free bank */ /* No free bank */
return 0 ; return 0 ;
} }

View File

@@ -1,175 +1,175 @@
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support * ATMEL Microcontroller Software Support
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* Copyright (c) 2009, Atmel Corporation * Copyright (c) 2009, Atmel Corporation
* *
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* *
* - Redistributions of source code must retain the above copyright notice, * - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below. * this list of conditions and the disclaimer below.
* *
* Atmel's name may not be used to endorse or promote products derived from * Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission. * this software without specific prior written permission.
* *
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
/** /**
* \file * \file
* *
* Implementation of Timer Counter (TC). * Implementation of Timer Counter (TC).
* *
*/ */
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
* Headers * Headers
*------------------------------------------------------------------------------*/ *------------------------------------------------------------------------------*/
#include "chip.h" #include "chip.h"
#include <assert.h> #include <assert.h>
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
* Global functions * Global functions
*------------------------------------------------------------------------------*/ *------------------------------------------------------------------------------*/
/** /**
* \brief Configures a Timer Counter Channel * \brief Configures a Timer Counter Channel
* *
* Configures a Timer Counter to operate in the given mode. Timer is stopped * Configures a Timer Counter to operate in the given mode. Timer is stopped
* after configuration and must be restarted with TC_Start(). All the * after configuration and must be restarted with TC_Start(). All the
* interrupts of the timer are also disabled. * interrupts of the timer are also disabled.
* *
* \param pTc Pointer to a Tc instance. * \param pTc Pointer to a Tc instance.
* \param channel Channel number. * \param channel Channel number.
* \param mode Operating mode (TC_CMR value). * \param mode Operating mode (TC_CMR value).
*/ */
extern void TC_Configure( Tc *pTc, uint32_t dwChannel, uint32_t dwMode ) extern void TC_Configure( Tc *pTc, uint32_t dwChannel, uint32_t dwMode )
{ {
TcChannel* pTcCh ; TcChannel* pTcCh ;
assert( dwChannel < (sizeof( pTc->TC_CHANNEL )/sizeof( pTc->TC_CHANNEL[0] )) ) ; assert( dwChannel < (sizeof( pTc->TC_CHANNEL )/sizeof( pTc->TC_CHANNEL[0] )) ) ;
pTcCh = pTc->TC_CHANNEL+dwChannel ; pTcCh = pTc->TC_CHANNEL+dwChannel ;
/* Disable TC clock */ /* Disable TC clock */
pTcCh->TC_CCR = TC_CCR_CLKDIS ; pTcCh->TC_CCR = TC_CCR_CLKDIS ;
/* Disable interrupts */ /* Disable interrupts */
pTcCh->TC_IDR = 0xFFFFFFFF ; pTcCh->TC_IDR = 0xFFFFFFFF ;
/* Clear status register */ /* Clear status register */
pTcCh->TC_SR ; pTcCh->TC_SR ;
/* Set mode */ /* Set mode */
pTcCh->TC_CMR = dwMode ; pTcCh->TC_CMR = dwMode ;
} }
/** /**
* \brief Reset and Start the TC Channel * \brief Reset and Start the TC Channel
* *
* Enables the timer clock and performs a software reset to start the counting. * Enables the timer clock and performs a software reset to start the counting.
* *
* \param pTc Pointer to a Tc instance. * \param pTc Pointer to a Tc instance.
* \param dwChannel Channel number. * \param dwChannel Channel number.
*/ */
extern void TC_Start( Tc *pTc, uint32_t dwChannel ) extern void TC_Start( Tc *pTc, uint32_t dwChannel )
{ {
TcChannel* pTcCh ; TcChannel* pTcCh ;
assert( dwChannel < (sizeof( pTc->TC_CHANNEL )/sizeof( pTc->TC_CHANNEL[0] )) ) ; assert( dwChannel < (sizeof( pTc->TC_CHANNEL )/sizeof( pTc->TC_CHANNEL[0] )) ) ;
pTcCh = pTc->TC_CHANNEL+dwChannel ; pTcCh = pTc->TC_CHANNEL+dwChannel ;
pTcCh->TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG ; pTcCh->TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG ;
} }
/** /**
* \brief Stop TC Channel * \brief Stop TC Channel
* *
* Disables the timer clock, stopping the counting. * Disables the timer clock, stopping the counting.
* *
* \param pTc Pointer to a Tc instance. * \param pTc Pointer to a Tc instance.
* \param dwChannel Channel number. * \param dwChannel Channel number.
*/ */
extern void TC_Stop(Tc *pTc, uint32_t dwChannel ) extern void TC_Stop(Tc *pTc, uint32_t dwChannel )
{ {
TcChannel* pTcCh ; TcChannel* pTcCh ;
assert( dwChannel < (sizeof( pTc->TC_CHANNEL )/sizeof( pTc->TC_CHANNEL[0] )) ) ; assert( dwChannel < (sizeof( pTc->TC_CHANNEL )/sizeof( pTc->TC_CHANNEL[0] )) ) ;
pTcCh = pTc->TC_CHANNEL+dwChannel ; pTcCh = pTc->TC_CHANNEL+dwChannel ;
pTcCh->TC_CCR = TC_CCR_CLKDIS ; pTcCh->TC_CCR = TC_CCR_CLKDIS ;
} }
/** /**
* \brief Find best MCK divisor * \brief Find best MCK divisor
* *
* Finds the best MCK divisor given the timer frequency and MCK. The result * Finds the best MCK divisor given the timer frequency and MCK. The result
* is guaranteed to satisfy the following equation: * is guaranteed to satisfy the following equation:
* \code * \code
* (MCK / (DIV * 65536)) <= freq <= (MCK / DIV) * (MCK / (DIV * 65536)) <= freq <= (MCK / DIV)
* \endcode * \endcode
* with DIV being the highest possible value. * with DIV being the highest possible value.
* *
* \param dwFreq Desired timer frequency. * \param dwFreq Desired timer frequency.
* \param dwMCk Master clock frequency. * \param dwMCk Master clock frequency.
* \param dwDiv Divisor value. * \param dwDiv Divisor value.
* \param dwTcClks TCCLKS field value for divisor. * \param dwTcClks TCCLKS field value for divisor.
* \param dwBoardMCK Board clock frequency. * \param dwBoardMCK Board clock frequency.
* *
* \return 1 if a proper divisor has been found, otherwise 0. * \return 1 if a proper divisor has been found, otherwise 0.
*/ */
extern uint32_t TC_FindMckDivisor( uint32_t dwFreq, uint32_t dwMCk, uint32_t *dwDiv, uint32_t *dwTcClks, uint32_t dwBoardMCK ) extern uint32_t TC_FindMckDivisor( uint32_t dwFreq, uint32_t dwMCk, uint32_t *dwDiv, uint32_t *dwTcClks, uint32_t dwBoardMCK )
{ {
const uint32_t adwDivisors[5] = { 2, 8, 32, 128, dwBoardMCK / 32768 } ; const uint32_t adwDivisors[5] = { 2, 8, 32, 128, dwBoardMCK / 32768 } ;
uint32_t dwIndex = 0 ; uint32_t dwIndex = 0 ;
/* Satisfy lower bound */ /* Satisfy lower bound */
while ( dwFreq < ((dwMCk / adwDivisors[dwIndex]) / 65536) ) while ( dwFreq < ((dwMCk / adwDivisors[dwIndex]) / 65536) )
{ {
dwIndex++ ; dwIndex++ ;
/* If no divisor can be found, return 0 */ /* If no divisor can be found, return 0 */
if ( dwIndex == (sizeof( adwDivisors )/sizeof( adwDivisors[0] )) ) if ( dwIndex == (sizeof( adwDivisors )/sizeof( adwDivisors[0] )) )
{ {
return 0 ; return 0 ;
} }
} }
/* Try to maximize DIV while satisfying upper bound */ /* Try to maximize DIV while satisfying upper bound */
while ( dwIndex < 4 ) while ( dwIndex < 4 )
{ {
if ( dwFreq > (dwMCk / adwDivisors[dwIndex + 1]) ) if ( dwFreq > (dwMCk / adwDivisors[dwIndex + 1]) )
{ {
break ; break ;
} }
dwIndex++ ; dwIndex++ ;
} }
/* Store results */ /* Store results */
if ( dwDiv ) if ( dwDiv )
{ {
*dwDiv = adwDivisors[dwIndex] ; *dwDiv = adwDivisors[dwIndex] ;
} }
if ( dwTcClks ) if ( dwTcClks )
{ {
*dwTcClks = dwIndex ; *dwTcClks = dwIndex ;
} }
return 1 ; return 1 ;
} }

View File

@@ -1,410 +1,410 @@
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support * ATMEL Microcontroller Software Support
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* Copyright (c) 2009, Atmel Corporation * Copyright (c) 2009, Atmel Corporation
* *
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* *
* - Redistributions of source code must retain the above copyright notice, * - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below. * this list of conditions and the disclaimer below.
* *
* Atmel's name may not be used to endorse or promote products derived from * Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission. * this software without specific prior written permission.
* *
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
/** \addtogroup usart_module Working with USART /** \addtogroup usart_module Working with USART
* The USART driver provides the interface to configure and use the USART peripheral.\n * The USART driver provides the interface to configure and use the USART peripheral.\n
* *
* The USART supports several kinds of comminication modes such as full-duplex asynchronous/ * The USART supports several kinds of comminication modes such as full-duplex asynchronous/
* synchronous serial commnunication,RS485 with driver control signal,ISO7816,SPI and Test modes. * synchronous serial commnunication,RS485 with driver control signal,ISO7816,SPI and Test modes.
* *
* To start a USART transfer with \ref AT91SAM3S_PDC "PDC" support, the user could follow these steps: * To start a USART transfer with \ref AT91SAM3S_PDC "PDC" support, the user could follow these steps:
* <ul> * <ul>
* <li> Configure USART with expected mode and baudrate(see \ref USART_Configure), which could be done by: * <li> Configure USART with expected mode and baudrate(see \ref USART_Configure), which could be done by:
* -# Resetting and disabling transmitter and receiver by setting US_CR(Control Register). </li> * -# Resetting and disabling transmitter and receiver by setting US_CR(Control Register). </li>
* -# Conifguring the USART in a specific mode by setting USART_MODE bits in US_MR(Mode Register) </li> * -# Conifguring the USART in a specific mode by setting USART_MODE bits in US_MR(Mode Register) </li>
* -# Setting baudrate which is different from mode to mode. * -# Setting baudrate which is different from mode to mode.
</li> </li>
* <li> Enable transmitter or receiver respectively by set US_CR_TXEN or US_CR_RXEN in US_CR.</li> * <li> Enable transmitter or receiver respectively by set US_CR_TXEN or US_CR_RXEN in US_CR.</li>
* <li> Read from or write to the peripheral with \ref USART_ReadBuffer or \ref USART_WriteBuffer. * <li> Read from or write to the peripheral with \ref USART_ReadBuffer or \ref USART_WriteBuffer.
These operations could be done by polling or interruption. </li> These operations could be done by polling or interruption. </li>
* <li> For polling, check the status bit US_CSR_ENDRX/US_CSR_RXBUFF (READ) or US_CSR_ENDTX/ * <li> For polling, check the status bit US_CSR_ENDRX/US_CSR_RXBUFF (READ) or US_CSR_ENDTX/
US_CSR_TXBUFE (WRITE). </li> US_CSR_TXBUFE (WRITE). </li>
* <li> For interruption,"enable" the status bit through US_IER and * <li> For interruption,"enable" the status bit through US_IER and
realize the hanler with USARTx_IrqHandler according to IRQ vector realize the hanler with USARTx_IrqHandler according to IRQ vector
table which is defined in board_cstartup_<toolchain>.c table which is defined in board_cstartup_<toolchain>.c
To enable the interruption of USART,it should be configured with priority and enabled first through To enable the interruption of USART,it should be configured with priority and enabled first through
NVIC .</li> NVIC .</li>
* </ul> * </ul>
* *
* For more accurate information, please look at the USART section of the * For more accurate information, please look at the USART section of the
* Datasheet. * Datasheet.
* *
* Related files :\n * Related files :\n
* \ref usart.c\n * \ref usart.c\n
* \ref usart.h\n * \ref usart.h\n
*/ */
/** /**
* \file * \file
* *
* Implementation of USART (Universal Synchronous Asynchronous Receiver Transmitter) * Implementation of USART (Universal Synchronous Asynchronous Receiver Transmitter)
* controller. * controller.
* *
*/ */
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
* Headers * Headers
*------------------------------------------------------------------------------*/ *------------------------------------------------------------------------------*/
#include "chip.h" #include "chip.h"
#include "trace.h" #include "trace.h"
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
* Local definitions * Local definitions
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
* Exported functions * Exported functions
*------------------------------------------------------------------------------*/ *------------------------------------------------------------------------------*/
/** /**
* \brief Configures an USART peripheral with the specified parameters. * \brief Configures an USART peripheral with the specified parameters.
* *
* *
* \param usart Pointer to the USART peripheral to configure. * \param usart Pointer to the USART peripheral to configure.
* \param mode Desired value for the USART mode register (see the datasheet). * \param mode Desired value for the USART mode register (see the datasheet).
* \param baudrate Baudrate at which the USART should operate (in Hz). * \param baudrate Baudrate at which the USART should operate (in Hz).
* \param masterClock Frequency of the system master clock (in Hz). * \param masterClock Frequency of the system master clock (in Hz).
*/ */
void USART_Configure(Usart *usart, void USART_Configure(Usart *usart,
uint32_t mode, uint32_t mode,
uint32_t baudrate, uint32_t baudrate,
uint32_t masterClock) uint32_t masterClock)
{ {
/* Reset and disable receiver & transmitter*/ /* Reset and disable receiver & transmitter*/
usart->US_CR = US_CR_RSTRX | US_CR_RSTTX usart->US_CR = US_CR_RSTRX | US_CR_RSTTX
| US_CR_RXDIS | US_CR_TXDIS; | US_CR_RXDIS | US_CR_TXDIS;
/* Configure mode*/ /* Configure mode*/
usart->US_MR = mode; usart->US_MR = mode;
/* Configure baudrate*/ /* Configure baudrate*/
/* Asynchronous, no oversampling*/ /* Asynchronous, no oversampling*/
if ( ((mode & US_MR_SYNC) == 0) && ((mode & US_MR_OVER) == 0) ) if ( ((mode & US_MR_SYNC) == 0) && ((mode & US_MR_OVER) == 0) )
{ {
usart->US_BRGR = (masterClock / baudrate) / 16; usart->US_BRGR = (masterClock / baudrate) / 16;
} }
if( ((mode & US_MR_USART_MODE_SPI_MASTER) == US_MR_USART_MODE_SPI_MASTER) if( ((mode & US_MR_USART_MODE_SPI_MASTER) == US_MR_USART_MODE_SPI_MASTER)
|| ((mode & US_MR_SYNC) == US_MR_SYNC)) || ((mode & US_MR_SYNC) == US_MR_SYNC))
{ {
if( (mode & US_MR_USCLKS_Msk) == US_MR_USCLKS_MCK) if( (mode & US_MR_USCLKS_Msk) == US_MR_USCLKS_MCK)
{ {
usart->US_BRGR = masterClock / baudrate; usart->US_BRGR = masterClock / baudrate;
} }
else else
{ {
if ( (mode & US_MR_USCLKS_DIV) == US_MR_USCLKS_DIV) if ( (mode & US_MR_USCLKS_DIV) == US_MR_USCLKS_DIV)
{ {
usart->US_BRGR = masterClock / baudrate / 8; usart->US_BRGR = masterClock / baudrate / 8;
} }
} }
} }
/* TODO other modes*/ /* TODO other modes*/
} }
/** /**
* \brief Enables or disables the transmitter of an USART peripheral. * \brief Enables or disables the transmitter of an USART peripheral.
* *
* *
* \param usart Pointer to an USART peripheral * \param usart Pointer to an USART peripheral
* \param enabled If true, the transmitter is enabled; otherwise it is * \param enabled If true, the transmitter is enabled; otherwise it is
* disabled. * disabled.
*/ */
void USART_SetTransmitterEnabled(Usart *usart, uint8_t enabled) void USART_SetTransmitterEnabled(Usart *usart, uint8_t enabled)
{ {
if (enabled) { if (enabled) {
usart->US_CR = US_CR_TXEN; usart->US_CR = US_CR_TXEN;
} }
else { else {
usart->US_CR = US_CR_TXDIS; usart->US_CR = US_CR_TXDIS;
} }
} }
/** /**
* \brief Enables or disables the receiver of an USART peripheral * \brief Enables or disables the receiver of an USART peripheral
* *
* *
* \param usart Pointer to an USART peripheral * \param usart Pointer to an USART peripheral
* \param enabled If true, the receiver is enabled; otherwise it is disabled. * \param enabled If true, the receiver is enabled; otherwise it is disabled.
*/ */
void USART_SetReceiverEnabled(Usart *usart, void USART_SetReceiverEnabled(Usart *usart,
uint8_t enabled) uint8_t enabled)
{ {
if (enabled) { if (enabled) {
usart->US_CR = US_CR_RXEN; usart->US_CR = US_CR_RXEN;
} }
else { else {
usart->US_CR = US_CR_RXDIS; usart->US_CR = US_CR_RXDIS;
} }
} }
/** /**
* \brief Sends one packet of data through the specified USART peripheral. This * \brief Sends one packet of data through the specified USART peripheral. This
* function operates synchronously, so it only returns when the data has been * function operates synchronously, so it only returns when the data has been
* actually sent. * actually sent.
* *
* *
* \param usart Pointer to an USART peripheral. * \param usart Pointer to an USART peripheral.
* \param data Data to send including 9nth bit and sync field if necessary (in * \param data Data to send including 9nth bit and sync field if necessary (in
* the same format as the US_THR register in the datasheet). * the same format as the US_THR register in the datasheet).
* \param timeOut Time out value (0 = no timeout). * \param timeOut Time out value (0 = no timeout).
*/ */
void USART_Write( void USART_Write(
Usart *usart, Usart *usart,
uint16_t data, uint16_t data,
volatile uint32_t timeOut) volatile uint32_t timeOut)
{ {
if (timeOut == 0) { if (timeOut == 0) {
while ((usart->US_CSR & US_CSR_TXEMPTY) == 0); while ((usart->US_CSR & US_CSR_TXEMPTY) == 0);
} }
else { else {
while ((usart->US_CSR & US_CSR_TXEMPTY) == 0) { while ((usart->US_CSR & US_CSR_TXEMPTY) == 0) {
if (timeOut == 0) { if (timeOut == 0) {
TRACE_ERROR("USART_Write: Timed out.\n\r"); TRACE_ERROR("USART_Write: Timed out.\n\r");
return; return;
} }
timeOut--; timeOut--;
} }
} }
usart->US_THR = data; usart->US_THR = data;
} }
/** /**
* \brief Sends the contents of a data buffer through the specified USART peripheral. * \brief Sends the contents of a data buffer through the specified USART peripheral.
* This function returns immediately (1 if the buffer has been queued, 0 * This function returns immediately (1 if the buffer has been queued, 0
* otherwise); poll the ENDTX and TXBUFE bits of the USART status register * otherwise); poll the ENDTX and TXBUFE bits of the USART status register
* to check for the transfer completion. * to check for the transfer completion.
* *
* \param usart Pointer to an USART peripheral. * \param usart Pointer to an USART peripheral.
* \param buffer Pointer to the data buffer to send. * \param buffer Pointer to the data buffer to send.
* \param size Size of the data buffer (in bytes). * \param size Size of the data buffer (in bytes).
*/ */
uint8_t USART_WriteBuffer( uint8_t USART_WriteBuffer(
Usart *usart, Usart *usart,
void *buffer, void *buffer,
uint32_t size) uint32_t size)
{ {
/* Check if the first PDC bank is free*/ /* Check if the first PDC bank is free*/
if ((usart->US_TCR == 0) && (usart->US_TNCR == 0)) { if ((usart->US_TCR == 0) && (usart->US_TNCR == 0)) {
usart->US_TPR = (uint32_t) buffer; usart->US_TPR = (uint32_t) buffer;
usart->US_TCR = size; usart->US_TCR = size;
usart->US_PTCR = US_PTCR_TXTEN; usart->US_PTCR = US_PTCR_TXTEN;
return 1; return 1;
} }
/* Check if the second PDC bank is free*/ /* Check if the second PDC bank is free*/
else if (usart->US_TNCR == 0) { else if (usart->US_TNCR == 0) {
usart->US_TNPR = (uint32_t) buffer; usart->US_TNPR = (uint32_t) buffer;
usart->US_TNCR = size; usart->US_TNCR = size;
return 1; return 1;
} }
else { else {
return 0; return 0;
} }
} }
/** /**
* \brief Reads and return a packet of data on the specified USART peripheral. This * \brief Reads and return a packet of data on the specified USART peripheral. This
* function operates asynchronously, so it waits until some data has been * function operates asynchronously, so it waits until some data has been
* received. * received.
* *
* \param usart Pointer to an USART peripheral. * \param usart Pointer to an USART peripheral.
* \param timeOut Time out value (0 -> no timeout). * \param timeOut Time out value (0 -> no timeout).
*/ */
uint16_t USART_Read( uint16_t USART_Read(
Usart *usart, Usart *usart,
volatile uint32_t timeOut) volatile uint32_t timeOut)
{ {
if (timeOut == 0) { if (timeOut == 0) {
while ((usart->US_CSR & US_CSR_RXRDY) == 0); while ((usart->US_CSR & US_CSR_RXRDY) == 0);
} }
else { else {
while ((usart->US_CSR & US_CSR_RXRDY) == 0) { while ((usart->US_CSR & US_CSR_RXRDY) == 0) {
if (timeOut == 0) { if (timeOut == 0) {
TRACE_ERROR( "USART_Read: Timed out.\n\r" ) ; TRACE_ERROR( "USART_Read: Timed out.\n\r" ) ;
return 0; return 0;
} }
timeOut--; timeOut--;
} }
} }
return usart->US_RHR; return usart->US_RHR;
} }
/** /**
* \brief Reads data from an USART peripheral, filling the provided buffer until it * \brief Reads data from an USART peripheral, filling the provided buffer until it
* becomes full. This function returns immediately with 1 if the buffer has * becomes full. This function returns immediately with 1 if the buffer has
* been queued for transmission; otherwise 0. * been queued for transmission; otherwise 0.
* *
* \param usart Pointer to an USART peripheral. * \param usart Pointer to an USART peripheral.
* \param buffer Pointer to the buffer where the received data will be stored. * \param buffer Pointer to the buffer where the received data will be stored.
* \param size Size of the data buffer (in bytes). * \param size Size of the data buffer (in bytes).
*/ */
uint8_t USART_ReadBuffer(Usart *usart, uint8_t USART_ReadBuffer(Usart *usart,
void *buffer, void *buffer,
uint32_t size) uint32_t size)
{ {
/* Check if the first PDC bank is free*/ /* Check if the first PDC bank is free*/
if ((usart->US_RCR == 0) && (usart->US_RNCR == 0)) { if ((usart->US_RCR == 0) && (usart->US_RNCR == 0)) {
usart->US_RPR = (uint32_t) buffer; usart->US_RPR = (uint32_t) buffer;
usart->US_RCR = size; usart->US_RCR = size;
usart->US_PTCR = US_PTCR_RXTEN; usart->US_PTCR = US_PTCR_RXTEN;
return 1; return 1;
} }
/* Check if the second PDC bank is free*/ /* Check if the second PDC bank is free*/
else if (usart->US_RNCR == 0) { else if (usart->US_RNCR == 0) {
usart->US_RNPR = (uint32_t) buffer; usart->US_RNPR = (uint32_t) buffer;
usart->US_RNCR = size; usart->US_RNCR = size;
return 1; return 1;
} }
else { else {
return 0; return 0;
} }
} }
/** /**
* \brief Returns 1 if some data has been received and can be read from an USART; * \brief Returns 1 if some data has been received and can be read from an USART;
* otherwise returns 0. * otherwise returns 0.
* *
* \param usart Pointer to an Usart instance. * \param usart Pointer to an Usart instance.
*/ */
uint8_t USART_IsDataAvailable(Usart *usart) uint8_t USART_IsDataAvailable(Usart *usart)
{ {
if ((usart->US_CSR & US_CSR_RXRDY) != 0) { if ((usart->US_CSR & US_CSR_RXRDY) != 0) {
return 1; return 1;
} }
else { else {
return 0; return 0;
} }
} }
/** /**
* \brief Sets the filter value for the IRDA demodulator. * \brief Sets the filter value for the IRDA demodulator.
* *
* \param pUsart Pointer to an Usart instance. * \param pUsart Pointer to an Usart instance.
* \param filter Filter value. * \param filter Filter value.
*/ */
void USART_SetIrdaFilter(Usart *pUsart, uint8_t filter) void USART_SetIrdaFilter(Usart *pUsart, uint8_t filter)
{ {
assert( pUsart != NULL ) ; assert( pUsart != NULL ) ;
pUsart->US_IF = filter; pUsart->US_IF = filter;
} }
/** /**
* \brief Sends one packet of data through the specified USART peripheral. This * \brief Sends one packet of data through the specified USART peripheral. This
* function operates synchronously, so it only returns when the data has been * function operates synchronously, so it only returns when the data has been
* actually sent. * actually sent.
* *
* \param usart Pointer to an USART peripheral. * \param usart Pointer to an USART peripheral.
* \param c Character to send * \param c Character to send
*/ */
void USART_PutChar( void USART_PutChar(
Usart *usart, Usart *usart,
uint8_t c) uint8_t c)
{ {
/* Wait for the transmitter to be ready*/ /* Wait for the transmitter to be ready*/
while ((usart->US_CSR & US_CSR_TXEMPTY) == 0); while ((usart->US_CSR & US_CSR_TXEMPTY) == 0);
/* Send character*/ /* Send character*/
usart->US_THR = c; usart->US_THR = c;
/* Wait for the transfer to complete*/ /* Wait for the transfer to complete*/
while ((usart->US_CSR & US_CSR_TXEMPTY) == 0); while ((usart->US_CSR & US_CSR_TXEMPTY) == 0);
} }
/** /**
* \brief Return 1 if a character can be read in USART * \brief Return 1 if a character can be read in USART
*/ */
uint32_t USART_IsRxReady(Usart *usart) uint32_t USART_IsRxReady(Usart *usart)
{ {
return (usart->US_CSR & US_CSR_RXRDY); return (usart->US_CSR & US_CSR_RXRDY);
} }
/** /**
* \brief Get present status * \brief Get present status
*/ */
uint32_t USART_GetStatus(Usart *usart) uint32_t USART_GetStatus(Usart *usart)
{ {
return usart->US_CSR; return usart->US_CSR;
} }
/** /**
* \brief Enable interrupt * \brief Enable interrupt
*/ */
void USART_EnableIt(Usart *usart,uint32_t mode) void USART_EnableIt(Usart *usart,uint32_t mode)
{ {
usart->US_IER = mode; usart->US_IER = mode;
} }
/** /**
* \brief Disable interrupt * \brief Disable interrupt
*/ */
void USART_DisableIt(Usart *usart,uint32_t mode) void USART_DisableIt(Usart *usart,uint32_t mode)
{ {
usart->US_IDR = mode; usart->US_IDR = mode;
} }
/** /**
* \brief Reads and returns a character from the USART. * \brief Reads and returns a character from the USART.
* *
* \note This function is synchronous (i.e. uses polling). * \note This function is synchronous (i.e. uses polling).
* \param usart Pointer to an USART peripheral. * \param usart Pointer to an USART peripheral.
* \return Character received. * \return Character received.
*/ */
uint8_t USART_GetChar(Usart *usart) uint8_t USART_GetChar(Usart *usart)
{ {
while ((usart->US_CSR & US_CSR_RXRDY) == 0); while ((usart->US_CSR & US_CSR_RXRDY) == 0);
return usart->US_RHR; return usart->US_RHR;
} }

View File

@@ -1,132 +1,132 @@
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support * ATMEL Microcontroller Software Support
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* Copyright (c) 2009, Atmel Corporation * Copyright (c) 2009, Atmel Corporation
* *
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* *
* - Redistributions of source code must retain the above copyright notice, * - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below. * this list of conditions and the disclaimer below.
* *
* Atmel's name may not be used to endorse or promote products derived from * Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission. * this software without specific prior written permission.
* *
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
/** /**
* \file * \file
* *
* Implementation of Watchdog Timer (WDT) controller. * Implementation of Watchdog Timer (WDT) controller.
* *
*/ */
/** \addtogroup wdt_module Working with WDT /** \addtogroup wdt_module Working with WDT
* The WDT driver provides the interface to configure and use the WDT * The WDT driver provides the interface to configure and use the WDT
* peripheral. * peripheral.
* *
* The WDT can be used to prevent system lock-up if the software becomes * The WDT can be used to prevent system lock-up if the software becomes
* trapped in a deadlock. It can generate a general reset or a processor * trapped in a deadlock. It can generate a general reset or a processor
* reset only. It is clocked by slow clock divided by 128. * reset only. It is clocked by slow clock divided by 128.
* *
* The WDT is running at reset with 16 seconds watchdog period (slow clock at 32.768 kHz) * The WDT is running at reset with 16 seconds watchdog period (slow clock at 32.768 kHz)
* and external reset generation enabled. The user must either disable it or * and external reset generation enabled. The user must either disable it or
* reprogram it to meet the application requires. * reprogram it to meet the application requires.
* *
* To use the WDT, the user could follow these few steps: * To use the WDT, the user could follow these few steps:
* <ul> * <ul>
* <li>Enable watchdog with given mode using \ref WDT_Enable(). * <li>Enable watchdog with given mode using \ref WDT_Enable().
* <li>Restart the watchdog using \ref WDT_Restart() within the watchdog period. * <li>Restart the watchdog using \ref WDT_Restart() within the watchdog period.
* </ul> * </ul>
* *
* For more accurate information, please look at the WDT section of the * For more accurate information, please look at the WDT section of the
* Datasheet. * Datasheet.
* *
* \note * \note
* The Watchdog Mode Register (WDT_MR) can be written only once.\n * The Watchdog Mode Register (WDT_MR) can be written only once.\n
* *
* Related files :\n * Related files :\n
* \ref wdt.c\n * \ref wdt.c\n
* \ref wdt.h.\n * \ref wdt.h.\n
*/ */
/*@{*/ /*@{*/
/*@}*/ /*@}*/
/*--------------------------------------------------------------------------- /*---------------------------------------------------------------------------
* Headers * Headers
*---------------------------------------------------------------------------*/ *---------------------------------------------------------------------------*/
#include "chip.h" #include "chip.h"
#include <stdint.h> #include <stdint.h>
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
* Exported functions * Exported functions
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
/** /**
* \brief Enable watchdog with given mode. * \brief Enable watchdog with given mode.
* *
* \note The Watchdog Mode Register (WDT_MR) can be written only once. * \note The Watchdog Mode Register (WDT_MR) can be written only once.
* Only a processor reset resets it. * Only a processor reset resets it.
* *
* \param dwMode WDT mode to be set * \param dwMode WDT mode to be set
*/ */
extern void WDT_Enable( Wdt* pWDT, uint32_t dwMode ) extern void WDT_Enable( Wdt* pWDT, uint32_t dwMode )
{ {
pWDT->WDT_MR = dwMode ; pWDT->WDT_MR = dwMode ;
} }
/** /**
* \brief Disable watchdog. * \brief Disable watchdog.
* *
* \note The Watchdog Mode Register (WDT_MR) can be written only once. * \note The Watchdog Mode Register (WDT_MR) can be written only once.
* Only a processor reset resets it. * Only a processor reset resets it.
*/ */
extern void WDT_Disable( Wdt* pWDT ) extern void WDT_Disable( Wdt* pWDT )
{ {
pWDT->WDT_MR = WDT_MR_WDDIS; pWDT->WDT_MR = WDT_MR_WDDIS;
} }
/** /**
* \brief Watchdog restart. * \brief Watchdog restart.
*/ */
extern void WDT_Restart( Wdt* pWDT ) extern void WDT_Restart( Wdt* pWDT )
{ {
pWDT->WDT_CR = 0xA5000001; pWDT->WDT_CR = 0xA5000001;
} }
/** /**
* \brief Watchdog get status. * \brief Watchdog get status.
*/ */
extern uint32_t WDT_GetStatus( Wdt* pWDT ) extern uint32_t WDT_GetStatus( Wdt* pWDT )
{ {
return (pWDT->WDT_SR & 0x3) ; return (pWDT->WDT_SR & 0x3) ;
} }
/** /**
* \brief Watchdog get period. * \brief Watchdog get period.
* *
* \param dwMs desired watchdog period in millisecond. * \param dwMs desired watchdog period in millisecond.
*/ */
extern uint32_t WDT_GetPeriod( uint32_t dwMs ) extern uint32_t WDT_GetPeriod( uint32_t dwMs )
{ {
if ( (dwMs < 4) || (dwMs > 16000) ) if ( (dwMs < 4) || (dwMs > 16000) )
{ {
return 0 ; return 0 ;
} }
return ((dwMs << 8) / 1000) ; return ((dwMs << 8) / 1000) ;
} }

View File

@@ -47,6 +47,8 @@
#include "USBD.h" #include "USBD.h"
#include "USBD_HAL.h" #include "USBD_HAL.h"
extern void USBDFU_Runtime_RequestHandler(const USBGenericRequest *request);
/*--------------------------------------------------------------------------- /*---------------------------------------------------------------------------
* Definitions * Definitions
*---------------------------------------------------------------------------*/ *---------------------------------------------------------------------------*/
@@ -144,7 +146,11 @@ void USBD_RequestHandler(uint8_t bEndpoint,
bEndpoint); bEndpoint);
} }
else { else {
#if defined(BOARD_USB_DFU) && !defined(APPLICATION_dfu)
USBDFU_Runtime_RequestHandler(pRequest);
#else
USBDCallbacks_RequestReceived(pRequest); USBDCallbacks_RequestReceived(pRequest);
#endif
} }
} }

View File

@@ -2,6 +2,7 @@
* ATMEL Microcontroller Software Support * ATMEL Microcontroller Software Support
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* Copyright (c) 2008, Atmel Corporation * Copyright (c) 2008, Atmel Corporation
* Copyright (c) 2018, Kevin Redon <kredon@sysmocom.de>
* *
* All rights reserved. * All rights reserved.
* *
@@ -250,7 +251,7 @@ static void GetDescriptor(
switch (type) { switch (type) {
case USBGenericDescriptor_DEVICE: case USBGenericDescriptor_DEVICE:
TRACE_INFO_WP("Dev "); TRACE_DEBUG_WP("Dev ");
/* Adjust length and send descriptor */ /* Adjust length and send descriptor */
@@ -262,7 +263,7 @@ static void GetDescriptor(
break; break;
case USBGenericDescriptor_CONFIGURATION: case USBGenericDescriptor_CONFIGURATION:
TRACE_INFO_WP("Cfg "); TRACE_DEBUG_WP("Cfg ");
/* Adjust length and send descriptor */ /* Adjust length and send descriptor */
@@ -279,7 +280,7 @@ static void GetDescriptor(
break; break;
case USBGenericDescriptor_DEVICEQUALIFIER: case USBGenericDescriptor_DEVICEQUALIFIER:
TRACE_INFO_WP("Qua "); TRACE_DEBUG_WP("Qua ");
/* Check if descriptor exists */ /* Check if descriptor exists */
@@ -300,7 +301,7 @@ static void GetDescriptor(
break; break;
case USBGenericDescriptor_OTHERSPEEDCONFIGURATION: case USBGenericDescriptor_OTHERSPEEDCONFIGURATION:
TRACE_INFO_WP("OSC "); TRACE_DEBUG_WP("OSC ");
/* Check if descriptor exists */ /* Check if descriptor exists */
@@ -326,13 +327,18 @@ static void GetDescriptor(
break; break;
case USBGenericDescriptor_STRING: case USBGenericDescriptor_STRING:
TRACE_INFO_WP("Str%d ", indexRDesc); TRACE_DEBUG_WP("Str%d ", indexRDesc);
/* Check if descriptor exists */ /* Check if descriptor exists */
if (indexRDesc >= numStrings) { if (indexRDesc >= numStrings) {
/* Sometimes descriptor string 0xee is requested.
USBD_Stall(0); * This is a mechanism used by Microsoft Windows to further identify the USB device.
* Instead of stalling, as is the original code, leading to an USB reset, we send an empty packet.
* I am not sure if sending an empty string would be better, but an empty packet seems sufficient.
*/
//USBD_Stall(0);
USBD_Write(0, NULL, 0, 0, 0);
} }
else { else {
@@ -498,13 +504,13 @@ void USBDDriver_RequestHandler(
uint32_t length; uint32_t length;
uint32_t address; uint32_t address;
TRACE_INFO_WP("Std "); TRACE_DEBUG_WP("Std ");
/* Check request code */ /* Check request code */
switch (USBGenericRequest_GetRequest(pRequest)) { switch (USBGenericRequest_GetRequest(pRequest)) {
case USBGenericRequest_GETDESCRIPTOR: case USBGenericRequest_GETDESCRIPTOR:
TRACE_INFO_WP("gDesc "); TRACE_DEBUG_WP("gDesc ");
/* Send the requested descriptor */ /* Send the requested descriptor */
type = USBGetDescriptorRequest_GetDescriptorType(pRequest); type = USBGetDescriptorRequest_GetDescriptorType(pRequest);
@@ -514,7 +520,7 @@ void USBDDriver_RequestHandler(
break; break;
case USBGenericRequest_SETADDRESS: case USBGenericRequest_SETADDRESS:
TRACE_INFO_WP("sAddr "); TRACE_DEBUG_WP("sAddr ");
/* Sends a zero-length packet and then set the device address */ /* Sends a zero-length packet and then set the device address */
address = USBSetAddressRequest_GetAddress(pRequest); address = USBSetAddressRequest_GetAddress(pRequest);
@@ -522,7 +528,7 @@ void USBDDriver_RequestHandler(
break; break;
case USBGenericRequest_SETCONFIGURATION: case USBGenericRequest_SETCONFIGURATION:
TRACE_INFO_WP("sCfg "); TRACE_DEBUG_WP("sCfg ");
/* Set the requested configuration */ /* Set the requested configuration */
cfgnum = USBSetConfigurationRequest_GetConfiguration(pRequest); cfgnum = USBSetConfigurationRequest_GetConfiguration(pRequest);
@@ -530,27 +536,27 @@ void USBDDriver_RequestHandler(
break; break;
case USBGenericRequest_GETCONFIGURATION: case USBGenericRequest_GETCONFIGURATION:
TRACE_INFO_WP("gCfg "); TRACE_DEBUG_WP("gCfg ");
/* Send the current configuration number */ /* Send the current configuration number */
GetConfiguration(pDriver); GetConfiguration(pDriver);
break; break;
case USBGenericRequest_GETSTATUS: case USBGenericRequest_GETSTATUS:
TRACE_INFO_WP("gSta "); TRACE_DEBUG_WP("gSta ");
/* Check who is the recipient */ /* Check who is the recipient */
switch (USBGenericRequest_GetRecipient(pRequest)) { switch (USBGenericRequest_GetRecipient(pRequest)) {
case USBGenericRequest_DEVICE: case USBGenericRequest_DEVICE:
TRACE_INFO_WP("Dev "); TRACE_DEBUG_WP("Dev ");
/* Send the device status */ /* Send the device status */
GetDeviceStatus(pDriver); GetDeviceStatus(pDriver);
break; break;
case USBGenericRequest_ENDPOINT: case USBGenericRequest_ENDPOINT:
TRACE_INFO_WP("Ept "); TRACE_DEBUG_WP("Ept ");
/* Send the endpoint status */ /* Send the endpoint status */
eptnum = USBGenericRequest_GetEndpointNumber(pRequest); eptnum = USBGenericRequest_GetEndpointNumber(pRequest);
@@ -566,13 +572,13 @@ void USBDDriver_RequestHandler(
break; break;
case USBGenericRequest_CLEARFEATURE: case USBGenericRequest_CLEARFEATURE:
TRACE_INFO_WP("cFeat "); TRACE_DEBUG_WP("cFeat ");
/* Check which is the requested feature */ /* Check which is the requested feature */
switch (USBFeatureRequest_GetFeatureSelector(pRequest)) { switch (USBFeatureRequest_GetFeatureSelector(pRequest)) {
case USBFeatureRequest_ENDPOINTHALT: case USBFeatureRequest_ENDPOINTHALT:
TRACE_INFO_WP("Hlt "); TRACE_DEBUG_WP("Hlt ");
/* Unhalt endpoint and send a zero-length packet */ /* Unhalt endpoint and send a zero-length packet */
USBD_Unhalt(USBGenericRequest_GetEndpointNumber(pRequest)); USBD_Unhalt(USBGenericRequest_GetEndpointNumber(pRequest));
@@ -580,7 +586,7 @@ void USBDDriver_RequestHandler(
break; break;
case USBFeatureRequest_DEVICEREMOTEWAKEUP: case USBFeatureRequest_DEVICEREMOTEWAKEUP:
TRACE_INFO_WP("RmWU "); TRACE_DEBUG_WP("RmWU ");
/* Disable remote wake-up and send a zero-length packet */ /* Disable remote wake-up and send a zero-length packet */
pDriver->isRemoteWakeUpEnabled = 0; pDriver->isRemoteWakeUpEnabled = 0;
@@ -596,13 +602,13 @@ void USBDDriver_RequestHandler(
break; break;
case USBGenericRequest_SETFEATURE: case USBGenericRequest_SETFEATURE:
TRACE_INFO_WP("sFeat "); TRACE_DEBUG_WP("sFeat ");
/* Check which is the selected feature */ /* Check which is the selected feature */
switch (USBFeatureRequest_GetFeatureSelector(pRequest)) { switch (USBFeatureRequest_GetFeatureSelector(pRequest)) {
case USBFeatureRequest_DEVICEREMOTEWAKEUP: case USBFeatureRequest_DEVICEREMOTEWAKEUP:
TRACE_INFO_WP("RmWU "); TRACE_DEBUG_WP("RmWU ");
/* Enable remote wake-up and send a ZLP */ /* Enable remote wake-up and send a ZLP */
pDriver->isRemoteWakeUpEnabled = 1; pDriver->isRemoteWakeUpEnabled = 1;
@@ -610,25 +616,25 @@ void USBDDriver_RequestHandler(
break; break;
case USBFeatureRequest_ENDPOINTHALT: case USBFeatureRequest_ENDPOINTHALT:
TRACE_INFO_WP("Halt "); TRACE_DEBUG_WP("Halt ");
/* Halt endpoint */ /* Halt endpoint */
USBD_Halt(USBGenericRequest_GetEndpointNumber(pRequest)); USBD_Halt(USBGenericRequest_GetEndpointNumber(pRequest));
USBD_Write(0, 0, 0, 0, 0); USBD_Write(0, 0, 0, 0, 0);
break; break;
case USBFeatureRequest_OTG_B_HNP_ENABLE: case USBFeatureRequest_OTG_B_HNP_ENABLE:
TRACE_INFO_WP("OTG_B_HNP_ENABLE "); TRACE_DEBUG_WP("OTG_B_HNP_ENABLE ");
pDriver->otg_features_supported |= pDriver->otg_features_supported |=
1<<USBFeatureRequest_OTG_B_HNP_ENABLE; 1<<USBFeatureRequest_OTG_B_HNP_ENABLE;
USBD_Write(0, 0, 0, 0, 0); USBD_Write(0, 0, 0, 0, 0);
break; break;
case USBFeatureRequest_OTG_A_HNP_SUPPORT: case USBFeatureRequest_OTG_A_HNP_SUPPORT:
TRACE_INFO_WP("OTG_A_HNP_SUPPORT "); TRACE_DEBUG_WP("OTG_A_HNP_SUPPORT ");
pDriver->otg_features_supported |= pDriver->otg_features_supported |=
1<<USBFeatureRequest_OTG_A_HNP_SUPPORT; 1<<USBFeatureRequest_OTG_A_HNP_SUPPORT;
USBD_Write(0, 0, 0, 0, 0); USBD_Write(0, 0, 0, 0, 0);
break; break;
case USBFeatureRequest_OTG_A_ALT_HNP_SUPPORT: case USBFeatureRequest_OTG_A_ALT_HNP_SUPPORT:
TRACE_INFO_WP("OTG_A_ALT_HNP_SUPPORT "); TRACE_DEBUG_WP("OTG_A_ALT_HNP_SUPPORT ");
pDriver->otg_features_supported |= pDriver->otg_features_supported |=
1<<USBFeatureRequest_OTG_A_ALT_HNP_SUPPORT; 1<<USBFeatureRequest_OTG_A_ALT_HNP_SUPPORT;
USBD_Write(0, 0, 0, 0, 0); USBD_Write(0, 0, 0, 0, 0);
@@ -643,7 +649,7 @@ void USBDDriver_RequestHandler(
break; break;
case USBGenericRequest_SETINTERFACE: case USBGenericRequest_SETINTERFACE:
TRACE_INFO_WP("sInterface "); TRACE_DEBUG_WP("sInterface ");
infnum = USBInterfaceRequest_GetInterface(pRequest); infnum = USBInterfaceRequest_GetInterface(pRequest);
setting = USBInterfaceRequest_GetAlternateSetting(pRequest); setting = USBInterfaceRequest_GetAlternateSetting(pRequest);
@@ -651,7 +657,7 @@ void USBDDriver_RequestHandler(
break; break;
case USBGenericRequest_GETINTERFACE: case USBGenericRequest_GETINTERFACE:
TRACE_INFO_WP("gInterface "); TRACE_DEBUG_WP("gInterface ");
infnum = USBInterfaceRequest_GetInterface(pRequest); infnum = USBInterfaceRequest_GetInterface(pRequest);
GetInterface(pDriver, infnum); GetInterface(pDriver, infnum);

View File

@@ -78,8 +78,8 @@ extern const USBDDriverDescriptors dfu_descriptors;
/* no DFU bootloader is being used */ /* no DFU bootloader is being used */
#define DFURT_NUM_IF 0 #define DFURT_NUM_IF 0
#define DFURT_IF_DESCRIPTOR_STRUCT(a, b) #define DFURT_IF_DESCRIPTOR_STRUCT
#define DFURT_IF_DESCRIPTOR #define DFURT_IF_DESCRIPTOR(a, b)
#endif /* BOARD_USB_DFU */ #endif /* BOARD_USB_DFU */

View File

@@ -28,7 +28,7 @@ static const USBDeviceDescriptor fsDevice = {
.bDeviceClass = 0, .bDeviceClass = 0,
.bDeviceSubClass = 0, .bDeviceSubClass = 0,
.bDeviceProtocol = 0, .bDeviceProtocol = 0,
.bMaxPacketSize0 = BOARD_USB_ENDPOINTS_MAXPACKETSIZE(0), .bMaxPacketSize0 = USBEndpointDescriptor_MAXCTRLSIZE_FS,
.idVendor = BOARD_USB_VENDOR_ID, .idVendor = BOARD_USB_VENDOR_ID,
.idProduct = BOARD_DFU_USB_PRODUCT_ID, .idProduct = BOARD_DFU_USB_PRODUCT_ID,
.bcdDevice = BOARD_USB_RELEASE, .bcdDevice = BOARD_USB_RELEASE,

View File

@@ -217,7 +217,7 @@ void USBDFU_DFU_RequestHandler(const USBGenericRequest *request)
uint8_t req = USBGenericRequest_GetRequest(request); uint8_t req = USBGenericRequest_GetRequest(request);
uint16_t len = USBGenericRequest_GetLength(request); uint16_t len = USBGenericRequest_GetLength(request);
uint16_t val = USBGenericRequest_GetValue(request); uint16_t val = USBGenericRequest_GetValue(request);
int rc, ret; int rc, ret = DFU_RET_NOTHING;
TRACE_DEBUG("type=0x%x, recipient=0x%x val=0x%x len=%u\n\r", TRACE_DEBUG("type=0x%x, recipient=0x%x val=0x%x len=%u\n\r",
USBGenericRequest_GetType(request), USBGenericRequest_GetType(request),

View File

@@ -107,7 +107,7 @@ void USBDFU_Runtime_RequestHandler(const USBGenericRequest *request)
uint8_t req = USBGenericRequest_GetRequest(request); uint8_t req = USBGenericRequest_GetRequest(request);
uint16_t len = USBGenericRequest_GetLength(request); uint16_t len = USBGenericRequest_GetLength(request);
uint16_t val = USBGenericRequest_GetValue(request); uint16_t val = USBGenericRequest_GetValue(request);
int rc, ret; int rc, ret = DFU_RET_NOTHING;
TRACE_DEBUG("type=0x%x, recipient=0x%x val=0x%x len=%u\n\r", TRACE_DEBUG("type=0x%x, recipient=0x%x val=0x%x len=%u\n\r",
USBGenericRequest_GetType(request), USBGenericRequest_GetType(request),
@@ -141,7 +141,7 @@ void USBDFU_Runtime_RequestHandler(const USBGenericRequest *request)
if (USBGenericRequest_GetType(request) != USBGenericRequest_CLASS || if (USBGenericRequest_GetType(request) != USBGenericRequest_CLASS ||
USBGenericRequest_GetRecipient(request) != USBGenericRequest_INTERFACE) { USBGenericRequest_GetRecipient(request) != USBGenericRequest_INTERFACE) {
TRACE_DEBUG("std_ho_usbd "); TRACE_DEBUG("std_ho_usbd ");
USBDDriver_RequestHandler(usbdDriver, request); USBDCallbacks_RequestReceived(request);
return; return;
} }
@@ -216,9 +216,3 @@ void DFURT_SwitchToDFU(void)
* ResetVector of the bootloader */ * ResetVector of the bootloader */
NVIC_SystemReset(); NVIC_SystemReset();
} }
void USBDCallbacks_RequestReceived(const USBGenericRequest *request)
{
/* FIXME: integration with CCID control point reqeusts */
USBDFU_Runtime_RequestHandler(request);
}

View File

@@ -1,3 +1,22 @@
/* SIMtrace 2 common board pin definitions
*
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef _BOARD_ #ifndef _BOARD_
#define _BOARD_ #define _BOARD_
@@ -37,10 +56,8 @@
/** Core definition */ /** Core definition */
#define cortexm3 #define cortexm3
#define BOARD_MCK 48000000 #define PIO_LED_RED PIO_PA17
#define PIO_LED_GREEN PIO_PA18
#define PIO_LED_RED PIO_PA17
#define PIO_LED_GREEN PIO_PA17
#define PIN_LED_RED {PIO_LED_RED, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} #define PIN_LED_RED {PIO_LED_RED, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
#define PIN_LED_GREEN {PIO_LED_GREEN, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} #define PIN_LED_GREEN {PIO_LED_GREEN, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
@@ -63,12 +80,16 @@
#define PINS_UART { PIO_PA9A_URXD0|PIO_PA10A_UTXD0, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT} #define PINS_UART { PIO_PA9A_URXD0|PIO_PA10A_UTXD0, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
/** UART0 */ /** UART0 */
/** Console baudrate always using 115200. */ /** Console baud rate in bps */
#define CONSOLE_BAUDRATE 115200 #define CONSOLE_BAUDRATE 921600
/** Usart Hw interface used by the console (UART0). */ /** UART peripheral used by the console (UART0). */
#define CONSOLE_USART UART0 #define CONSOLE_UART UART0
/** Usart Hw ID used by the console (UART0). */ /** UART peripheral ID used by the console (UART0). */
#define CONSOLE_ID ID_UART0 #define CONSOLE_ID ID_UART0
/** UART ISR used by the console (UART0). */
#define CONSOLE_ISR UART0_IrqHandler
/** UART IRQ used by the console (UART0). */
#define CONSOLE_IRQ UART0_IRQn
/** Pins description corresponding to Rxd,Txd, (UART pins) */ /** Pins description corresponding to Rxd,Txd, (UART pins) */
#define CONSOLE_PINS {PINS_UART} #define CONSOLE_PINS {PINS_UART}
@@ -77,39 +98,25 @@
#define BOARD_ISO7816_BASE_USART USART0 #define BOARD_ISO7816_BASE_USART USART0
#define BOARD_ISO7816_ID_USART ID_USART0 #define BOARD_ISO7816_ID_USART ID_USART0
/* USART peripherals for a phone and SIM card setup */
/* USART peripheral connected to the SIM card */
#define USART_SIM USART0 #define USART_SIM USART0
/* ID of USART peripheral connected to the SIM card */
#define ID_USART_SIM ID_USART0 #define ID_USART_SIM ID_USART0
#define USART_PHONE USART1 /* Interrupt request ID of USART peripheral connected to the SIM card */
#define ID_USART_PHONE ID_USART1 #define IRQ_USART_SIM USART0_IRQn
/* USART peripheral connected to the phone */
#define USART_PHONE USART1
/* ID of USART peripheral connected to the phone */
#define ID_USART_PHONE ID_USART1
/* Interrupt request ID of USART peripheral connected to the phone */
#define IRQ_USART_PHONE USART1_IRQn
#define SIM_PWEN PIO_PA5 #define SIM_PWEN PIO_PA5
#define VCC_FWD PIO_PA26 #define VCC_FWD PIO_PA26
//** USB **/
// USB pull-up control pin definition (PA16).
// Default: 1 (USB Pullup deactivated)
#define PIN_USB_PULLUP {1 << 16, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
// Board has UDP controller // Board has UDP controller
#define BOARD_USB_UDP #define BOARD_USB_UDP
// D+ has external pull-up
#define BOARD_USB_PULLUP_EXTERNAL
#define BOARD_USB_NUMENDPOINTS 8
// FIXME: in all other cases return 0?
#define BOARD_USB_ENDPOINTS_MAXPACKETSIZE(i) (((i == 4) || (i == 5))? 512 : 64)
#define BOARD_USB_ENDPOINTS_BANKS(i) (((i == 0) || (i == 3)) ? 1 : 2)
#define USB_VENDOR_OPENMOKO 0x1d50
#define USB_PRODUCT_OWHW_SAM3_DFU 0x4001 /* was 0x4000 */
#define USB_PRODUCT_OWHW_SAM3 0x4001
#define USB_PRODUCT_QMOD_HUB 0x4002
#define USB_PRODUCT_QMOD_SAM3_DFU 0x4004 /* was 0x4003 */
#define USB_PRODUCT_QMOD_SAM3 0x4004
#define USB_PRODUCT_SIMTRACE2_DFU 0x60e3 /* was 0x60e2 */
#define USB_PRODUCT_SIMTRACE2 0x60e3
#define BOARD_USB_DFU #define BOARD_USB_DFU
#define BOARD_DFU_BOOT_SIZE (16 * 1024) #define BOARD_DFU_BOOT_SIZE (16 * 1024)
@@ -119,4 +126,5 @@
extern void board_exec_dbg_cmd(int ch); extern void board_exec_dbg_cmd(int ch);
extern void board_main_top(void); extern void board_main_top(void);
extern int board_override_enter_dfu(void);
#endif #endif

View File

@@ -26,7 +26,6 @@
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
/** /**
* \file * \file
* *

View File

@@ -1,3 +1,18 @@
/* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#pragma once #pragma once
int get_board_version_adc(void); int get_board_version_adc(void);
uint32_t adc2uv(uint16_t adc);

View File

@@ -1,3 +1,17 @@
/* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#pragma once #pragma once
enum led { enum led {
@@ -13,9 +27,11 @@ enum led_pattern {
BLINK_3O_30F = 3, BLINK_3O_30F = 3,
BLINK_3O_1F_3O_30F = 4, BLINK_3O_1F_3O_30F = 4,
BLINK_3O_1F_3O_1F_3O_30F= 5, BLINK_3O_1F_3O_1F_3O_30F= 5,
BLINK_200O_F = 6, BLINK_2O_F = 6,
BLINK_600O_F = 7, BLINK_200O_F = 7,
BLINK_CUSTOM = 8, BLINK_600O_F = 8,
BLINK_CUSTOM = 9,
BLINK_2F_O,
_NUM_LED_BLINK _NUM_LED_BLINK
}; };

View File

@@ -1,4 +1,17 @@
/* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef _MANIFEST_H #ifndef _MANIFEST_H
#define _MANIFEST_H #define _MANIFEST_H

View File

@@ -1,4 +1,26 @@
/* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#pragma once #pragma once
/** switch card lines to use physical or emulated card
* @param[in] nr card interface number (i.e. slot)
* @param[in] physical which physical interface to switch to (e.g. 0: physical, 1: virtual)
* @return 0 on success, negative else
*/
int sim_switch_use_physical(unsigned int nr, int physical); int sim_switch_use_physical(unsigned int nr, int physical);
/** initialise card switching capabilities
* @return number of switchable card interfaces
*/
int sim_switch_init(void); int sim_switch_init(void);

View File

@@ -2,6 +2,7 @@
* ATMEL Microcontroller Software Support * ATMEL Microcontroller Software Support
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* Copyright (c) 2009, Atmel Corporation * Copyright (c) 2009, Atmel Corporation
* Copyright (c) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
* *
* All rights reserved. * All rights reserved.
* *
@@ -26,19 +27,17 @@
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
#ifndef _UART_CONSOLE_ #ifndef _UART_CONSOLE_
#define _UART_CONSOLE_ #define _UART_CONSOLE_
#include <stdint.h> #include <stdint.h>
extern void UART_Configure( uint32_t dwBaudrate, uint32_t dwMasterClock ) ; extern void UART_Configure( uint32_t dwBaudrate, uint32_t dwMasterClock ) ;
extern void UART_Exit( void ) ;
extern void UART_PutChar( uint8_t uc ) ; extern void UART_PutChar( uint8_t uc ) ;
extern void UART_PutChar_Sync( uint8_t uc ) ;
extern uint32_t UART_GetChar( void ) ; extern uint32_t UART_GetChar( void ) ;
extern uint32_t UART_IsRxReady( void ) ; extern uint32_t UART_IsRxReady( void ) ;
extern void UART_DumpFrame( uint8_t* pucFrame, uint32_t dwSize ) ; extern void UART_DumpFrame( uint8_t* pucFrame, uint32_t dwSize ) ;
extern void UART_DumpMemory( uint8_t* pucBuffer, uint32_t dwSize, uint32_t dwAddress ) ; extern void UART_DumpMemory( uint8_t* pucBuffer, uint32_t dwSize, uint32_t dwAddress ) ;
extern uint32_t UART_GetInteger( uint32_t* pdwValue ) ; extern uint32_t UART_GetInteger( uint32_t* pdwValue ) ;

View File

@@ -1,203 +1,208 @@
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support * ATMEL Microcontroller Software Support
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* Copyright (c) 2010, Atmel Corporation * Copyright (c) 2010, Atmel Corporation
* * Copyright (c) 2017, Harald Welte <laforge@gnumonks.org>
* All rights reserved. * Copyright (c) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
* *
* Redistribution and use in source and binary forms, with or without * All rights reserved.
* modification, are permitted provided that the following conditions are met: *
* * Redistribution and use in source and binary forms, with or without
* - Redistributions of source code must retain the above copyright notice, * modification, are permitted provided that the following conditions are met:
* this list of conditions and the disclaimer below. *
* * - Redistributions of source code must retain the above copyright notice,
* Atmel's name may not be used to endorse or promote products derived from * this list of conditions and the disclaimer below.
* this software without specific prior written permission. *
* * Atmel's name may not be used to endorse or promote products derived from
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR * this software without specific prior written permission.
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* ---------------------------------------------------------------------------- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
*/ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
/*---------------------------------------------------------------------------- */
* Headers
*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------
* Headers
#include "board.h" *----------------------------------------------------------------------------*/
#include "board_lowlevel.h"
#include "board.h"
/*---------------------------------------------------------------------------- #include "board_lowlevel.h"
* Exported variables
*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------
* Exported variables
/* Stack Configuration */ *----------------------------------------------------------------------------*/
#define STACK_SIZE 0x900 /** Stack size (in DWords) */
__attribute__ ((aligned(8),section(".stack"))) /* Stack Configuration */
uint32_t pdwStack[STACK_SIZE] ; #define STACK_SIZE 0x900 /** Stack size (in DWords) */
__attribute__ ((aligned(8),section(".stack")))
/* Initialize segments */ uint32_t pdwStack[STACK_SIZE] ;
extern uint32_t _sfixed;
extern uint32_t _efixed; /* Initialize segments */
extern uint32_t _etext; extern uint32_t _sfixed;
extern uint32_t _srelocate; extern uint32_t _efixed;
extern uint32_t _erelocate; extern uint32_t _etext;
extern uint32_t _szero; extern uint32_t _srelocate;
extern uint32_t _ezero; extern uint32_t _erelocate;
extern uint32_t _szero;
extern uint32_t _ezero;
/*----------------------------------------------------------------------------
* ProtoTypes
*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------
* ProtoTypes
/** \cond DOXYGEN_SHOULD_SKIP_THIS */ *----------------------------------------------------------------------------*/
extern int main( void ) ;
/** \endcond */ /** \cond DOXYGEN_SHOULD_SKIP_THIS */
void ResetException( void ) ; extern int main( void ) ;
/** \endcond */
/*------------------------------------------------------------------------------ void ResetException( void ) ;
* Exception Table
*------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------
* Exception Table
__attribute__((section(".vectors"))) *------------------------------------------------------------------------------*/
IntFunc exception_table[] = {
__attribute__((section(".vectors")))
/* Configure Initial Stack Pointer, using linker-generated symbols */ IntFunc exception_table[] = {
(IntFunc)(&pdwStack[STACK_SIZE-1]),
ResetException, /* Configure Initial Stack Pointer, using linker-generated symbols */
(IntFunc)(&pdwStack[STACK_SIZE-1]),
NMI_Handler, ResetException,
HardFault_Handler,
MemManage_Handler, NMI_Handler,
BusFault_Handler, HardFault_Handler,
UsageFault_Handler, MemManage_Handler,
0, 0, 0, 0, /* Reserved */ BusFault_Handler,
SVC_Handler, UsageFault_Handler,
DebugMon_Handler, 0, 0, 0, 0, /* Reserved */
0, /* Reserved */ SVC_Handler,
PendSV_Handler, DebugMon_Handler,
SysTick_Handler, 0, /* Reserved */
PendSV_Handler,
/* Configurable interrupts */ SysTick_Handler,
SUPC_IrqHandler, /* 0 Supply Controller */
RSTC_IrqHandler, /* 1 Reset Controller */ /* Configurable interrupts */
RTC_IrqHandler, /* 2 Real Time Clock */ SUPC_IrqHandler, /* 0 Supply Controller */
RTT_IrqHandler, /* 3 Real Time Timer */ RSTC_IrqHandler, /* 1 Reset Controller */
WDT_IrqHandler, /* 4 Watchdog Timer */ RTC_IrqHandler, /* 2 Real Time Clock */
PMC_IrqHandler, /* 5 PMC */ RTT_IrqHandler, /* 3 Real Time Timer */
EEFC_IrqHandler, /* 6 EEFC */ WDT_IrqHandler, /* 4 Watchdog Timer */
IrqHandlerNotUsed, /* 7 Reserved */ PMC_IrqHandler, /* 5 PMC */
UART0_IrqHandler, /* 8 UART0 */ EEFC_IrqHandler, /* 6 EEFC */
UART1_IrqHandler, /* 9 UART1 */ IrqHandlerNotUsed, /* 7 Reserved */
SMC_IrqHandler, /* 10 SMC */ UART0_IrqHandler, /* 8 UART0 */
PIOA_IrqHandler, /* 11 Parallel IO Controller A */ UART1_IrqHandler, /* 9 UART1 */
PIOB_IrqHandler, /* 12 Parallel IO Controller B */ SMC_IrqHandler, /* 10 SMC */
PIOC_IrqHandler, /* 13 Parallel IO Controller C */ PIOA_IrqHandler, /* 11 Parallel IO Controller A */
USART0_IrqHandler, /* 14 USART 0 */ PIOB_IrqHandler, /* 12 Parallel IO Controller B */
USART1_IrqHandler, /* 15 USART 1 */ PIOC_IrqHandler, /* 13 Parallel IO Controller C */
IrqHandlerNotUsed, /* 16 Reserved */ USART0_IrqHandler, /* 14 USART 0 */
IrqHandlerNotUsed, /* 17 Reserved */ USART1_IrqHandler, /* 15 USART 1 */
MCI_IrqHandler, /* 18 MCI */ IrqHandlerNotUsed, /* 16 Reserved */
TWI0_IrqHandler, /* 19 TWI 0 */ IrqHandlerNotUsed, /* 17 Reserved */
TWI1_IrqHandler, /* 20 TWI 1 */ MCI_IrqHandler, /* 18 MCI */
SPI_IrqHandler, /* 21 SPI */ TWI0_IrqHandler, /* 19 TWI 0 */
SSC_IrqHandler, /* 22 SSC */ TWI1_IrqHandler, /* 20 TWI 1 */
TC0_IrqHandler, /* 23 Timer Counter 0 */ SPI_IrqHandler, /* 21 SPI */
TC1_IrqHandler, /* 24 Timer Counter 1 */ SSC_IrqHandler, /* 22 SSC */
TC2_IrqHandler, /* 25 Timer Counter 2 */ TC0_IrqHandler, /* 23 Timer Counter 0 */
TC3_IrqHandler, /* 26 Timer Counter 3 */ TC1_IrqHandler, /* 24 Timer Counter 1 */
TC4_IrqHandler, /* 27 Timer Counter 4 */ TC2_IrqHandler, /* 25 Timer Counter 2 */
TC5_IrqHandler, /* 28 Timer Counter 5 */ TC3_IrqHandler, /* 26 Timer Counter 3 */
ADC_IrqHandler, /* 29 ADC controller */ TC4_IrqHandler, /* 27 Timer Counter 4 */
DAC_IrqHandler, /* 30 DAC controller */ TC5_IrqHandler, /* 28 Timer Counter 5 */
PWM_IrqHandler, /* 31 PWM */ ADC_IrqHandler, /* 29 ADC controller */
CRCCU_IrqHandler, /* 32 CRC Calculation Unit */ DAC_IrqHandler, /* 30 DAC controller */
ACC_IrqHandler, /* 33 Analog Comparator */ PWM_IrqHandler, /* 31 PWM */
USBD_IrqHandler, /* 34 USB Device Port */ CRCCU_IrqHandler, /* 32 CRC Calculation Unit */
IrqHandlerNotUsed /* 35 not used */ ACC_IrqHandler, /* 33 Analog Comparator */
}; USBD_IrqHandler, /* 34 USB Device Port */
IrqHandlerNotUsed /* 35 not used */
#if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu) };
#include "usb/device/dfu/dfu.h"
static void BootIntoApp(void) #if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu)
{ #include "usb/device/dfu/dfu.h"
unsigned int *pSrc; static void BootIntoApp(void)
void (*appReset)(void); {
unsigned int *pSrc;
pSrc = (unsigned int *) ((unsigned char *)IFLASH_ADDR + BOARD_DFU_BOOT_SIZE); void (*appReset)(void);
SCB->VTOR = ((unsigned int)(pSrc)) | (0x0 << 7);
appReset = pSrc[1]; pSrc = (unsigned int *) ((unsigned char *)IFLASH_ADDR + BOARD_DFU_BOOT_SIZE);
/* set vector table to application vector table (store at the beginning of the application) */
g_dfu->state = DFU_STATE_appIDLE; SCB->VTOR = (unsigned int)(pSrc);
/* set stack pointer to address provided in the beginning of the application (loaded into a register first) */
appReset(); __asm__ volatile ("MSR msp,%0" : :"r"(*pSrc));
} /* start application (by jumping to the reset function which address is stored as second entry of the vector table) */
#endif appReset = (void(*)(void))pSrc[1];
/** g_dfu->state = DFU_STATE_appIDLE;
* \brief This is the code that gets called on processor reset.
* To initialize the device, and call the main() routine. appReset();
*/ }
void ResetException( void ) #endif
{
uint32_t *pSrc, *pDest ; /**
* \brief This is the code that gets called on processor reset.
/* Low level Initialize */ * To initialize the device, and call the main() routine.
LowLevelInit() ; */
void ResetException( void )
{
#if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu) uint32_t *pSrc, *pDest ;
/* we are before the text segment has been relocated, so g_dfu is
* not initialized yet */ /* Low level Initialize */
g_dfu = &_g_dfu; LowLevelInit() ;
if ((g_dfu->magic != USB_DFU_MAGIC) && !USBDFU_OverrideEnterDFU()) {
BootIntoApp();
/* Infinite loop */ #if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu)
while ( 1 ) ; if (!USBDFU_OverrideEnterDFU()) {
} UART_Exit();
#endif __disable_irq();
BootIntoApp();
/* Initialize the relocate segment */ /* Infinite loop */
pSrc = &_etext ; while ( 1 ) ;
pDest = &_srelocate ; }
#endif
if ( pSrc != pDest )
{ /* Initialize the relocate segment */
for ( ; pDest < &_erelocate ; ) pSrc = &_etext ;
{ pDest = &_srelocate ;
*pDest++ = *pSrc++ ;
} if ( pSrc != pDest )
} {
for ( ; pDest < &_erelocate ; )
/* Clear the zero segment */ {
for ( pDest = &_szero ; pDest < &_ezero ; ) *pDest++ = *pSrc++ ;
{ }
*pDest++ = 0; }
}
/* Clear the zero segment */
/* Set the vector table base address */ for ( pDest = &_szero ; pDest < &_ezero ; )
pSrc = (uint32_t *)&_sfixed; {
SCB->VTOR = ( (uint32_t)pSrc & SCB_VTOR_TBLOFF_Msk ) ; *pDest++ = 0;
}
if ( ((uint32_t)pSrc >= IRAM_ADDR) && ((uint32_t)pSrc < IRAM_ADDR+IRAM_SIZE) )
{ /* Set the vector table base address */
SCB->VTOR |= 1 << SCB_VTOR_TBLBASE_Pos ; pSrc = (uint32_t *)&_sfixed;
} SCB->VTOR = ( (uint32_t)pSrc & SCB_VTOR_TBLOFF_Msk ) ;
/* App should have disabled interrupts during the transition */ if ( ((uint32_t)pSrc >= IRAM_ADDR) && ((uint32_t)pSrc < IRAM_ADDR+IRAM_SIZE) )
__enable_irq(); {
SCB->VTOR |= 1 << SCB_VTOR_TBLBASE_Pos ;
/* Branch to main function */ }
main() ;
/* App should have disabled interrupts during the transition */
/* Infinite loop */ __enable_irq();
while ( 1 ) ;
} /* Branch to main function */
main() ;
/* Infinite loop */
while ( 1 ) ;
}

View File

@@ -1,216 +1,217 @@
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support * ATMEL Microcontroller Software Support
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* Copyright (c) 2009, Atmel Corporation * Copyright (c) 2009, Atmel Corporation
* * Copyright (c) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
* All rights reserved. *
* * All rights reserved.
* Redistribution and use in source and binary forms, with or without *
* modification, are permitted provided that the following conditions are met: * Redistribution and use in source and binary forms, with or without
* * modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice, *
* this list of conditions and the disclaimer below. * - Redistributions of source code must retain the above copyright notice,
* * this list of conditions and the disclaimer below.
* Atmel's name may not be used to endorse or promote products derived from *
* this software without specific prior written permission. * Atmel's name may not be used to endorse or promote products derived from
* * this software without specific prior written permission.
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR *
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* ---------------------------------------------------------------------------- * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ * ----------------------------------------------------------------------------
*/
/**
* \file /**
* * \file
* Provides the low-level initialization function that called on chip startup. *
*/ * Provides the low-level initialization function that called on chip startup.
*/
/*----------------------------------------------------------------------------
* Headers /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ * Headers
*----------------------------------------------------------------------------*/
#include "board.h"
#include "board.h"
/*----------------------------------------------------------------------------
* Local definitions /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ * Local definitions
*----------------------------------------------------------------------------*/
#define BOARD_OSCOUNT (CKGR_MOR_MOSCXTST(0x8))
#define BOARD_MCKR (PMC_MCKR_PRES_CLK | PMC_MCKR_CSS_PLLA_CLK) #define BOARD_OSCOUNT (CKGR_MOR_MOSCXTST(0x8))
#define BOARD_MCKR (PMC_MCKR_PRES_CLK | PMC_MCKR_CSS_PLLA_CLK)
#if (BOARD_MCK == 48000000)
#if (BOARD_MAINOSC == 18432000) /** configure PLL to generate main clock based on main oscillator frequency */
/* Clock settings at 48MHz for 18 MHz crystal */ #if (BOARD_MAINOSC == 12000000) && (BOARD_MCK == 48000000)
#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \ #define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \
| CKGR_PLLAR_MULA(13-1) \ | CKGR_PLLAR_MULA(8-1) \
| CKGR_PLLAR_PLLACOUNT(0x1) \ | CKGR_PLLAR_PLLACOUNT(0x1) \
| CKGR_PLLAR_DIVA(5)) | CKGR_PLLAR_DIVA(2))
#elif (BOARD_MAINOSC == 12000000) #elif (BOARD_MAINOSC == 12000000) && (BOARD_MCK == 58000000)
/* QMod has 12 MHz clock, so multply by 8 (96 MHz) and divide by 2 */ #define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \
#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \ | CKGR_PLLAR_MULA(29-1) \
| CKGR_PLLAR_MULA(8-1) \ | CKGR_PLLAR_PLLACOUNT(0x1) \
| CKGR_PLLAR_PLLACOUNT(0x1) \ | CKGR_PLLAR_DIVA(6))
| CKGR_PLLAR_DIVA(2)) #elif (BOARD_MAINOSC == 12000000) && (BOARD_MCK == 60000000)
#else #define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \
#error "Please define PLLA config for your MAINOSC frequency" | CKGR_PLLAR_MULA(10-1) \
#endif /* MAINOSC */ | CKGR_PLLAR_PLLACOUNT(0x1) \
#elif (BOARD_MCK == 64000000) | CKGR_PLLAR_DIVA(2))
#if (BOARD_MAINOSC == 18432000) #elif (BOARD_MAINOSC == 18432000) && (BOARD_MCK == 47923200)
/* Clock settings at 64MHz for 18 MHz crystal: 64.512 MHz */ #define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \
#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \ | CKGR_PLLAR_MULA(13-1) \
| CKGR_PLLAR_MULA(7-1) \ | CKGR_PLLAR_PLLACOUNT(0x1) \
| CKGR_PLLAR_PLLACOUNT(0x1) \ | CKGR_PLLAR_DIVA(5))
| CKGR_PLLAR_DIVA(2)) #elif (BOARD_MAINOSC == 18432000) && (BOARD_MCK == 58982400)
#elif (BOARD_MAINOSC == 12000000) #define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \
/* QMod has 12 MHz clock, so multply by 10 / div by 2: 60 MHz */ | CKGR_PLLAR_MULA(16-1) \
#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \ | CKGR_PLLAR_PLLACOUNT(0x1) \
| CKGR_PLLAR_MULA(10-1) \ | CKGR_PLLAR_DIVA(5))
| CKGR_PLLAR_PLLACOUNT(0x1) \ #elif (BOARD_MAINOSC == 18432000) && (BOARD_MCK == 64512000)
| CKGR_PLLAR_DIVA(2)) #define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \
#error "Please define PLLA config for your MAINOSC frequency" | CKGR_PLLAR_MULA(7-1) \
#endif /* MAINOSC */ | CKGR_PLLAR_PLLACOUNT(0x1) \
#else | CKGR_PLLAR_DIVA(2))
#error "No PLL settings for current BOARD_MCK." #else
#endif #error "Please define PLLA config for your BOARD_MCK/MAINOSC frequency"
#endif
#if (BOARD_MAINOSC == 12000000)
#define PLLB_CFG (CKGR_PLLBR_DIVB(2)|CKGR_PLLBR_MULB(8-1)|CKGR_PLLBR_PLLBCOUNT_Msk) #if (BOARD_MAINOSC == 12000000)
#elif (BOARD_MAINOSC == 18432000) #define PLLB_CFG (CKGR_PLLBR_DIVB(2)|CKGR_PLLBR_MULB(8-1)|CKGR_PLLBR_PLLBCOUNT_Msk)
#define PLLB_CFG (CKGR_PLLBR_DIVB(5)|CKGR_PLLBR_MULB(13-1)|CKGR_PLLBR_PLLBCOUNT_Msk) #elif (BOARD_MAINOSC == 18432000)
#else #define PLLB_CFG (CKGR_PLLBR_DIVB(5)|CKGR_PLLBR_MULB(13-1)|CKGR_PLLBR_PLLBCOUNT_Msk)
#error "Please configure PLLB for your MAINOSC freq" #else
#endif #error "Please configure PLLB for your MAINOSC freq"
#endif
/* Define clock timeout */
#define CLOCK_TIMEOUT 0xFFFFFFFF /* Define clock timeout */
#define CLOCK_TIMEOUT 0xFFFFFFFF
/**
* \brief Configure 48MHz Clock for USB /**
*/ * \brief Configure 48MHz Clock for USB
static void _ConfigureUsbClock(void) */
{ static void _ConfigureUsbClock(void)
/* Enable PLLB for USB */ {
PMC->CKGR_PLLBR = PLLB_CFG; /* Enable PLLB for USB */
while ((PMC->PMC_SR & PMC_SR_LOCKB) == 0) ; PMC->CKGR_PLLBR = PLLB_CFG;
while ((PMC->PMC_SR & PMC_SR_LOCKB) == 0) ;
/* USB Clock uses PLLB */
PMC->PMC_USB = PMC_USB_USBDIV(0) /* /1 (no divider) */ /* USB Clock uses PLLB */
| PMC_USB_USBS; /* PLLB */ PMC->PMC_USB = PMC_USB_USBDIV(0) /* /1 (no divider) */
} | PMC_USB_USBS; /* PLLB */
}
/*----------------------------------------------------------------------------
* Exported functions /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ * Exported functions
*----------------------------------------------------------------------------*/
/**
* \brief Performs the low-level initialization of the chip. /**
* This includes EFC and master clock configuration. * \brief Performs the low-level initialization of the chip.
* It also enable a low level on the pin NRST triggers a user reset. * This includes EFC and master clock configuration.
*/ * It also enable a low level on the pin NRST triggers a user reset.
extern WEAK void LowLevelInit( void ) */
{ extern WEAK void LowLevelInit( void )
uint32_t timeout = 0; {
uint32_t timeout = 0;
/* Configure the Supply Monitor to reset the CPU in case VDDIO is
* lower than 3.0V. As we run the board on 3.3V, any lower voltage /* Configure the Supply Monitor to reset the CPU in case VDDIO is
* might be some kind of leakage that creeps in some way, but is not * lower than 3.0V. As we run the board on 3.3V, any lower voltage
* the "official" power supply */ * might be some kind of leakage that creeps in some way, but is not
SUPC->SUPC_SMMR = SUPC_SMMR_SMTH_3_0V | SUPC_SMMR_SMSMPL_CSM | * the "official" power supply */
SUPC_SMMR_SMRSTEN_ENABLE; SUPC->SUPC_SMMR = SUPC_SMMR_SMTH_3_0V | SUPC_SMMR_SMSMPL_CSM |
SUPC_SMMR_SMRSTEN_ENABLE;
/* enable both LED and green LED */
PIOA->PIO_PER |= PIO_LED_RED | PIO_LED_GREEN; /* enable both LED and green LED */
PIOA->PIO_OER |= PIO_LED_RED | PIO_LED_GREEN; PIOA->PIO_PER |= PIO_LED_RED | PIO_LED_GREEN;
PIOA->PIO_CODR |= PIO_LED_RED | PIO_LED_GREEN; PIOA->PIO_OER |= PIO_LED_RED | PIO_LED_GREEN;
PIOA->PIO_CODR |= PIO_LED_RED | PIO_LED_GREEN;
/* Set 3 FWS for Embedded Flash Access */
EFC->EEFC_FMR = EEFC_FMR_FWS(3); /* Set 3 FWS for Embedded Flash Access */
EFC->EEFC_FMR = EEFC_FMR_FWS(3);
/* Select external slow clock */
/* if ((SUPC->SUPC_SR & SUPC_SR_OSCSEL) != SUPC_SR_OSCSEL_CRYST) /* Select external slow clock */
{ /* if ((SUPC->SUPC_SR & SUPC_SR_OSCSEL) != SUPC_SR_OSCSEL_CRYST)
SUPC->SUPC_CR = (uint32_t)(SUPC_CR_XTALSEL_CRYSTAL_SEL | SUPC_CR_KEY(0xA5)); {
timeout = 0; SUPC->SUPC_CR = (uint32_t)(SUPC_CR_XTALSEL_CRYSTAL_SEL | SUPC_CR_KEY(0xA5));
while (!(SUPC->SUPC_SR & SUPC_SR_OSCSEL_CRYST) ); timeout = 0;
} while (!(SUPC->SUPC_SR & SUPC_SR_OSCSEL_CRYST) );
*/ }
*/
#ifndef qmod
/* Initialize main oscillator */ #ifndef qmod
if ( !(PMC->CKGR_MOR & CKGR_MOR_MOSCSEL) ) /* Initialize main oscillator */
{ if ( !(PMC->CKGR_MOR & CKGR_MOR_MOSCSEL) )
PMC->CKGR_MOR = CKGR_MOR_KEY(0x37) | BOARD_OSCOUNT | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN; {
timeout = 0; PMC->CKGR_MOR = CKGR_MOR_KEY(0x37) | BOARD_OSCOUNT | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN;
while (!(PMC->PMC_SR & PMC_SR_MOSCXTS) && (timeout++ < CLOCK_TIMEOUT)); timeout = 0;
} while (!(PMC->PMC_SR & PMC_SR_MOSCXTS) && (timeout++ < CLOCK_TIMEOUT));
}
/* Switch to 3-20MHz Xtal oscillator */
PIOB->PIO_PDR = (1 << 8) | (1 << 9); /* Switch to 3-20MHz Xtal oscillator */
PIOB->PIO_PUDR = (1 << 8) | (1 << 9); PIOB->PIO_PDR = (1 << 8) | (1 << 9);
PIOB->PIO_PPDDR = (1 << 8) | (1 << 9); PIOB->PIO_PUDR = (1 << 8) | (1 << 9);
PMC->CKGR_MOR = CKGR_MOR_KEY(0x37) | BOARD_OSCOUNT | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN | CKGR_MOR_MOSCSEL; PIOB->PIO_PPDDR = (1 << 8) | (1 << 9);
/* wait for Main XTAL oscillator stabilization */ PMC->CKGR_MOR = CKGR_MOR_KEY(0x37) | BOARD_OSCOUNT | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN | CKGR_MOR_MOSCSEL;
timeout = 0; /* wait for Main XTAL oscillator stabilization */
while (!(PMC->PMC_SR & PMC_SR_MOSCSELS) && (timeout++ < CLOCK_TIMEOUT)); timeout = 0;
#else while (!(PMC->PMC_SR & PMC_SR_MOSCSELS) && (timeout++ < CLOCK_TIMEOUT));
/* QMOD has external 12MHz clock source */ #else
PIOB->PIO_PDR = (1 << 9); /* QMOD has external 12MHz clock source */
PIOB->PIO_PUDR = (1 << 9); PIOB->PIO_PDR = (1 << 9);
PIOB->PIO_PPDDR = (1 << 9); PIOB->PIO_PUDR = (1 << 9);
PMC->CKGR_MOR = CKGR_MOR_KEY(0x37) | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTBY| CKGR_MOR_MOSCSEL; PIOB->PIO_PPDDR = (1 << 9);
#endif PMC->CKGR_MOR = CKGR_MOR_KEY(0x37) | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTBY| CKGR_MOR_MOSCSEL;
#endif
/* disable the red LED after main clock initialization */
PIOA->PIO_SODR = PIO_LED_RED; /* disable the red LED after main clock initialization */
PIOA->PIO_SODR = PIO_LED_RED;
/* "switch" to main clock as master clock source (should already be the case */
PMC->PMC_MCKR = (PMC->PMC_MCKR & ~(uint32_t)PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_MAIN_CLK; /* "switch" to main clock as master clock source (should already be the case */
/* wait for master clock to be ready */ PMC->PMC_MCKR = (PMC->PMC_MCKR & ~(uint32_t)PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_MAIN_CLK;
for ( timeout = 0; !(PMC->PMC_SR & PMC_SR_MCKRDY) && (timeout++ < CLOCK_TIMEOUT) ; ); /* wait for master clock to be ready */
for ( timeout = 0; !(PMC->PMC_SR & PMC_SR_MCKRDY) && (timeout++ < CLOCK_TIMEOUT) ; );
/* Initialize PLLA */
PMC->CKGR_PLLAR = BOARD_PLLAR; /* Initialize PLLA */
/* Wait for PLLA to lock */ PMC->CKGR_PLLAR = BOARD_PLLAR;
timeout = 0; /* Wait for PLLA to lock */
while (!(PMC->PMC_SR & PMC_SR_LOCKA) && (timeout++ < CLOCK_TIMEOUT)); timeout = 0;
while (!(PMC->PMC_SR & PMC_SR_LOCKA) && (timeout++ < CLOCK_TIMEOUT));
/* Switch to main clock (again ?!?) */
PMC->PMC_MCKR = (BOARD_MCKR & ~PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_MAIN_CLK; /* Switch to main clock (again ?!?) */
/* wait for master clock to be ready */ PMC->PMC_MCKR = (BOARD_MCKR & ~PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_MAIN_CLK;
for ( timeout = 0; !(PMC->PMC_SR & PMC_SR_MCKRDY) && (timeout++ < CLOCK_TIMEOUT) ; ); /* wait for master clock to be ready */
for ( timeout = 0; !(PMC->PMC_SR & PMC_SR_MCKRDY) && (timeout++ < CLOCK_TIMEOUT) ; );
/* switch to PLLA as master clock source */
PMC->PMC_MCKR = BOARD_MCKR ; /* switch to PLLA as master clock source */
/* wait for master clock to be ready */ PMC->PMC_MCKR = BOARD_MCKR ;
for ( timeout = 0; !(PMC->PMC_SR & PMC_SR_MCKRDY) && (timeout++ < CLOCK_TIMEOUT) ; ); /* wait for master clock to be ready */
for ( timeout = 0; !(PMC->PMC_SR & PMC_SR_MCKRDY) && (timeout++ < CLOCK_TIMEOUT) ; );
/* Configure SysTick for 1ms */
SysTick_Config(BOARD_MCK/1000); /* Configure SysTick for 1ms */
SysTick_Config(BOARD_MCK/1000);
_ConfigureUsbClock();
} _ConfigureUsbClock();
}
/* SysTick based delay function */
/* SysTick based delay function */
volatile uint32_t jiffies;
volatile uint32_t jiffies;
/* Interrupt handler for SysTick interrupt */
void SysTick_Handler(void) /* Interrupt handler for SysTick interrupt */
{ void SysTick_Handler(void)
jiffies++; {
} jiffies++;
}
void mdelay(unsigned int msecs)
{ void mdelay(unsigned int msecs)
uint32_t jiffies_start = jiffies; {
do { uint32_t jiffies_start = jiffies;
} while ((jiffies - jiffies_start) < msecs); do {
} } while ((jiffies - jiffies_start) < msecs);
}

View File

@@ -1,9 +1,22 @@
/* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#include "board.h" #include "board.h"
#include "boardver_adc.h" #include "boardver_adc.h"
/* FIXME: share this with mode_cardemu.c */
#define UV_PER_LSB ((3300 * 1000) / 4096) #define UV_PER_LSB ((3300 * 1000) / 4096)
static uint32_t adc2uv(uint16_t adc) uint32_t adc2uv(uint16_t adc)
{ {
uint32_t uv = (uint32_t) adc * UV_PER_LSB; uint32_t uv = (uint32_t) adc * UV_PER_LSB;
return uv; return uv;
@@ -73,7 +86,7 @@ int get_board_version_adc(void)
/* convert to voltage */ /* convert to voltage */
sample = ADC->ADC_CDR[2]; sample = ADC->ADC_CDR[2];
uv = adc2uv(sample); uv = adc2uv(sample);
TRACE_INFO("VERSION_DET ADC=%u => %u uV\r\n", sample, uv); TRACE_INFO("VERSION_DET ADC=%u => %lu uV\r\n", sample, uv);
/* FIXME: convert to board version based on thresholds */ /* FIXME: convert to board version based on thresholds */

View File

@@ -1,3 +1,22 @@
/* LED control
*
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
@@ -16,9 +35,9 @@ static void led_set(enum led led, int on)
ASSERT(led < PIO_LISTSIZE(pinsLeds)); ASSERT(led < PIO_LISTSIZE(pinsLeds));
if (on) if (on)
PIO_Set(&pinsLeds[led]); PIO_Clear(&pinsLeds[led]);
else else
PIO_Clear(&pinsLeds[led]); PIO_Set(&pinsLeds[led]);
} }
/* LED blinking code */ /* LED blinking code */
@@ -27,7 +46,7 @@ static void led_set(enum led led, int on)
struct blink_state { struct blink_state {
/* duration of the state in ms */ /* duration of the state in ms */
uint16_t duration; uint16_t duration;
/* bringhtness of LED during the state */ /* brightness of LED during the state */
uint8_t on; uint8_t on;
} __attribute__((packed)); } __attribute__((packed));
@@ -54,13 +73,23 @@ static const struct blink_state bs_3on_1off_3on_30off[] = {
static const struct blink_state bs_3on_1off_3on_1off_3on_30off[] = { static const struct blink_state bs_3on_1off_3on_1off_3on_30off[] = {
{ 300, 1 }, { 100, 0 }, { 300, 1 }, { 100, 0 }, { 300, 1 }, { 3000, 0 } { 300, 1 }, { 100, 0 }, { 300, 1 }, { 100, 0 }, { 300, 1 }, { 3000, 0 }
}; };
static const struct blink_state bs_2on_off[] = {
{ 200, 1 }, { 0, 0 },
};
static const struct blink_state bs_200on_off[] = { static const struct blink_state bs_200on_off[] = {
{ 20000, 1 }, { 0, 0 }, { 20000, 1 }, { 0, 0 },
}; };
static const struct blink_state bs_600on_off[] = { static const struct blink_state bs_600on_off[] = {
{ 60000, 1 }, { 0, 0 }, { 60000, 1 }, { 0, 0 },
}; };
static const struct blink_state bs_2off_on[] = {
{ 200, 0 }, { 0, 1 },
};
/* a blink pattern is an array of blink_states */ /* a blink pattern is an array of blink_states */
struct blink_pattern { struct blink_pattern {
@@ -94,6 +123,10 @@ static const struct blink_pattern patterns[] = {
.states = bs_3on_1off_3on_1off_3on_30off, .states = bs_3on_1off_3on_1off_3on_30off,
.size = ARRAY_SIZE(bs_3on_1off_3on_1off_3on_30off), .size = ARRAY_SIZE(bs_3on_1off_3on_1off_3on_30off),
}, },
[BLINK_2O_F] = {
.states = bs_2on_off,
.size = ARRAY_SIZE(bs_2on_off),
},
[BLINK_200O_F] = { [BLINK_200O_F] = {
.states = bs_200on_off, .states = bs_200on_off,
.size = ARRAY_SIZE(bs_200on_off), .size = ARRAY_SIZE(bs_200on_off),
@@ -102,6 +135,11 @@ static const struct blink_pattern patterns[] = {
.states = bs_600on_off, .states = bs_600on_off,
.size = ARRAY_SIZE(bs_600on_off), .size = ARRAY_SIZE(bs_600on_off),
}, },
[BLINK_2F_O] = {
.states = bs_2off_on,
.size = ARRAY_SIZE(bs_2off_on),
},
}; };
struct led_state { struct led_state {
@@ -158,16 +196,16 @@ static void blink_tmr_cb(void *data)
} }
static struct led_state led_state[] = { static struct led_state led_state[] = {
[LED_GREEN] = {
.led = LED_GREEN,
.timer.cb = blink_tmr_cb,
.timer.data = &led_state[LED_GREEN],
},
[LED_RED] = { [LED_RED] = {
.led = LED_RED, .led = LED_RED,
.timer.cb = blink_tmr_cb, .timer.cb = blink_tmr_cb,
.timer.data = &led_state[LED_RED], .timer.data = &led_state[LED_RED],
}, },
[LED_GREEN] = {
.led = LED_GREEN,
.timer.cb = blink_tmr_cb,
.timer.data = &led_state[LED_GREEN],
},
}; };
#endif /* PINS_LEDS */ #endif /* PINS_LEDS */

View File

@@ -1,4 +1,17 @@
/* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#include "manifest.h" #include "manifest.h"
const char *manifest_application = APPLICATION; const char *manifest_application = APPLICATION;

View File

@@ -1,380 +1,453 @@
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support * ATMEL Microcontroller Software Support
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* Copyright (c) 2009, Atmel Corporation * Copyright (c) 2009, Atmel Corporation
* * Copyright (c) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
* All rights reserved. *
* * All rights reserved.
* Redistribution and use in source and binary forms, with or without *
* modification, are permitted provided that the following conditions are met: * Redistribution and use in source and binary forms, with or without
* * modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice, *
* this list of conditions and the disclaimer below. * - Redistributions of source code must retain the above copyright notice,
* * this list of conditions and the disclaimer below.
* Atmel's name may not be used to endorse or promote products derived from *
* this software without specific prior written permission. * Atmel's name may not be used to endorse or promote products derived from
* * this software without specific prior written permission.
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR *
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* ---------------------------------------------------------------------------- * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ * ----------------------------------------------------------------------------
*/
/**
* \file /**
* * \file
* Implements UART console. *
* * Implements UART console.
*/ *
*/
/*----------------------------------------------------------------------------
* Headers /*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/ * Headers
*----------------------------------------------------------------------------*/
#include "board.h"
#include "board.h"
#include <stdio.h>
#include <stdint.h> #include <stdio.h>
#include <stdint.h>
/*----------------------------------------------------------------------------
* Definitions #include "ringbuffer.h"
*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
/*---------------------------------------------------------------------------- * Definitions
* Variables *----------------------------------------------------------------------------*/
*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
/** Is Console Initialized. */ * Variables
static uint8_t _ucIsConsoleInitialized=0 ; *----------------------------------------------------------------------------*/
/** /** Is Console Initialized. */
* \brief Configures an USART peripheral with the specified parameters. static uint8_t _ucIsConsoleInitialized=0;
* /** Ring buffer to queue data to be sent */
* \param baudrate Baudrate at which the USART should operate (in Hz). static ringbuf uart_tx_buffer;
* \param masterClock Frequency of the system master clock (in Hz).
*/ /**
extern void UART_Configure( uint32_t baudrate, uint32_t masterClock) * \brief Configures an USART peripheral with the specified parameters.
{ *
const Pin pPins[] = CONSOLE_PINS; * \param baudrate Baudrate at which the USART should operate (in Hz).
Uart *pUart = CONSOLE_USART; * \param masterClock Frequency of the system master clock (in Hz).
*/
/* Configure PIO */ extern void UART_Configure( uint32_t baudrate, uint32_t masterClock)
PIO_Configure(pPins, PIO_LISTSIZE(pPins)); {
const Pin pPins[] = CONSOLE_PINS;
/* Configure PMC */ Uart *pUart = CONSOLE_UART;
PMC->PMC_PCER0 = 1 << CONSOLE_ID;
/* Configure PIO */
/* Reset and disable receiver & transmitter */ PIO_Configure(pPins, PIO_LISTSIZE(pPins));
pUart->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX
| UART_CR_RXDIS | UART_CR_TXDIS; /* Configure PMC */
PMC->PMC_PCER0 = 1 << CONSOLE_ID;
/* Configure mode */
pUart->UART_MR = UART_MR_PAR_NO; /* Reset and disable receiver & transmitter */
pUart->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX
/* Configure baudrate */ | UART_CR_RXDIS | UART_CR_TXDIS;
/* Asynchronous, no oversampling */
pUart->UART_BRGR = (masterClock / baudrate) / 16; /* Configure mode */
pUart->UART_MR = UART_MR_PAR_NO;
/* Disable PDC channel */
pUart->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS; /* Configure baudrate */
/* Asynchronous, no oversampling */
/* Enable receiver and transmitter */ //pUart->UART_BRGR = (masterClock / baudrate) / 16;
pUart->UART_CR = UART_CR_RXEN | UART_CR_TXEN; if ((masterClock / baudrate) % 16 >= 7) {
pUart->UART_BRGR = ( masterClock / baudrate) / 16 + 1;
_ucIsConsoleInitialized=1 ; } else {
} pUart->UART_BRGR = ( masterClock / baudrate) / 16 + 0;
}
/**
* \brief Outputs a character on the UART line. /* Disable PDC channel */
* pUart->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS;
* \note This function is synchronous (i.e. uses polling).
* \param c Character to send. /* Reset transmit ring buffer */
*/ rbuf_reset(&uart_tx_buffer);
extern void UART_PutChar( uint8_t c )
{ /* Enable TX interrupts */
Uart *pUart=CONSOLE_USART ; pUart->UART_IER = UART_IER_TXRDY;
NVIC_EnableIRQ(CONSOLE_IRQ);
if ( !_ucIsConsoleInitialized )
{ /* Enable receiver and transmitter */
UART_Configure(CONSOLE_BAUDRATE, BOARD_MCK); pUart->UART_CR = UART_CR_RXEN | UART_CR_TXEN;
}
/* Remember the configuration is complete */
/* Wait for the transmitter to be ready */ _ucIsConsoleInitialized=1 ;
while ( (pUart->UART_SR & UART_SR_TXEMPTY) == 0 ) ; }
/* Send character */ /**
pUart->UART_THR=c ; * \brief Disables the USART peripheral and related IRQ
*/
} void UART_Exit(void)
{
/** if (!_ucIsConsoleInitialized) {
* \brief Input a character from the UART line. return;
* }
* \note This function is synchronous
* \return character received. Uart *pUart = CONSOLE_UART;
*/ pUart->UART_IDR = UART_IDR_TXRDY;
extern uint32_t UART_GetChar( void ) pUart->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS | UART_CR_TXDIS | UART_CR_RSTSTA;
{ PMC->PMC_PCDR0 = 1 << CONSOLE_ID;
Uart *pUart=CONSOLE_USART ; NVIC_DisableIRQ(CONSOLE_IRQ);
}
if ( !_ucIsConsoleInitialized )
{ /** Interrupt Service routine to transmit queued data */
UART_Configure(CONSOLE_BAUDRATE, BOARD_MCK); void CONSOLE_ISR(void)
} {
Uart *uart = CONSOLE_UART;
while ( (pUart->UART_SR & UART_SR_RXRDY) == 0 ) ; if (uart->UART_SR & UART_SR_TXRDY) {
if (!rbuf_is_empty(&uart_tx_buffer)) {
return pUart->UART_RHR ; uart->UART_THR = rbuf_read(&uart_tx_buffer);
} } else {
uart->UART_IDR = UART_IER_TXRDY;
/** }
* \brief Check if there is Input from UART line. }
* }
* \return true if there is Input.
*/ /**
extern uint32_t UART_IsRxReady( void ) * \brief Outputs a character on the UART line.
{ *
Uart *pUart=CONSOLE_USART ; * \note This function is asynchronous (i.e. uses a buffer and interrupt to complete the transfer).
* \param c Character to send.
if ( !_ucIsConsoleInitialized ) */
{ void UART_PutChar( uint8_t uc )
UART_Configure( CONSOLE_BAUDRATE, BOARD_MCK ) ; {
} Uart *pUart = CONSOLE_UART ;
return (pUart->UART_SR & UART_SR_RXRDY) > 0 ; /* Initialize console is not already done */
} if ( !_ucIsConsoleInitialized )
{
/** UART_Configure(CONSOLE_BAUDRATE, BOARD_MCK);
* Displays the content of the given frame on the UART0. }
*
* \param pucFrame Pointer to the frame to dump. if (!rbuf_is_full(&uart_tx_buffer)) {
* \param dwSize Buffer size in bytes. rbuf_write(&uart_tx_buffer, uc);
*/ if (!(pUart->UART_IMR & UART_IMR_TXRDY)) {
extern void UART_DumpFrame( uint8_t* pucFrame, uint32_t dwSize ) pUart->UART_IER = UART_IER_TXRDY;
{ CONSOLE_ISR();
uint32_t dw ; }
}
for ( dw=0 ; dw < dwSize ; dw++ ) }
{
printf( "%02X ", pucFrame[dw] ) ; /**
} * \brief Outputs a character on the UART line.
*
printf( "\n\r" ) ; * \note This function is synchronous (i.e. uses polling and blocks until the transfer is complete).
} * \param c Character to send.
*/
/** void UART_PutChar_Sync( uint8_t uc )
* Displays the content of the given buffer on the UART0. {
* Uart *pUart = CONSOLE_UART ;
* \param pucBuffer Pointer to the buffer to dump.
* \param dwSize Buffer size in bytes. /* Initialize console is not already done */
* \param dwAddress Start address to display if ( !_ucIsConsoleInitialized )
*/ {
extern void UART_DumpMemory( uint8_t* pucBuffer, uint32_t dwSize, uint32_t dwAddress ) UART_Configure(CONSOLE_BAUDRATE, BOARD_MCK);
{ }
uint32_t i ;
uint32_t j ; while (!(pUart->UART_SR & UART_SR_TXRDY)); /* Wait for transfer buffer to be empty */
uint32_t dwLastLineStart ; pUart->UART_THR = uc; /* Send data to UART peripheral */
uint8_t* pucTmp ; while (!(pUart->UART_SR & UART_SR_TXRDY)); /* Wait for transfer buffer to transferred to shift register */
while (!(pUart->UART_SR & UART_SR_TXEMPTY)); /* Wait for transfer shift register to be empty (i.e. transfer is complete) */
for ( i=0 ; i < (dwSize / 16) ; i++ ) }
{
printf( "0x%08X: ", (unsigned int)(dwAddress + (i*16)) ) ; /**
pucTmp = (uint8_t*)&pucBuffer[i*16] ; * \brief Input a character from the UART line.
*
for ( j=0 ; j < 4 ; j++ ) * \note This function is synchronous
{ * \return character received.
printf( "%02X%02X%02X%02X ", pucTmp[0], pucTmp[1], pucTmp[2], pucTmp[3] ) ; */
pucTmp += 4 ; extern uint32_t UART_GetChar( void )
} {
Uart *pUart = CONSOLE_UART ;
pucTmp=(uint8_t*)&pucBuffer[i*16] ;
if ( !_ucIsConsoleInitialized )
for ( j=0 ; j < 16 ; j++ ) {
{ UART_Configure(CONSOLE_BAUDRATE, BOARD_MCK);
UART_PutChar( *pucTmp++ ) ; }
}
while ( (pUart->UART_SR & UART_SR_RXRDY) == 0 )
printf( "\n\r" ) ; WDT_Restart(WDT);
}
return pUart->UART_RHR ;
if ( (dwSize%16) != 0 ) }
{
dwLastLineStart=dwSize - (dwSize%16) ; /**
* \brief Check if there is Input from UART line.
printf( "0x%08X: ", (unsigned int)(dwAddress + dwLastLineStart) ) ; *
for ( j=dwLastLineStart ; j < dwLastLineStart+16 ; j++ ) * \return true if there is Input.
{ */
if ( (j!=dwLastLineStart) && (j%4 == 0) ) extern uint32_t UART_IsRxReady( void )
{ {
printf( " " ) ; Uart *pUart = CONSOLE_UART;
}
if ( !_ucIsConsoleInitialized )
if ( j < dwSize ) {
{ UART_Configure( CONSOLE_BAUDRATE, BOARD_MCK ) ;
printf( "%02X", pucBuffer[j] ) ; }
}
else return (pUart->UART_SR & UART_SR_RXRDY) > 0 ;
{ }
printf(" ") ;
} /**
} * Displays the content of the given frame on the UART0.
*
printf( " " ) ; * \param pucFrame Pointer to the frame to dump.
for ( j=dwLastLineStart ; j < dwSize ; j++ ) * \param dwSize Buffer size in bytes.
{ */
UART_PutChar( pucBuffer[j] ) ; extern void UART_DumpFrame( uint8_t* pucFrame, uint32_t dwSize )
} {
uint32_t dw ;
printf( "\n\r" ) ;
} for ( dw=0 ; dw < dwSize ; dw++ )
} {
printf( "%02X ", pucFrame[dw] ) ;
/** }
* Reads an integer
* printf( "\n\r" ) ;
* \param pdwValue Pointer to the uint32_t variable to contain the input value. }
*/
extern uint32_t UART_GetInteger( uint32_t* pdwValue ) /**
{ * Displays the content of the given buffer on the UART0.
uint8_t ucKey ; *
uint8_t ucNbNb=0 ; * \param pucBuffer Pointer to the buffer to dump.
uint32_t dwValue=0 ; * \param dwSize Buffer size in bytes.
* \param dwAddress Start address to display
while ( 1 ) */
{ extern void UART_DumpMemory( uint8_t* pucBuffer, uint32_t dwSize, uint32_t dwAddress )
ucKey=UART_GetChar() ; {
UART_PutChar( ucKey ) ; uint32_t i ;
uint32_t j ;
if ( ucKey >= '0' && ucKey <= '9' ) uint32_t dwLastLineStart ;
{ uint8_t* pucTmp ;
dwValue = (dwValue * 10) + (ucKey - '0');
ucNbNb++ ; for ( i=0 ; i < (dwSize / 16) ; i++ )
} {
else printf( "0x%08X: ", (unsigned int)(dwAddress + (i*16)) ) ;
{ pucTmp = (uint8_t*)&pucBuffer[i*16] ;
if ( ucKey == 0x0D || ucKey == ' ' )
{ for ( j=0 ; j < 4 ; j++ )
if ( ucNbNb == 0 ) {
{ printf( "%02X%02X%02X%02X ", pucTmp[0], pucTmp[1], pucTmp[2], pucTmp[3] ) ;
printf( "\n\rWrite a number and press ENTER or SPACE!\n\r" ) ; pucTmp += 4 ;
return 0 ; }
}
else pucTmp=(uint8_t*)&pucBuffer[i*16] ;
{
printf( "\n\r" ) ; for ( j=0 ; j < 16 ; j++ )
*pdwValue=dwValue ; {
UART_PutChar( *pucTmp++ ) ;
return 1 ; }
}
} printf( "\n\r" ) ;
else }
{
printf( "\n\r'%c' not a number!\n\r", ucKey ) ; if ( (dwSize%16) != 0 )
{
return 0 ; dwLastLineStart=dwSize - (dwSize%16) ;
}
} printf( "0x%08X: ", (unsigned int)(dwAddress + dwLastLineStart) ) ;
} for ( j=dwLastLineStart ; j < dwLastLineStart+16 ; j++ )
} {
if ( (j!=dwLastLineStart) && (j%4 == 0) )
/** {
* Reads an integer and check the value printf( " " ) ;
* }
* \param pdwValue Pointer to the uint32_t variable to contain the input value.
* \param dwMin Minimum value if ( j < dwSize )
* \param dwMax Maximum value {
*/ printf( "%02X", pucBuffer[j] ) ;
extern uint32_t UART_GetIntegerMinMax( uint32_t* pdwValue, uint32_t dwMin, uint32_t dwMax ) }
{ else
uint32_t dwValue=0 ; {
printf(" ") ;
if ( UART_GetInteger( &dwValue ) == 0 ) }
{ }
return 0 ;
} printf( " " ) ;
for ( j=dwLastLineStart ; j < dwSize ; j++ )
if ( dwValue < dwMin || dwValue > dwMax ) {
{ UART_PutChar( pucBuffer[j] ) ;
printf( "\n\rThe number have to be between %d and %d\n\r", (int)dwMin, (int)dwMax ) ; }
return 0 ; printf( "\n\r" ) ;
} }
}
printf( "\n\r" ) ;
/**
*pdwValue = dwValue ; * Reads an integer
*
return 1 ; * \param pdwValue Pointer to the uint32_t variable to contain the input value.
} */
extern uint32_t UART_GetInteger( uint32_t* pdwValue )
/** {
* Reads an hexadecimal number uint8_t ucKey ;
* uint8_t ucNbNb=0 ;
* \param pdwValue Pointer to the uint32_t variable to contain the input value. uint32_t dwValue=0 ;
*/
extern uint32_t UART_GetHexa32( uint32_t* pdwValue ) while ( 1 )
{ {
uint8_t ucKey ; ucKey=UART_GetChar() ;
uint32_t dw = 0 ; UART_PutChar( ucKey ) ;
uint32_t dwValue = 0 ;
if ( ucKey >= '0' && ucKey <= '9' )
for ( dw=0 ; dw < 8 ; dw++ ) {
{ dwValue = (dwValue * 10) + (ucKey - '0');
ucKey = UART_GetChar() ; ucNbNb++ ;
UART_PutChar( ucKey ) ; }
else
if ( ucKey >= '0' && ucKey <= '9' ) {
{ if ( ucKey == 0x0D || ucKey == ' ' )
dwValue = (dwValue * 16) + (ucKey - '0') ; {
} if ( ucNbNb == 0 )
else {
{ printf( "\n\rWrite a number and press ENTER or SPACE!\n\r" ) ;
if ( ucKey >= 'A' && ucKey <= 'F' ) return 0 ;
{ }
dwValue = (dwValue * 16) + (ucKey - 'A' + 10) ; else
} {
else printf( "\n\r" ) ;
{ *pdwValue=dwValue ;
if ( ucKey >= 'a' && ucKey <= 'f' )
{ return 1 ;
dwValue = (dwValue * 16) + (ucKey - 'a' + 10) ; }
} }
else else
{ {
printf( "\n\rIt is not a hexa character!\n\r" ) ; printf( "\n\r'%c' not a number!\n\r", ucKey ) ;
return 0 ; return 0 ;
} }
} }
} WDT_Restart(WDT);
} }
}
printf("\n\r" ) ;
*pdwValue = dwValue ; /**
* Reads an integer and check the value
return 1 ; *
} * \param pdwValue Pointer to the uint32_t variable to contain the input value.
* \param dwMin Minimum value
#if defined __ICCARM__ /* IAR Ewarm 5.41+ */ * \param dwMax Maximum value
/** */
* \brief Outputs a character on the UART. extern uint32_t UART_GetIntegerMinMax( uint32_t* pdwValue, uint32_t dwMin, uint32_t dwMax )
* {
* \param c Character to output. uint32_t dwValue=0 ;
*
* \return The character that was output. if ( UART_GetInteger( &dwValue ) == 0 )
*/ {
extern WEAK signed int putchar( signed int c ) return 0 ;
{ }
UART_PutChar( c ) ;
if ( dwValue < dwMin || dwValue > dwMax )
return c ; {
} printf( "\n\rThe number have to be between %d and %d\n\r", (int)dwMin, (int)dwMax ) ;
#endif // defined __ICCARM__
return 0 ;
}
printf( "\n\r" ) ;
*pdwValue = dwValue ;
return 1 ;
}
/**
* Reads an hexadecimal number
*
* \param pdwValue Pointer to the uint32_t variable to contain the input value.
*/
extern uint32_t UART_GetHexa32( uint32_t* pdwValue )
{
uint8_t ucKey ;
uint32_t dw = 0 ;
uint32_t dwValue = 0 ;
for ( dw=0 ; dw < 8 ; dw++ )
{
ucKey = UART_GetChar() ;
UART_PutChar( ucKey ) ;
if ( ucKey >= '0' && ucKey <= '9' )
{
dwValue = (dwValue * 16) + (ucKey - '0') ;
}
else
{
if ( ucKey >= 'A' && ucKey <= 'F' )
{
dwValue = (dwValue * 16) + (ucKey - 'A' + 10) ;
}
else
{
if ( ucKey >= 'a' && ucKey <= 'f' )
{
dwValue = (dwValue * 16) + (ucKey - 'a' + 10) ;
}
else
{
printf( "\n\rIt is not a hexa character!\n\r" ) ;
return 0 ;
}
}
}
}
printf("\n\r" ) ;
*pdwValue = dwValue ;
return 1 ;
}
#if defined __ICCARM__ /* IAR Ewarm 5.41+ */
/**
* \brief Outputs a character on the UART.
*
* \param c Character to output.
*
* \return The character that was output.
*/
extern WEAK signed int putchar( signed int c )
{
UART_PutChar( c ) ;
return c ;
}
#endif // defined __ICCARM__

View File

@@ -1,12 +1,35 @@
/* OWHW board definition
*
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#pragma once #pragma once
#include "board_common.h" #include "board_common.h"
#include "simtrace_usb.h"
/** Name of the board */ /** Name of the board */
#define BOARD_NAME "OWHW" #define BOARD_NAME "OWHW"
/** Board definition */ /** Board definition */
#define owhw #define owhw
/** oscillator used as main clock source (in Hz) */
#define BOARD_MAINOSC 18432000 #define BOARD_MAINOSC 18432000
/** desired main clock frequency (in Hz, based on BOARD_MAINOSC) */
#define BOARD_MCK 58982400 // 18.432 * 16 / 5
/* USIM 2 interface (USART) */ /* USIM 2 interface (USART) */
#define PIN_USIM2_CLK {PIO_PA2, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT} #define PIN_USIM2_CLK {PIO_PA2, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}

View File

@@ -1,28 +1,55 @@
/* Card simulator specific functions */ /* Card simulator specific functions
/* (C) 2015 by Harald Welte <hwelte@hmw-consulting.de>
* *
* This program is free software; you can redistribute it and/or modify * (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
* it under the terms of the GNU General Public License as published by * (C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is free software; you can redistribute it and/or modify
* but WITHOUT ANY WARRANTY; without even the implied warranty of * it under the terms of the GNU General Public License as published by
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * the Free Software Foundation; either version 2 of the License, or
* GNU General Public License for more details. * (at your option) any later version.
* *
* You should have received a copy of the GNU General Public License * This program is distributed in the hope that it will be useful,
* along with this program; if not, write to the Free Software * but WITHOUT ANY WARRANTY; without even the implied warranty of
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/ */
#include "chip.h" #include "chip.h"
#include "board.h" #include "board.h"
#include "utils.h" #include "utils.h"
#include "usb_buf.h"
static const Pin pins_cardsim[] = PINS_CARDSIM; static const Pin pins_cardsim[] = PINS_CARDSIM;
void board_exec_dbg_cmd(int ch)
{
switch (ch) {
case '?':
printf("\t?\thelp\n\r");
printf("\tR\treset SAM3\n\r");
break;
case 'R':
printf("Asking NVIC to reset us\n\r");
USBD_Disconnect();
NVIC_SystemReset();
break;
default:
printf("Unknown command '%c'\n\r", ch);
break;
}
}
void board_main_top(void)
{
#ifndef APPLICATION_dfu
usb_buf_init();
#endif
}
void cardsim_set_simpres(uint8_t slot, int present) void cardsim_set_simpres(uint8_t slot, int present)
{ {
if (slot > 1) if (slot > 1)
@@ -36,5 +63,5 @@ void cardsim_set_simpres(uint8_t slot, int present)
void cardsim_gpio_init(void) void cardsim_gpio_init(void)
{ {
PIO_Configure(&pins_cardsim, ARRAY_SIZE(pins_cardsim)); PIO_Configure(pins_cardsim, ARRAY_SIZE(pins_cardsim));
} }

View File

@@ -1,7 +1,24 @@
/* Code to switch between local (physical) and remote (emulated) SIM */ /* Code to switch between local (physical) and remote (emulated) SIM
*
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#include "board.h" #include "board.h"
#include "trace.h" #include "trace.h"
#include "led.h"
#include "sim_switch.h" #include "sim_switch.h"
#ifdef PIN_SIM_SWITCH1 #ifdef PIN_SIM_SWITCH1
@@ -16,6 +33,7 @@ static int initialized = 0;
int sim_switch_use_physical(unsigned int nr, int physical) int sim_switch_use_physical(unsigned int nr, int physical)
{ {
const Pin *pin; const Pin *pin;
enum led led;
if (!initialized) { if (!initialized) {
TRACE_ERROR("Somebody forgot to call sim_switch_init()\r\n"); TRACE_ERROR("Somebody forgot to call sim_switch_init()\r\n");
@@ -29,11 +47,13 @@ int sim_switch_use_physical(unsigned int nr, int physical)
#ifdef PIN_SIM_SWITCH1 #ifdef PIN_SIM_SWITCH1
case 0: case 0:
pin = &pin_conn_usim1; pin = &pin_conn_usim1;
led = LED_USIM1;
break; break;
#endif #endif
#ifdef PIN_SIM_SWITCH2 #ifdef PIN_SIM_SWITCH2
case 1: case 1:
pin = &pin_conn_usim2; pin = &pin_conn_usim2;
led = LED_USIM2;
break; break;
#endif #endif
default: default:
@@ -44,9 +64,11 @@ int sim_switch_use_physical(unsigned int nr, int physical)
if (physical) { if (physical) {
TRACE_INFO("%u: Use local/physical SIM\r\n", nr); TRACE_INFO("%u: Use local/physical SIM\r\n", nr);
PIO_Clear(pin); PIO_Clear(pin);
led_blink(led, BLINK_ALWAYS_ON);
} else { } else {
TRACE_INFO("%u: Use remote/emulated SIM\r\n", nr); TRACE_INFO("%u: Use remote/emulated SIM\r\n", nr);
PIO_Set(pin); PIO_Set(pin);
led_blink(led, BLINK_ALWAYS_OFF);
} }
return 0; return 0;
@@ -63,5 +85,6 @@ int sim_switch_init(void)
PIO_Configure(&pin_conn_usim2, 1); PIO_Configure(&pin_conn_usim2, 1);
num_switch++; num_switch++;
#endif #endif
initialized = 1;
return num_switch; return num_switch;
} }

View File

@@ -1,12 +1,37 @@
/* sysmocom quad-modem sysmoQMOD board definition
*
* (C) 2016-2017 by Harald Welte <hwelte@hmw-consulting.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#pragma once #pragma once
#include "board_common.h" #include "board_common.h"
#include "simtrace_usb.h"
#define LED_USIM1 LED_GREEN
#define LED_USIM2 LED_RED
/** Name of the board */ /** Name of the board */
#define BOARD_NAME "QMOD" #define BOARD_NAME "QMOD"
/** Board definition */ /** Board definition */
#define qmod #define qmod
/** oscillator used as main clock source (in Hz) */
#define BOARD_MAINOSC 12000000 #define BOARD_MAINOSC 12000000
/** desired main clock frequency (in Hz, based on BOARD_MAINOSC) */
#define BOARD_MCK 58000000 // 18.432 * 29 / 6
/* USIM 2 interface (USART) */ /* USIM 2 interface (USART) */
#define PIN_USIM2_CLK {PIO_PA2, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT} #define PIN_USIM2_CLK {PIO_PA2, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
@@ -70,4 +95,7 @@
#define CARDEMU_SECOND_UART #define CARDEMU_SECOND_UART
#define DETECT_VCC_BY_ADC #define DETECT_VCC_BY_ADC
/** sysmoQMOD only supports card emulation */
#ifdef APPLICATION_cardem
#define HAVE_CARDEM #define HAVE_CARDEM
#endif

View File

@@ -1,3 +1,21 @@
/* card presence utilities
*
* (C) 2016-2017 by Harald Welte <hwelte@hmw-consulting.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#pragma once #pragma once
int is_card_present(int port); int is_card_present(int port);

View File

@@ -1,3 +1,19 @@
/* I2C EEPROM memory read and write utilities
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#pragma once #pragma once
void i2c_pin_init(void); void i2c_pin_init(void);

View File

@@ -1,3 +1,19 @@
/* Code to read/track the status of the WWAN LEDs of attached modems
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#pragma once #pragma once
int wwan_led_active(int wwan); int wwan_led_active(int wwan);

View File

@@ -1,3 +1,19 @@
/* Code to control the PERST lines of attached modems
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#pragma once #pragma once
int wwan_perst_set(int modem_nr, int active); int wwan_perst_set(int modem_nr, int active);

View File

@@ -1,15 +1,32 @@
/* Quad-modem speciic application code */ /* sysmocom quad-modem sysmoQMOD application code
/* (C) 2016-2016 by Harald Welte <laforge@gnumonks.org> */ *
* (C) 2016-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#include "board.h" #include "board.h"
#include "simtrace.h" #include "simtrace.h"
#include "utils.h" #include "utils.h"
#include "led.h"
#include "wwan_led.h" #include "wwan_led.h"
#include "wwan_perst.h" #include "wwan_perst.h"
#include "sim_switch.h" #include "sim_switch.h"
#include "boardver_adc.h" #include "boardver_adc.h"
#include "card_pres.h" #include "card_pres.h"
#include "osmocom/core/timer.h" #include <osmocom/core/timer.h>
#include "usb_buf.h" #include "usb_buf.h"
static const Pin pin_hubpwr_override = PIN_PRTPWR_OVERRIDE; static const Pin pin_hubpwr_override = PIN_PRTPWR_OVERRIDE;
@@ -55,8 +72,6 @@ const unsigned char __eeprom_bin[256] = {
#include "i2c.h" #include "i2c.h"
static int write_hub_eeprom(void) static int write_hub_eeprom(void)
{ {
const unsigned int __eeprom_bin_len = 256;
int i; int i;
/* wait */ /* wait */
@@ -64,22 +79,25 @@ static int write_hub_eeprom(void)
TRACE_INFO("Writing EEPROM...\n\r"); TRACE_INFO("Writing EEPROM...\n\r");
/* write the EEPROM once */ /* write the EEPROM once */
for (i = 0; i < 256; i++) { for (i = 0; i < ARRAY_SIZE(__eeprom_bin); i++) {
int rc = eeprom_write_byte(0x50, i, __eeprom_bin[i]); int rc = eeprom_write_byte(0x50, i, __eeprom_bin[i]);
/* if the result was negative, repeat that write */ if (rc < 0) {
if (rc < 0) TRACE_ERROR("Writing EEPROM failed at byte %u: 0x%02x\n\r",
i--; i, __eeprom_bin[i]);
return 1;
}
} }
/* then pursue re-reading it again and again */ /* then pursue re-reading it again and again */
TRACE_INFO("Verifying EEPROM...\n\r"); TRACE_INFO("Verifying EEPROM...\n\r");
for (i = 0; i < 256; i++) { for (i = 0; i < ARRAY_SIZE(__eeprom_bin); i++) {
int byte = eeprom_read_byte(0x50, i); int byte = eeprom_read_byte(0x50, i);
TRACE_INFO("0x%02x: %02x\n\r", i, byte); TRACE_DEBUG("0x%02x: %02x\n\r", i, byte);
if (byte != __eeprom_bin[i]) if (byte != __eeprom_bin[i])
TRACE_ERROR("Byte %u is wrong, expected 0x%02x, found 0x%02x\n\r", TRACE_ERROR("Byte %u is wrong, expected 0x%02x, found 0x%02x\n\r",
i, __eeprom_bin[i], byte); i, __eeprom_bin[i], byte);
} }
TRACE_INFO("EEPROM written\n\r");
/* FIXME: Release PIN_PRTPWR_OVERRIDE after we know the hub is /* FIXME: Release PIN_PRTPWR_OVERRIDE after we know the hub is
* again powering us up */ * again powering us up */
@@ -87,6 +105,29 @@ static int write_hub_eeprom(void)
return 0; return 0;
} }
static int erase_hub_eeprom(void)
{
int i;
/* wait */
mdelay(100);
TRACE_INFO("Erasing EEPROM...\n\r");
/* write the EEPROM once */
for (i = 0; i < 256; i++) {
int rc = eeprom_write_byte(0x50, i, 0xff);
if (rc < 0) {
TRACE_ERROR("Erasing EEPROM failed at byte %u: 0x%02x\n\r",
i, __eeprom_bin[i]);
return 1;
}
}
TRACE_INFO("EEPROM erased\n\r");
return 0;
}
static void board_exec_dbg_cmd_st12only(int ch) static void board_exec_dbg_cmd_st12only(int ch)
{ {
uint32_t addr, val; uint32_t addr, val;
@@ -99,6 +140,9 @@ static void board_exec_dbg_cmd_st12only(int ch)
case 'E': case 'E':
write_hub_eeprom(); write_hub_eeprom();
break; break;
case 'e':
erase_hub_eeprom();
break;
case 'O': case 'O':
printf("Setting PRTPWR_OVERRIDE\n\r"); printf("Setting PRTPWR_OVERRIDE\n\r");
PIO_Set(&pin_hubpwr_override); PIO_Set(&pin_hubpwr_override);
@@ -123,13 +167,13 @@ static void board_exec_dbg_cmd_st12only(int ch)
UART_GetIntegerMinMax(&addr, 0, 255); UART_GetIntegerMinMax(&addr, 0, 255);
printf("Please enter EEPROM value:\n\r"); printf("Please enter EEPROM value:\n\r");
UART_GetIntegerMinMax(&val, 0, 255); UART_GetIntegerMinMax(&val, 0, 255);
printf("Writing value 0x%02x to EEPROM offset 0x%02x\n\r", val, addr); printf("Writing value 0x%02lx to EEPROM offset 0x%02lx\n\r", val, addr);
eeprom_write_byte(0x50, addr, val); eeprom_write_byte(0x50, addr, val);
break; break;
case 'r': case 'r':
printf("Please enter EEPROM offset:\n\r"); printf("Please enter EEPROM offset:\n\r");
UART_GetIntegerMinMax(&addr, 0, 255); UART_GetIntegerMinMax(&addr, 0, 255);
printf("EEPROM[0x%02x] = 0x%02x\n\r", addr, eeprom_read_byte(0x50, addr)); printf("EEPROM[0x%02lx] = 0x%02x\n\r", addr, eeprom_read_byte(0x50, addr));
break; break;
default: default:
printf("Unknown command '%c'\n\r", ch); printf("Unknown command '%c'\n\r", ch);
@@ -144,8 +188,13 @@ void board_exec_dbg_cmd(int ch)
case '?': case '?':
printf("\t?\thelp\n\r"); printf("\t?\thelp\n\r");
printf("\tR\treset SAM3\n\r"); printf("\tR\treset SAM3\n\r");
printf("\tl\tswitch off LED 1\n\r");
printf("\tL\tswitch off LED 1\n\r");
printf("\tg\tswitch off LED 2\n\r");
printf("\tG\tswitch off LED 2\n\r");
if (qmod_sam3_is_12()) { if (qmod_sam3_is_12()) {
printf("\tE\tprogram EEPROM\n\r"); printf("\tE\tprogram EEPROM\n\r");
printf("\te\tErase EEPROM\n\r");
printf("\tO\tEnable PRTPWR_OVERRIDE\n\r"); printf("\tO\tEnable PRTPWR_OVERRIDE\n\r");
printf("\to\tDisable PRTPWR_OVERRIDE\n\r"); printf("\to\tDisable PRTPWR_OVERRIDE\n\r");
printf("\tH\tRelease HUB RESET (high)\n\r"); printf("\tH\tRelease HUB RESET (high)\n\r");
@@ -166,6 +215,22 @@ void board_exec_dbg_cmd(int ch)
USBD_Disconnect(); USBD_Disconnect();
NVIC_SystemReset(); NVIC_SystemReset();
break; break;
case 'l':
led_blink(LED_GREEN, BLINK_ALWAYS_OFF);
printf("LED 1 switched off\n\r");
break;
case 'L':
led_blink(LED_GREEN, BLINK_ALWAYS_ON);
printf("LED 1 switched on\n\r");
break;
case 'g':
led_blink(LED_RED, BLINK_ALWAYS_OFF);
printf("LED 2 switched off\n\r");
break;
case 'G':
led_blink(LED_RED, BLINK_ALWAYS_ON);
printf("LED 2 switched on\n\r");
break;
case 'X': case 'X':
printf("Clearing _SIMTRACExx_RST -> SIMTRACExx_RST high (inactive)\n\r"); printf("Clearing _SIMTRACExx_RST -> SIMTRACExx_RST high (inactive)\n\r");
PIO_Clear(&pin_peer_rst); PIO_Clear(&pin_peer_rst);
@@ -249,3 +314,51 @@ void board_main_top(void)
card_present_init(); card_present_init();
#endif #endif
} }
static int uart_has_loopback_jumper(void)
{
unsigned int i;
const Pin uart_loopback_pins[] = {
{PIO_PA9A_URXD0, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT},
{PIO_PA10A_UTXD0, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
};
/* Configure UART pins as I/O */
PIO_Configure(uart_loopback_pins, PIO_LISTSIZE(uart_loopback_pins));
/* Send pattern over UART TX and check if it is received on RX
* If the loop doesn't get interrupted, RxD always follows TxD and thus a
* loopback jumper has been placed on RxD/TxD, and we will boot
* into DFU unconditionally
*/
int has_loopback_jumper = 1;
for (i = 0; i < 10; i++) {
/* Set TxD high; abort if RxD doesn't go high either */
PIO_Set(&uart_loopback_pins[1]);
if (!PIO_Get(&uart_loopback_pins[0])) {
has_loopback_jumper = 0;
break;
}
/* Set TxD low, abort if RxD doesn't go low either */
PIO_Clear(&uart_loopback_pins[1]);
if (PIO_Get(&uart_loopback_pins[0])) {
has_loopback_jumper = 0;
break;
}
}
/* Put pins back to UART mode */
const Pin uart_pins[] = {PINS_UART};
PIO_Configure(uart_pins, PIO_LISTSIZE(uart_pins));
return has_loopback_jumper;
}
int board_override_enter_dfu(void)
{
/* If the loopback jumper is set, we enter DFU mode */
if (uart_has_loopback_jumper())
return 1;
return 0;
}

View File

@@ -1,3 +1,21 @@
/* card presence utilities
*
* (C) 2016-2017 by Harald Welte <hwelte@hmw-consulting.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#include <osmocom/core/timer.h> #include <osmocom/core/timer.h>
#include "board.h" #include "board.h"
#include "utils.h" #include "utils.h"
@@ -17,9 +35,9 @@ int is_card_present(int port)
const Pin *pin; const Pin *pin;
int present; int present;
if (port < 1 || port > NUM_CARDPRES) if (port < 0 || port >= NUM_CARDPRES)
return -1; return -1;
pin = &pin_cardpres[port-1]; pin = &pin_cardpres[port];
/* Card present signals are low-active, as we have a switch /* Card present signals are low-active, as we have a switch
* against GND and an internal-pull-up in the SAM3 */ * against GND and an internal-pull-up in the SAM3 */
@@ -32,12 +50,12 @@ static void cardpres_tmr_cb(void *data)
{ {
unsigned int i; unsigned int i;
for (i = 1; i <= ARRAY_SIZE(pin_cardpres); i++) { for (i = 0; i < ARRAY_SIZE(pin_cardpres); i++) {
int state = is_card_present(i); int state = is_card_present(i);
if (state != last_state[i-1]) { if (state != last_state[i]) {
TRACE_INFO("Card Detect %d Status %d -> %d\r\n", i, last_state[i], state); TRACE_INFO("%u: Card Detect Status %d -> %d\r\n", i, last_state[i], state);
/* FIXME: report to USB host */ /* FIXME: report to USB host */
last_state[i-1] = state; last_state[i] = state;
} }
} }

View File

@@ -1,3 +1,19 @@
/* I2C EEPROM memory read and write utilities
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#include "board.h" #include "board.h"
#include <stdbool.h> #include <stdbool.h>
@@ -169,6 +185,8 @@ int eeprom_write_byte(uint8_t slave, uint8_t addr, uint8_t byte)
nack = i2c_write_byte(false, true, byte); nack = i2c_write_byte(false, true, byte);
if (nack) if (nack)
goto out_stop; goto out_stop;
/* Wait tWR time to ensure EEPROM is writing correctly (tWR = 5 ms for AT24C02) */
mdelay(5);
out_stop: out_stop:
i2c_stop_cond(); i2c_stop_cond();

View File

@@ -0,0 +1,90 @@
/* Code to switch between local (physical) and remote (emulated) SIM
*
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#include "board.h"
#include "trace.h"
#include "led.h"
#include "sim_switch.h"
#ifdef PIN_SIM_SWITCH1
static const Pin pin_conn_usim1 = {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT};
#endif
#ifdef PIN_SIM_SWITCH2
static const Pin pin_conn_usim2 = {PIO_PA28, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT};
#endif
static int initialized = 0;
int sim_switch_use_physical(unsigned int nr, int physical)
{
const Pin *pin;
enum led led;
if (!initialized) {
TRACE_ERROR("Somebody forgot to call sim_switch_init()\r\n");
sim_switch_init();
}
TRACE_INFO("Modem %d: %s SIM\n\r", nr,
physical ? "physical" : "virtual");
switch (nr) {
#ifdef PIN_SIM_SWITCH1
case 0:
pin = &pin_conn_usim1;
led = LED_USIM1;
break;
#endif
#ifdef PIN_SIM_SWITCH2
case 1:
pin = &pin_conn_usim2;
led = LED_USIM2;
break;
#endif
default:
TRACE_ERROR("Invalid SIM%u\n\r", nr);
return -1;
}
if (physical) {
TRACE_INFO("%u: Use local/physical SIM\r\n", nr);
PIO_Clear(pin);
led_blink(led, BLINK_ALWAYS_ON);
} else {
TRACE_INFO("%u: Use remote/emulated SIM\r\n", nr);
PIO_Set(pin);
led_blink(led, BLINK_ALWAYS_OFF);
}
return 0;
}
int sim_switch_init(void)
{
int num_switch = 0;
#ifdef PIN_SIM_SWITCH1
PIO_Configure(&pin_conn_usim1, 1);
num_switch++;
#endif
#ifdef PIN_SIM_SWITCH2
PIO_Configure(&pin_conn_usim2, 1);
num_switch++;
#endif
initialized = 1;
return num_switch;
}

View File

@@ -1,11 +1,24 @@
/* Code to read/track the status of the WWAN LEDs of attached modems /* Code to read/track the status of the WWAN LEDs of attached modems
* *
* Depending on the board this is running on, it might be possible * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
/* Depending on the board this is running on, it might be possible
* for the controller to read the status of the WWAN LED output lines of * for the controller to read the status of the WWAN LED output lines of
* the cellular modem. If the board supports this, it sets the * the cellular modem. If the board supports this, it sets the
* PIN_WWAN1 and/or PIN_WWAN2 defines in its board.h file. * PIN_WWAN1 and/or PIN_WWAN2 defines in its board.h file.
*/ */
#include "board.h" #include "board.h"
#include "wwan_led.h" #include "wwan_led.h"
@@ -14,9 +27,9 @@ static const Pin pin_wwan1 = PIN_WWAN1;
static void wwan1_irqhandler(const Pin *pPin) static void wwan1_irqhandler(const Pin *pPin)
{ {
int active = wwan_led_active(1); int active = wwan_led_active(0);
TRACE_INFO("WWAN1 LED %u\r\n", active); TRACE_INFO("0: WWAN LED %u\r\n", active);
/* TODO: notify host via USB */ /* TODO: notify host via USB */
} }
@@ -27,8 +40,8 @@ static const Pin pin_wwan2 = PIN_WWAN2;
static void wwan2_irqhandler(const Pin *pPin) static void wwan2_irqhandler(const Pin *pPin)
{ {
int active = wwan_led_active(2); int active = wwan_led_active(1);
TRACE_INFO("WWAN2 LED %u\r\n", active); TRACE_INFO("1: WWAN LED %u\r\n", active);
/* TODO: notify host via USB */ /* TODO: notify host via USB */
} }
@@ -42,12 +55,12 @@ int wwan_led_active(int wwan)
switch (wwan) { switch (wwan) {
#ifdef PIN_WWAN1 #ifdef PIN_WWAN1
case 1: case 0:
pin = &pin_wwan1; pin = &pin_wwan1;
break; break;
#endif #endif
#ifdef PIN_WWAN2 #ifdef PIN_WWAN2
case 2: case 1:
pin = &pin_wwan2; pin = &pin_wwan2;
break; break;
#endif #endif

View File

@@ -1,29 +1,45 @@
/* Code to control the PERST lines of attached modems /* Code to control the PERST lines of attached modems
* *
* Depending on the board this is running on, it might be possible * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
/* Depending on the board this is running on, it might be possible
* for the controller to set the status of the PERST input line of * for the controller to set the status of the PERST input line of
* the cellular modem. If the board supports this, it sets the * the cellular modem. If the board supports this, it sets the
* PIN_PERST1 and/or PIN_PERST2 defines in its board.h file. * PIN_PERST1 and/or PIN_PERST2 defines in its board.h file.
*/ */
#include "board.h" #include "board.h"
#include "trace.h" #include "trace.h"
#include "wwan_perst.h" #include "wwan_perst.h"
#include "osmocom/core/timer.h" #include <osmocom/core/timer.h>
struct wwan_perst { struct wwan_perst {
uint8_t idx;
const Pin pin; const Pin pin;
struct osmo_timer_list timer; struct osmo_timer_list timer;
}; };
#ifdef PIN_PERST1 #ifdef PIN_PERST1
static struct wwan_perst perst1 = { static struct wwan_perst perst1 = {
.idx = 0,
.pin = PIN_PERST1, .pin = PIN_PERST1,
}; };
#endif #endif
#ifdef PIN_PERST2 #ifdef PIN_PERST2
static struct wwan_perst perst2 = { static struct wwan_perst perst2 = {
.idx = 1,
.pin = PIN_PERST2, .pin = PIN_PERST2,
}; };
#endif #endif
@@ -34,7 +50,7 @@ static void perst_tmr_cb(void *data)
{ {
struct wwan_perst *perst = data; struct wwan_perst *perst = data;
/* release the (low-active) reset */ /* release the (low-active) reset */
TRACE_INFO("De-asserting modem reset\r\n"); TRACE_INFO("%u: De-asserting modem reset\r\n", perst->idx);
PIO_Clear(&perst->pin); PIO_Clear(&perst->pin);
} }
@@ -106,5 +122,6 @@ int wwan_perst_init(void)
perst2.timer.data = (void *) &perst2; perst2.timer.data = (void *) &perst2;
num_perst++; num_perst++;
#endif #endif
initialized = 1;
return num_perst; return num_perst;
} }

View File

@@ -1,87 +1,163 @@
/* SIMtrace with SAM3S board definition
*
* (C) 2016-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#pragma once #pragma once
#include "board_common.h" #include "board_common.h"
#include "simtrace_usb.h"
/** Name of the board */ /* Name of the board */
#define BOARD_NAME "SAM3S-SIMTRACE" #define BOARD_NAME "SAM3S-SIMTRACE"
/** Board definition */ /* Board definition */
#define simtrace #define simtrace
/** oscillator used as main clock source (in Hz) */
#define BOARD_MAINOSC 18432000 #define BOARD_MAINOSC 18432000
/** desired main clock frequency (in Hz, based on BOARD_MAINOSC) */
#define BOARD_MCK 58982400 // 18.432 * 16 / 5
/** Phone (SIM card emulator)/CCID Reader/MITM configuration **/ /** Pin configuration **/
/* Normally the communication lines between phone and SIM card are disconnected */ /* Button to force bootloader start (shorted to ground when pressed */
// Disconnect SIM card I/O, VPP line from the phone lines #define PIN_BOOTLOADER_SW {PIO_PA31, PIOA, ID_PIOA, PIO_INPUT, PIO_PULLUP}
// FIXME: Per default pins are input, therefore high-impedance, therefore they don not activate the bus switch, right? /* Enable powering the card using the second 3.3 V output of the LDO (active high) */
#define PIN_SC_SW_DEFAULT {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} #define SIM_PWEN_PIN {SIM_PWEN, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
// Disconnect SIM card RST, CLK line from the phone lines /* Enable powering the SIM card */
#define PIN_IO_SW_DEFAULT {PIO_PA19, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} #define PWR_PINS SIM_PWEN_PIN
#define PINS_BUS_DEFAULT PIN_SC_SW_DEFAULT, PIN_IO_SW_DEFAULT /* Card presence pin */
#define SW_SIM PIO_PA8
/* Pull card presence pin high (shorted to ground in card slot when card is present) */
#define SMARTCARD_CONNECT_PIN {SW_SIM, PIOA, ID_PIOA, PIO_INPUT, PIO_PULLUP | PIO_DEBOUNCE | PIO_DEGLITCH | PIO_IT_EDGE }
/** Smart card connection **/
/* Card RST reset signal input (active low; RST_SIM in schematic) */
#define PIN_SIM_RST {PIO_PA7, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
/* Card I/O data signal input/output (I/O_SIM in schematic) */
#define PIN_SIM_IO {PIO_PA6A_TXD0, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
/* Card CLK clock input (CLK_SIM in schematic) */
#define PIN_SIM_CLK {PIO_PA2B_SCK0, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
/* Pin to measure card I/O timing (to start measuring the ETU on I/O activity; connected I/O_SIM in schematic) */
#define PIN_SIM_IO_INPUT {PIO_PA1B_TIOB0, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
/* Pin used as clock input (to measure the ETU duration; connected to CLK_SIM in schematic) */
#define PIN_SIM_CLK_INPUT {PIO_PA4B_TCLK0, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
/* Pins used to measure ETU timing (using timer counter) */
#define PINS_TC PIN_SIM_IO_INPUT, PIN_SIM_CLK_INPUT
/** Phone connection **/
/* Phone USIM slot 1 VCC pin (VCC_PHONE in schematic) */
#define PIN_USIM1_VCC {PIO_PA25, PIOA, ID_PIOA, PIO_INPUT, PIO_IT_EDGE | PIO_DEGLITCH }
/* Phone USIM slot 1 RST pin (active low; RST_PHONE in schematic) */
#define PIN_USIM1_nRST {PIO_PA24, PIOA, ID_PIOA, PIO_INPUT, PIO_IT_EDGE | PIO_DEGLITCH }
/* Phone I/O data signal input/output (I/O_PHONE in schematic) */
#define PIN_USIM1_IO {PIO_PA22A_TXD1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
/* Phone CLK clock input (CLK_PHONE in schematic) */
#define PIN_PHONE_CLK {PIO_PA23A_SCK1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
/* Pin used for phone USIM slot 1 communication */
#define PINS_USIM1 PIN_USIM1_IO, PIN_PHONE_CLK, PIN_PHONE_CLK_INPUT, PIN_USIM1_VCC, PIN_PHONE_IO_INPUT, PIN_USIM1_nRST
/* Phone I/O data signal input/output (unused USART RX input; connected to I/O_PHONE in schematic) */
#define PIN_PHONE_IO_INPUT {PIO_PA21A_RXD1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
/* Pin used as clock input (to measure the ETU duration; connected to CLK_PHONE in schematic) */
#define PIN_PHONE_CLK_INPUT {PIO_PA29B_TCLK2, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
/** Default pin configuration **/
/* Disconnect VPP, CLK, and RST lines between card and phone using bus switch (high sets bus switch to high-impedance) */
#define PIN_SC_SW_DEFAULT {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
/* Disconnect I/O line between card and phone using bus switch (high sets bus switch to high-impedance) */
#define PIN_IO_SW_DEFAULT {PIO_PA19, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
/* Disconnect all lines (VPP, CLK, RST, and I/O) between card and phone */
#define PINS_BUS_DEFAULT PIN_SC_SW_DEFAULT, PIN_IO_SW_DEFAULT
/** Sniffer configuration **/ /** Sniffer configuration **/
// Connect VPP, CLK and RST lines from smartcard to the phone /* Connect VPP, CLK, and RST lines between card and phone using bus switch (low connects signals on bus switch) */
#define PIN_SC_SW_SNIFF {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} #define PIN_SC_SW_SNIFF {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
/* Connect I/O line between card and phone using bus switch (low connects signals on bus switch) */
#define PIN_IO_SW_SNIFF {PIO_PA19, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT} #define PIN_IO_SW_SNIFF {PIO_PA19, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
/* Connect all lines (VPP, CLK, RST, and I/O) between card and phone */
#define PINS_BUS_SNIFF PIN_SC_SW_SNIFF, PIN_IO_SW_SNIFF #define PINS_BUS_SNIFF PIN_SC_SW_SNIFF, PIN_IO_SW_SNIFF
/* Card RST reset signal input (use as input since the phone will drive it) */
#define PIN_SIM_RST_SNIFF {PIO_PA7, PIOA, ID_PIOA, PIO_INPUT, PIO_DEGLITCH | PIO_IT_EDGE}
/* Pins used to sniff phone-card communication */
#define PINS_SIM_SNIFF PIN_SIM_IO, PIN_SIM_CLK, PIN_SIM_RST_SNIFF
/* Disable power converter 4.5-6V to 3.3V (active high) */
#define PIN_SIM_PWEN_SNIFF {SIM_PWEN, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
/* Enable power switch to forward VCC_PHONE to VCC_SIM (active high) */
#define PIN_VCC_FWD_SNIFF {VCC_FWD, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
/* Use phone VCC to power card */
#define PINS_PWR_SNIFF PIN_SIM_PWEN_SNIFF, PIN_VCC_FWD_SNIFF
#define PINS_SIM_SNIFF_SIM PIN_PHONE_IO, PIN_PHONE_CLK /** CCID configuration */
/* Card RST reset signal input (active low; RST_SIM in schematic) */
#define PIN_ISO7816_RSTMC {PIO_PA7, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
/* ISO7816-communication related pins */
#define PINS_ISO7816 PIN_SIM_IO, PIN_SIM_CLK, PIN_ISO7816_RSTMC // SIM_PWEN_PIN, PIN_SIM_IO2, PIN_SIM_CLK2
#define SIM_PWEN_PIN {PIO_PA5, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} /** card emulation configuration */
/* Disable power converter 4.5-6V to 3.3V (active high) */
#define PIN_SIM_PWEN_CARDEMU {SIM_PWEN, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
/* Disable power switch to forward VCC_PHONE to VCC_SIM (active high) */
#define PIN_VCC_FWD_CARDEMU {VCC_FWD, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
/* Disable power to SIM */
#define PINS_PWR_CARDEMU PIN_SIM_PWEN_CARDEMU, PIN_VCC_FWD_CARDEMU
#define PWR_PINS \ /** External SPI flash interface **/
/* Enable power converter 4.5-6V to 3.3V; low: off */ \ /* SPI MISO pin definition */
{SIM_PWEN, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}, \ #define PIN_SPI_MISO {PIO_PA12A_MISO, PIOA, PIOA, PIO_PERIPH_A, PIO_PULLUP}
/* Enable second power converter: VCC_PHONE to VCC_SIM; high: on */ \ /* SPI MOSI pin definition */
{VCC_FWD, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} #define PIN_SPI_MOSI {PIO_PA13A_MOSI, PIOA, PIOA, PIO_PERIPH_A, PIO_DEFAULT}
/* SPI SCK pin definition */
#define PIN_SPI_SCK {PIO_PA14A_SPCK, PIOA, PIOA, PIO_PERIPH_A, PIO_DEFAULT}
/* SPI pins definition. Contains MISO, MOSI & SCK */
#define PINS_SPI PIN_SPI_MISO, PIN_SPI_MOSI, PIN_SPI_SCK
/* SPI chip select 0 pin definition */
#define PIN_SPI_NPCS0 {PIO_PA11A_NPCS0, PIOA, PIOA, PIO_PERIPH_A, PIO_DEFAULT}
/* SPI flash write protect pin (active low, pulled low) */
#define PIN_SPI_WP {PA15, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
#define SW_SIM PIO_PA8 /** Pin configuration to control USB pull-up on D+
#define SMARTCARD_CONNECT_PIN {SW_SIM, PIOA, ID_PIOA, PIO_INPUT, PIO_PULLUP | PIO_DEBOUNCE | PIO_DEGLITCH | PIO_IT_EDGE } * @details the USB pull-up on D+ is enable by default on the board but can be disabled by setting PA16 high
//#define SMARTCARD_CONNECT_PIN {SW_SIM, PIOB, ID_PIOB, PIO_INPUT, PIO_PULLUP | PIO_DEBOUNCE | PIO_IT_EDGE} */
#define PIN_USB_PULLUP {PIO_PA16, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
/// PIN used for resetting the smartcard
// FIXME: Card is resetted with pin set to 0 --> PIO_OUTPUT_1 as default is right?
#define PIN_ISO7816_RSTMC {PIO_PA7, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
/// Pins used for connect the smartcard
#define PIN_SIM_IO_INPUT {PIO_PA1, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT}
#define PIN_SIM_IO {PIO_PA6, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
#define PIN_SIM_CLK {PIO_PA2, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
#define PIN_SIM_CLK_INPUT {PIO_PA4, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT}
//#define PINS_ISO7816 PIN_USART1_TXD, PIN_USART1_SCK, PIN_ISO7816_RSTMC
#define PINS_ISO7816 PIN_SIM_IO, PIN_SIM_CLK, PIN_ISO7816_RSTMC // SIM_PWEN_PIN, PIN_SIM_IO2, PIN_SIM_CLK2
#define PINS_TC PIN_SIM_IO_INPUT, PIN_SIM_CLK_INPUT
#define VCC_PHONE {PIO_PA25, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT}
#define PIN_ISO7816_RST_PHONE {PIO_PA24, PIOA, ID_PIOA, PIO_INPUT, PIO_IT_RISE_EDGE | PIO_DEGLITCH }
#define PIN_PHONE_IO_INPUT {PIO_PA21, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT}
#define PIN_PHONE_IO {PIO_PA22, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT}
#define PIN_PHONE_CLK {PIO_PA23A_SCK1, PIOA, ID_PIOA, PIO_PERIPH_A, PIO_DEFAULT} // External Clock Input on PA28
//#define PIN_PHONE_CLK {PIO_PA23A_SCK1, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT} // External Clock Input on PA28
#define PIN_PHONE_CLK_INPUT {PIO_PA29, PIOA, ID_PIOA, PIO_INPUT, PIO_DEFAULT}
#define PINS_ISO7816_PHONE PIN_PHONE_IO, PIN_PHONE_CLK, PIN_PHONE_CLK_INPUT, VCC_PHONE, PIN_PHONE_IO_INPUT, PIN_ISO7816_RST_PHONE
//, VCC_PHONE
//** SPI interface **/
/// SPI MISO pin definition (PA12).
#define PIN_SPI_MISO {1 << 12, PIOA, PIOA, PIO_PERIPH_A, PIO_PULLUP}
/// SPI MOSI pin definition (PA13).
#define PIN_SPI_MOSI {1 << 13, PIOA, PIOA, PIO_PERIPH_A, PIO_DEFAULT}
/// SPI SPCK pin definition (PA14).
#define PIN_SPI_SPCK {1 << 14, PIOA, PIOA, PIO_PERIPH_A, PIO_DEFAULT}
/// SPI pins definition. Contains MISO, MOSI & SPCK (PA12, PA13 & PA14).
#define PINS_SPI PIN_SPI_MISO, PIN_SPI_MOSI, PIN_SPI_SPCK
/// SPI chip select 0 pin definition (PA11).
#define PIN_SPI_NPCS0 {1 << 11, PIOA, PIOA, PIO_PERIPH_A, PIO_DEFAULT}
/** USB definitions */
/* OpenMoko SIMtrace 2 USB vendor ID */
#define BOARD_USB_VENDOR_ID USB_VENDOR_OPENMOKO
/* OpenMoko SIMtrace 2 USB product ID (main application/runtime mode) */
#define BOARD_USB_PRODUCT_ID USB_PRODUCT_SIMTRACE2
/* OpenMoko SIMtrace 2 DFU USB product ID (DFU bootloader/DFU mode) */
#define BOARD_DFU_USB_PRODUCT_ID USB_PRODUCT_SIMTRACE2_DFU
/* USB release number (bcdDevice, shown as 0.00) */
#define BOARD_USB_RELEASE 0x000
/* Indicate SIMtrace is bus power in USB attributes */
#define BOARD_USB_BMATTRIBUTES USBConfigurationDescriptor_BUSPOWERED_NORWAKEUP #define BOARD_USB_BMATTRIBUTES USBConfigurationDescriptor_BUSPOWERED_NORWAKEUP
#define BOARD_USB_VENDOR_ID USB_VENDOR_OPENMOKO /** Supported modes */
#define BOARD_USB_PRODUCT_ID USB_PRODUCT_SIMTRACE2 /* SIMtrace board supports sniffer mode */
#define BOARD_DFU_USB_PRODUCT_ID USB_PRODUCT_SIMTRACE2_DFU #ifdef APPLICATION_trace
#define BOARD_USB_RELEASE 0x000
#define HAVE_SNIFFER #define HAVE_SNIFFER
#define HAVE_CCID #endif
/* SIMtrace board supports CCID mode */
#ifdef APPLICATION_ccid
//#define HAVE_CCID
#endif
/* SIMtrace board supports card emulation mode */
#ifdef APPLICATION_cardem
#define HAVE_CARDEM #define HAVE_CARDEM
#define HAVE_MITM #endif
/* SIMtrace board supports man-in-the-middle mode */
#ifdef APPLICATION_mitm
//#define HAVE_MITM
#endif

View File

@@ -0,0 +1,68 @@
/* SIMtrace with SAM3S specific application code
*
* (C) 2017 by Harald Welte <laforge@gnumonks.org>
* (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#include "board.h"
#include "simtrace.h"
#include "utils.h"
#include "sim_switch.h"
#include <osmocom/core/timer.h>
#include "usb_buf.h"
void board_exec_dbg_cmd(int ch)
{
switch (ch) {
case '?':
printf("\t?\thelp\n\r");
printf("\tR\treset SAM3\n\r");
break;
case 'R':
printf("Asking NVIC to reset us\n\r");
USBD_Disconnect();
NVIC_SystemReset();
break;
default:
printf("Unknown command '%c'\n\r", ch);
break;
}
}
void board_main_top(void)
{
#ifndef APPLICATION_dfu
usb_buf_init();
/* Initialize checking for card insert/remove events */
//card_present_init();
#endif
}
int board_override_enter_dfu(void)
{
const Pin bl_sw_pin = PIN_BOOTLOADER_SW;
PIO_Configure(&bl_sw_pin, 1);
/* Enter DFU bootloader in case the respective button is pressed */
if (PIO_Get(&bl_sw_pin) == 0) {
/* do not print to early since the console is not initialized yet */
//printf("BOOTLOADER switch pressed -> Force DFU\n\r");
return 1;
} else
return 0;
}

View File

@@ -0,0 +1,63 @@
/* Code to switch between local (physical) and remote (emulated) SIM
*
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#include "board.h"
#include "trace.h"
#include "led.h"
#include "sim_switch.h"
#ifdef PIN_SIM_SWITCH1
static const Pin pin_conn_usim1 = {PIO_PA20, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT};
#endif
#ifdef PIN_SIM_SWITCH2
static const Pin pin_conn_usim2 = {PIO_PA28, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT};
#endif
static int initialized = 0;
int sim_switch_use_physical(unsigned int nr, int physical)
{
const Pin pin_sc = PIN_SC_SW_DEFAULT; // pin to control bus switch for VCC/RST/CLK signals
const Pin pin_io = PIN_IO_SW_DEFAULT; // pin to control bus switch for I/O signal
if (nr > 0) {
TRACE_ERROR("SIM interface for Modem %d can't be switched\r\n", nr);
return -1;
}
TRACE_INFO("Modem %u: %s SIM\n\r", nr, physical ? "physical" : "virtual");
if (physical) {
TRACE_INFO("%u: Use local/physical SIM\r\n", nr);
PIO_Set(&pin_sc);
PIO_Set(&pin_io);
} else {
TRACE_INFO("%u: Use remote/emulated SIM\r\n", nr);
PIO_Clear(&pin_sc);
PIO_Clear(&pin_io);
}
return 0;
}
int sim_switch_init(void)
{
// the bus switch is already initialised
return 1; // SIMtrace hardware has only one switchable interface
}

View File

@@ -65,41 +65,41 @@
// Definitions // Definitions
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#if defined(NOASSERT) #if defined(NOASSERT)
#define ASSERT(...) #define ASSERT(...)
#define SANITY_CHECK(...) #define SANITY_CHECK(...)
#else #else
#if (TRACE_LEVEL == 0) #if (TRACE_LEVEL == 0)
/// Checks that the given condition is true, /// Checks that the given condition is true,
/// otherwise stops the program execution. /// otherwise stops the program execution.
/// \param condition Condition to verify. /// \param condition Condition to verify.
#define ASSERT(condition) { \ #define ASSERT(condition) { \
if (!(condition)) { \ if (!(condition)) { \
while (1); \ while (1); \
} \ } \
} }
/// Performs the same duty as the ASSERT() macro /// Performs the same duty as the ASSERT() macro
/// \param condition Condition to verify. /// \param condition Condition to verify.
#define SANITY_CHECK(condition) ASSERT(condition, ...) #define SANITY_CHECK(condition) ASSERT(condition, ...)
#else #else
/// Checks that the given condition is true, otherwise displays an error /// Checks that the given condition is true, otherwise displays an error
/// message and stops the program execution. /// message and stops the program execution.
/// \param condition Condition to verify. /// \param condition Condition to verify.
#define ASSERT(condition) { \ #define ASSERT(condition) { \
if (!(condition)) { \ if (!(condition)) { \
printf("-F- ASSERT: %s %s:%d\n\r", #condition, __BASE_FILE__, __LINE__); \ printf("-F- ASSERT: %s %s:%d\n\r", #condition, __BASE_FILE__, __LINE__); \
while (1); \ while (1); \
} \ } \
} }
#define SANITY_ERROR "Sanity check failed at %s:%d\n\r" #define SANITY_ERROR "Sanity check failed at %s:%d\n\r"
/// Performs the same duty as the ASSERT() macro, except a default error /// Performs the same duty as the ASSERT() macro, except a default error
/// message is output if the condition is false. /// message is output if the condition is false.
/// \param condition Condition to verify. /// \param condition Condition to verify.
#define SANITY_CHECK(condition) ASSERT(condition, SANITY_ERROR, __FILE__, __LINE__) #define SANITY_CHECK(condition) ASSERT(condition, SANITY_ERROR, __FILE__, __LINE__)
#endif #endif
#endif #endif

View File

@@ -1,3 +1,22 @@
/* ISO7816-3 state machine for the card side
*
* (C) 2010-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
@@ -29,10 +48,42 @@ struct llist_head *card_emu_get_uart_tx_queue(struct card_handle *ch);
void card_emu_have_new_uart_tx(struct card_handle *ch); void card_emu_have_new_uart_tx(struct card_handle *ch);
void card_emu_report_status(struct card_handle *ch); void card_emu_report_status(struct card_handle *ch);
/*! call when the waiting time has half-expired
* param[in] ch card for which the waiting time half expired
*/
void card_emu_wt_halfed(struct card_handle *ch);
/*! call when the waiting time has expired
* param[in] ch card for which the waiting time expired
*/
void card_emu_wt_expired(struct card_handle *ch);
#define ENABLE_TX 0x01 #define ENABLE_TX 0x01
#define ENABLE_RX 0x02 #define ENABLE_RX 0x02
int card_emu_uart_update_fidi(uint8_t uart_chan, unsigned int fidi); // the following functions are callbacks implement in mode_cardemu.c
/*! update F and D on USART peripheral
* @param[in] usart USART peripheral to configure
* @param[in] f clock rate conversion integer F value
* @param[in] d baud rate adjustment factor D value
* @note this should happen after reset and protocol select (through PPS or implicit)
*/
void card_emu_uart_update_fd(uint8_t uart_chan, uint16_t f, uint8_t d);
/*! update WT on USART peripheral
* @param[in] usart USART peripheral to configure
* @param[in] wt inactivity Waiting Time before card_emu_wt_expired is called (0 to disable)
*/
void card_emu_uart_update_wt(uint8_t uart_chan, uint32_t wt);
/*! reset waiting timeout count down on USART peripheral
* @param[in] usart USART peripheral to configure
*/
void card_emu_uart_reset_wt(uint8_t uart_chan);
/*! set I/O line high
* @param[in] usart USART peripheral to configure
* @param[in] set if I/O line should be set high (true), or cleared low (false)
*/
void card_emu_uart_io_set(uint8_t uart_chan, bool set);
int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte); int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte);
void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx); void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx);
void card_emu_uart_wait_tx_idle(uint8_t uart_chan); void card_emu_uart_wait_tx_idle(uint8_t uart_chan);
void card_emu_uart_interrupt(uint8_t uart_chan);

View File

@@ -145,129 +145,129 @@ typedef struct
/// 6.1.11.2 PIN Verification Data Structure /// 6.1.11.2 PIN Verification Data Structure
typedef struct typedef struct
{ {
/// Number of seconds. /// Number of seconds.
unsigned char bTimerOut; unsigned char bTimerOut;
/// Several parameters for the PIN format options /// Several parameters for the PIN format options
unsigned char bmFormatString; unsigned char bmFormatString;
/// Define the length of the PIN to present in the APDU command /// Define the length of the PIN to present in the APDU command
unsigned char bmPINBlockString; unsigned char bmPINBlockString;
/// Allows the length PIN insertion in the APDU command /// Allows the length PIN insertion in the APDU command
unsigned char bmPINLengthFormat; unsigned char bmPINLengthFormat;
/// Minimum PIN size in digit and Maximum PIN size in digit /// Minimum PIN size in digit and Maximum PIN size in digit
unsigned char wPINMaxExtraDigit; unsigned char wPINMaxExtraDigit;
/// The value is a bit wise OR operation. /// The value is a bit wise OR operation.
unsigned char bEntryValidationCondition; unsigned char bEntryValidationCondition;
/// Number of messages to display for the PIN modify command /// Number of messages to display for the PIN modify command
unsigned char bNumberMessage; unsigned char bNumberMessage;
/// Language used to display the messages. /// Language used to display the messages.
unsigned char wLangId; unsigned char wLangId;
/// Message index in the Reader message table /// Message index in the Reader message table
unsigned char bMsgIndex; unsigned char bMsgIndex;
/// T=1 I-block prologue field to use /// T=1 I-block prologue field to use
unsigned char bTeoPrologue[3]; unsigned char bTeoPrologue[3];
/// APDU to send to the ICC /// APDU to send to the ICC
unsigned char abPINApdu[255]; unsigned char abPINApdu[255];
}__attribute__ ((packed)) S_ccid_PIN_Verification; }__attribute__ ((packed)) S_ccid_PIN_Verification;
/// 6.1.11.7 PIN Modification Data Structure /// 6.1.11.7 PIN Modification Data Structure
typedef struct typedef struct
{ {
/// Number of seconds. If 00h then CCID default value is used. /// Number of seconds. If 00h then CCID default value is used.
unsigned char bTimeOut; unsigned char bTimeOut;
/// Several parameters for the PIN format options (defined in § 6.1.11.4) /// Several parameters for the PIN format options (defined in § 6.1.11.4)
unsigned char bmFormatString4; unsigned char bmFormatString4;
/// Define the length of the PIN to present in the APDU command /// Define the length of the PIN to present in the APDU command
unsigned char bmPINBlockString; unsigned char bmPINBlockString;
/// Allows the length PIN insertion in the APDU command (defined in § 6.1.11.6) /// Allows the length PIN insertion in the APDU command (defined in § 6.1.11.6)
unsigned char bmPinLengthFormat; unsigned char bmPinLengthFormat;
/// Insertion position offset in byte for the current PIN /// Insertion position offset in byte for the current PIN
unsigned char bInsertionOffsetOld; unsigned char bInsertionOffsetOld;
/// Insertion position offset in byte for the new PIN /// Insertion position offset in byte for the new PIN
unsigned char bInsertionOffsetNew; unsigned char bInsertionOffsetNew;
/// XXYYh /// XXYYh
/// XX: Minimum PIN size in digit /// XX: Minimum PIN size in digit
/// YY: Maximum PIN size in digit /// YY: Maximum PIN size in digit
unsigned char wPINMaxExtraDigit; unsigned char wPINMaxExtraDigit;
/// 00h,01h,02h,03h /// 00h,01h,02h,03h
/// Indicates if a confirmation is requested before acceptance of a new PIN (meaning that the user has to enter this new PIN twice before it is accepted) /// Indicates if a confirmation is requested before acceptance of a new PIN (meaning that the user has to enter this new PIN twice before it is accepted)
/// Indicates if the current PIN must be entered and set in the same APDU field of not. /// Indicates if the current PIN must be entered and set in the same APDU field of not.
unsigned char bConfirmPIN; unsigned char bConfirmPIN;
/// The value is a bit wise OR operation. /// The value is a bit wise OR operation.
/// 01h Max size reached /// 01h Max size reached
/// 02h Validation key pressed /// 02h Validation key pressed
/// 04h Timeout occurred /// 04h Timeout occurred
unsigned char bEntryValidationCondition; unsigned char bEntryValidationCondition;
/// 00h,01h,02h,03h,or FFh /// 00h,01h,02h,03h,or FFh
/// Number of messages to display for the PIN modify command. /// Number of messages to display for the PIN modify command.
unsigned char bNumberMessage; unsigned char bNumberMessage;
/// Language used to display the messages. The 16 bit /// Language used to display the messages. The 16 bit
unsigned char wLangId; unsigned char wLangId;
/// Message index in the Reader message table (should be 00h or 01h). /// Message index in the Reader message table (should be 00h or 01h).
unsigned char bMsgIndex1; unsigned char bMsgIndex1;
/// Message index in the Reader message table (should be 01h or 02h). /// Message index in the Reader message table (should be 01h or 02h).
unsigned char bMsgIndex2; unsigned char bMsgIndex2;
/// Message index in the Reader message table (should be 02h). /// Message index in the Reader message table (should be 02h).
unsigned char bMsgIndex3; unsigned char bMsgIndex3;
/// T=1 I-block prologue field to use. Significant only if protocol in use is T=1. /// T=1 I-block prologue field to use. Significant only if protocol in use is T=1.
unsigned char bTeoPrologue[3]; unsigned char bTeoPrologue[3];
/// Byte array APDU to send to the ICC /// Byte array APDU to send to the ICC
unsigned char abPINApdu[255]; unsigned char abPINApdu[255];
}__attribute__ ((packed)) S_ccid_PIN_Modification; }__attribute__ ((packed)) S_ccid_PIN_Modification;
/// Protocol Data Structure for Protocol T=0 (bProtocolNum=0, dwLength=00000005h) /// Protocol Data Structure for Protocol T=0 (bProtocolNum=0, dwLength=00000005h)
typedef struct typedef struct
{ {
/// B7-4 FI Index into the table 7 in ISO/IEC 7816-3:1997 selecting a /// B7-4 FI Index into the table 7 in ISO/IEC 7816-3:1997 selecting a
/// clock rate conversion factor /// clock rate conversion factor
/// B3-0 DI - Index into the table 8 in ISO/IEC 7816-3:1997 selecting a /// B3-0 DI - Index into the table 8 in ISO/IEC 7816-3:1997 selecting a
/// baud rate conversion factor /// baud rate conversion factor
unsigned char bmFindexDindex; unsigned char bmFindexDindex;
/// For T=0 ,B0 0b, B7-2 000000b /// For T=0 ,B0 0b, B7-2 000000b
/// B1 Convention used (b1=0 for direct, b1=1 for inverse) /// B1 Convention used (b1=0 for direct, b1=1 for inverse)
unsigned char bmTCCKST0; // 0 to 2 unsigned char bmTCCKST0; // 0 to 2
/// Extra Guardtime between two characters. Add 0 to 254 etu to the normal /// Extra Guardtime between two characters. Add 0 to 254 etu to the normal
/// guardtime of 12etu. FFh is the same as 00h. /// guardtime of 12etu. FFh is the same as 00h.
unsigned char bGuardTimeT0; // 0 to FF unsigned char bGuardTimeT0; // 0 to FF
/// WI for T=0 used to define WWT /// WI for T=0 used to define WWT
unsigned char bWaitingIntegerT0; // 0 to FF unsigned char bWaitingIntegerT0; // 0 to FF
/// ICC Clock Stop Support /// ICC Clock Stop Support
/// 00 = Stopping the Clock is not allowed /// 00 = Stopping the Clock is not allowed
/// 01 = Stop with Clock signal Low /// 01 = Stop with Clock signal Low
/// 02 = Stop with Clock signal High /// 02 = Stop with Clock signal High
/// 03 = Stop with Clock either High or Low /// 03 = Stop with Clock either High or Low
unsigned char bClockStop; // 0 to 3 unsigned char bClockStop; // 0 to 3
} __attribute__ ((packed)) S_ccid_protocol_t0; } __attribute__ ((packed)) S_ccid_protocol_t0;
/// Protocol Data Structure for Protocol T=1 (bProtocolNum=1, dwLength=00000007h) /// Protocol Data Structure for Protocol T=1 (bProtocolNum=1, dwLength=00000007h)
typedef struct typedef struct
{ {
/// B7-4 FI Index into the table 7 in ISO/IEC 7816-3:1997 selecting a /// B7-4 FI Index into the table 7 in ISO/IEC 7816-3:1997 selecting a
/// clock rate conversion factor /// clock rate conversion factor
/// B3-0 DI - Index into the table 8 in ISO/IEC 7816-3:1997 selecting a /// B3-0 DI - Index into the table 8 in ISO/IEC 7816-3:1997 selecting a
/// baud rate conversion factor /// baud rate conversion factor
unsigned char bmFindexDindex; unsigned char bmFindexDindex;
/// For T=1, B7-2 000100b /// For T=1, B7-2 000100b
/// B0 Checksum type (b0=0 for LRC, b0=1 for CRC /// B0 Checksum type (b0=0 for LRC, b0=1 for CRC
/// B1 Convention used (b1=0 for direct, b1=1 for inverse) /// B1 Convention used (b1=0 for direct, b1=1 for inverse)
unsigned char bmTCCKST1; // 10h, 11h, 12h, 13h unsigned char bmTCCKST1; // 10h, 11h, 12h, 13h
/// Extra Guardtime (0 to 254 etu between two characters). /// Extra Guardtime (0 to 254 etu between two characters).
/// If value is FFh, then guardtime is reduced by 1. /// If value is FFh, then guardtime is reduced by 1.
unsigned char bGuardTimeT1; // 0 to FF unsigned char bGuardTimeT1; // 0 to FF
/// B7-4 = BWI /// B7-4 = BWI
/// B3-0 = CWI /// B3-0 = CWI
unsigned char bmWaitingIntegersT1; // 0 to 9 unsigned char bmWaitingIntegersT1; // 0 to 9
/// ICC Clock Stop Support /// ICC Clock Stop Support
/// 00 = Stopping the Clock is not allowed /// 00 = Stopping the Clock is not allowed
/// 01 = Stop with Clock signal Low /// 01 = Stop with Clock signal Low
/// 02 = Stop with Clock signal High /// 02 = Stop with Clock signal High
/// 03 = Stop with Clock either High or Low /// 03 = Stop with Clock either High or Low
unsigned char bClockStop; // 0 to 3 unsigned char bClockStop; // 0 to 3
/// Size of negotiated IFSC /// Size of negotiated IFSC
unsigned char bIFSC; // 0 to FE unsigned char bIFSC; // 0 to FE
/// Nad value used by CCID /// Nad value used by CCID
unsigned char bNadValue; // 0 to FF unsigned char bNadValue; // 0 to FF
} __attribute__ ((packed)) S_ccid_protocol_t1; } __attribute__ ((packed)) S_ccid_protocol_t1;
@@ -357,8 +357,8 @@ typedef struct
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
extern unsigned char RDRtoPCHardwareError( unsigned char bSlot, extern unsigned char RDRtoPCHardwareError( unsigned char bSlot,
unsigned char bSeq, unsigned char bSeq,
unsigned char bHardwareErrorCode ); unsigned char bHardwareErrorCode );
/* /*
#if !defined(NOAUTOCALLBACK) #if !defined(NOAUTOCALLBACK)
@@ -368,13 +368,13 @@ extern void USBDCallbacks_RequestReceived(const USBGenericRequest *request);
extern void CCID_SmartCardRequest( void ); extern void CCID_SmartCardRequest( void );
extern void CCIDDriver_Initialize( void ); extern void CCIDDriver_Initialize( void );
extern unsigned char CCID_Read(void *pBuffer, extern unsigned char CCID_Read(void *pBuffer,
unsigned int dLength, unsigned int dLength,
TransferCallback fCallback, TransferCallback fCallback,
void *pArgument); void *pArgument);
extern unsigned char CCID_Write(void *pBuffer, extern unsigned char CCID_Write(void *pBuffer,
unsigned int dLength, unsigned int dLength,
TransferCallback fCallback, TransferCallback fCallback,
void *pArgument); void *pArgument);
extern unsigned char CCID_Insertion( void ); extern unsigned char CCID_Insertion( void );
extern unsigned char CCID_Removal( void ); extern unsigned char CCID_Removal( void );

View File

@@ -0,0 +1,98 @@
/*
* Copyright (C) 2019 sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/* this library provides utilities to handle the ISO-7816 part 3 communication aspects (e.g. related to F and D) */
#pragma once
#include <stdint.h>
#include <stdbool.h>
/** default clock rate conversion integer Fd
* @implements ISO/IEC 7816-3:2006(E) section 8.1
*/
#define ISO7816_3_DEFAULT_FD 372
/** default baud rate adjustment factor Dd
* @implements ISO/IEC 7816-3:2006(E) section 8.1
*/
#define ISO7816_3_DEFAULT_DD 1
/** default clock rate conversion integer Fi
* @implements ISO/IEC 7816-3:2006(E) section 8.3
* @note non-default value is optionally specified in TA1
*/
#define ISO7816_3_DEFAULT_FI 372
/** default baud rate adjustment factor Di
* @implements ISO/IEC 7816-3:2006(E) section 8.3
* @note non-default value is optionally specified in TA1
*/
#define ISO7816_3_DEFAULT_DI 1
/** default maximum clock frequency, in Hz
* @implements ISO/IEC 7816-3:2006(E) section 8.3
* @note non-default value is optionally specified in TA1
*/
#define ISO7816_3_DEFAULT_FMAX 5000000UL
/** default Waiting Integer (WI) value for T=0
* @implements ISO/IEC 7816-3:2006(E) section 10.2
* @note non-default value is optionally specified in TC2
*/
#define ISO7816_3_DEFAULT_WI 10
/** default Waiting Time (WT) value, in ETU
* @implements ISO/IEC 7816-3:2006(E) section 8.1
* @note depends on Fi, Di, and WI if protocol T=0 is selected
*/
#define ISO7816_3_DEFAULT_WT 9600
/** Table encoding the clock rate conversion integer Fi
* @note Fi is indicated in TA1, but the same table is used for F and Fn during PPS
* @implements ISO/IEC 7816-3:2006(E) table 7
*/
extern const uint16_t iso7816_3_fi_table[];
/** Table encoding the maximum clock frequency f_max in Hz
* @implements ISO/IEC 7816-3:2006(E) table 7
* @note f_max is indicated in TA1, but the same table is used for F and Fn during PPS
*/
extern const uint32_t iso7816_3_fmax_table[];
/** Table encoding the baud rate adjust integer Di
* @implements ISO/IEC 7816-3:2006(E) table 8
* @note Di is indicated in TA1, but the same table is used for D and Dn during PPS
*/
extern const uint8_t iso7816_3_di_table[];
/* verify if the clock rate conversion integer F value is valid
* @param[in] f F value to be validated
* @return if F value is valid
* @note only values in ISO/IEC 7816-3:2006(E) table 7 are valid
*/
bool iso7816_3_valid_f(uint16_t f);
/* verify if the baud rate adjustment factor D value is valid
* @param[in] d D value to be validated
* @return if D value is valid
* @note only values in ISO/IEC 7816-3:2006(E) table 8 are valid
*/
bool iso7816_3_valid_d(uint8_t d);
/** calculate Waiting Time (WT)
* @param[in] wi Waiting Integer
* @param[in] fi clock rate conversion integer Fi value
* @param[in] di baud rate adjustment factor Di value
* @param[in] f clock rate conversion integer F value
* @param[in] d baud rate adjustment factor D value
* @return Waiting Time WT, in ETU, or < 0 on error (see code for return codes)
* @note this should happen after reset and T=0 protocol select (through PPS or implicit)
* @implements ISO/IEC 7816-3:2006(E) section 8.1 and 10.2
*/
int32_t iso7816_3_calculate_wt(uint8_t wi, uint16_t fi, uint8_t di, uint16_t f, uint8_t d);

View File

@@ -76,9 +76,9 @@ extern uint32_t ISO7816_GetChar( uint8_t *pCharToReceive, Usart_info *usart);
extern void ISO7816_IccPowerOff(void); extern void ISO7816_IccPowerOff(void);
extern uint32_t ISO7816_XfrBlockTPDU_T0(const uint8_t *pAPDU, extern uint32_t ISO7816_XfrBlockTPDU_T0(const uint8_t *pAPDU,
uint8_t *pMessage, uint8_t *pMessage,
uint16_t wLength, uint16_t wLength,
uint16_t *retlen); uint16_t *retlen);
extern void ISO7816_Escape( void ); extern void ISO7816_Escape( void );
extern void ISO7816_RestartClock(void); extern void ISO7816_RestartClock(void);
extern void ISO7816_StopClock( void ); extern void ISO7816_StopClock( void );

View File

@@ -1,6 +1,30 @@
/* ISO7816-3 Fi/Di tables + computation
*
* (C) 2010-2015 by Harald Welte <laforge@gnumonks.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
/* Table 7 of ISO 7816-3:2006 */
extern const uint16_t fi_table[];
/* Table 8 from ISO 7816-3:2006 */
extern const uint8_t di_table[];
/* compute the F/D ratio based on Fi and Di values */ /* compute the F/D ratio based on Fi and Di values */
int compute_fidi_ratio(uint8_t fi, uint8_t di); int compute_fidi_ratio(uint8_t fi, uint8_t di);

View File

@@ -1,19 +1,42 @@
/* IRQ-safe linked lists
*
* (C) 2015-2017 by Harald Welte <laforge@gnumonks.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#pragma once #pragma once
#include "osmocom/core/linuxlist.h" #include <osmocom/core/linuxlist.h>
#include "utils.h"
static inline void llist_add_irqsafe(struct llist_head *_new, static inline void llist_add_irqsafe(struct llist_head *_new,
struct llist_head *head) struct llist_head *head)
{ {
__disable_irq(); unsigned long x;
local_irq_save(x);
llist_add(_new, head); llist_add(_new, head);
__enable_irq(); local_irq_restore(x);
} }
static inline void llist_add_tail_irqsafe(struct llist_head *_new, static inline void llist_add_tail_irqsafe(struct llist_head *_new,
struct llist_head *head) struct llist_head *head)
{ {
__disable_irq(); unsigned long x;
local_irq_save(x);
llist_add_tail(_new, head); llist_add_tail(_new, head);
__enable_irq(); __enable_irq();
} }
@@ -21,15 +44,16 @@ static inline void llist_add_tail_irqsafe(struct llist_head *_new,
static inline struct llist_head *llist_head_dequeue_irqsafe(struct llist_head *head) static inline struct llist_head *llist_head_dequeue_irqsafe(struct llist_head *head)
{ {
struct llist_head *lh; struct llist_head *lh;
unsigned long x;
__disable_irq(); local_irq_save(x);
if (llist_empty(head)) { if (llist_empty(head)) {
lh = NULL; lh = NULL;
} else { } else {
lh = head->next; lh = head->next;
llist_del(lh); llist_del(lh);
} }
__enable_irq(); local_irq_restore(x);
return lh; return lh;
} }

View File

@@ -1,3 +1,19 @@
/* Ring buffer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef SIMTRACE_RINGBUF_H #ifndef SIMTRACE_RINGBUF_H
#define SIMTRACE_RINGBUF_H #define SIMTRACE_RINGBUF_H
@@ -5,7 +21,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <sys/types.h> #include <sys/types.h>
#define RING_BUFLEN 128 #define RING_BUFLEN 512
typedef struct ringbuf { typedef struct ringbuf {
uint8_t buf[RING_BUFLEN]; uint8_t buf[RING_BUFLEN];
@@ -16,7 +32,7 @@ typedef struct ringbuf {
void rbuf_reset(volatile ringbuf * rb); void rbuf_reset(volatile ringbuf * rb);
uint8_t rbuf_read(volatile ringbuf * rb); uint8_t rbuf_read(volatile ringbuf * rb);
uint8_t rbuf_peek(volatile ringbuf * rb); uint8_t rbuf_peek(volatile ringbuf * rb);
void rbuf_write(volatile ringbuf * rb, uint8_t item); int rbuf_write(volatile ringbuf * rb, uint8_t item);
bool rbuf_is_empty(volatile ringbuf * rb); bool rbuf_is_empty(volatile ringbuf * rb);
bool rbuf_is_full(volatile ringbuf * rb); bool rbuf_is_full(volatile ringbuf * rb);

View File

@@ -1,24 +1,30 @@
/* SIMtrace 2 mode definitions
*
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef SIMTRACE_H #ifndef SIMTRACE_H
#define SIMTRACE_H #define SIMTRACE_H
#include "ringbuffer.h" #include "ringbuffer.h"
#include "board.h" #include "board.h"
#include <usb/device/dfu/dfu.h>
/* Endpoint numbers */
#define DATAOUT 1
#define DATAIN 2
#define INT 3
#define BUFLEN 512 #define BUFLEN 512
#define PHONE_DATAOUT 4
#define PHONE_DATAIN 5
#define PHONE_INT 6
#define CARDEM_USIM2_DATAOUT DATAOUT
#define CARDEM_USIM2_DATAIN DATAIN
#define CARDEM_USIM2_INT INT
#define CLK_MASTER true #define CLK_MASTER true
#define CLK_SLAVE false #define CLK_SLAVE false
@@ -59,24 +65,28 @@ enum confNum {
/// device using the CCID driver. /// device using the CCID driver.
typedef struct { typedef struct {
/// Configuration descriptor /// Configuration descriptor
USBConfigurationDescriptor configuration; USBConfigurationDescriptor configuration;
/// Interface descriptor /// Interface descriptor
USBInterfaceDescriptor interface; USBInterfaceDescriptor interface;
/// CCID descriptor /// CCID descriptor
CCIDDescriptor ccid; CCIDDescriptor ccid;
/// Bulk OUT endpoint descriptor /// Bulk OUT endpoint descriptor
USBEndpointDescriptor bulkOut; USBEndpointDescriptor bulkOut;
/// Bulk IN endpoint descriptor /// Bulk IN endpoint descriptor
USBEndpointDescriptor bulkIn; USBEndpointDescriptor bulkIn;
/// Interrupt OUT endpoint descriptor /// Interrupt OUT endpoint descriptor
USBEndpointDescriptor interruptIn; USBEndpointDescriptor interruptIn;
DFURT_IF_DESCRIPTOR_STRUCT
} __attribute__ ((packed)) CCIDDriverConfigurationDescriptors; } __attribute__ ((packed)) CCIDDriverConfigurationDescriptors;
extern const USBConfigurationDescriptor *configurationDescriptorsArr[]; extern const USBConfigurationDescriptor *configurationDescriptorsArr[];
int check_data_from_phone(); /*! Update USART baud rate to Fi/Di ratio
void update_fidi(uint8_t fidi); * @param[io] usart USART peripheral base address
* @param[in] fidi FiDi value as provided in TA interface byte
*/
void update_fidi(Usart_info *usart, uint8_t fidi);
void ISR_PhoneRST( const Pin *pPin); void ISR_PhoneRST( const Pin *pPin);
@@ -106,6 +116,9 @@ extern void CCID_run( void );
extern void mode_cardemu_run(void); extern void mode_cardemu_run(void);
extern void MITM_run( void ); extern void MITM_run( void );
/* IRQ functions */
extern void Sniffer_usart0_irq(void);
extern void Sniffer_usart1_irq(void);
extern void mode_cardemu_usart0_irq(void); extern void mode_cardemu_usart0_irq(void);
extern void mode_cardemu_usart1_irq(void); extern void mode_cardemu_usart1_irq(void);

View File

@@ -1,26 +1,26 @@
/* SIMtrace2 USB protocol
*
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
/* SIMtrace2 USB protocol */
/* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/*********************************************************************** /***********************************************************************
* COMMON HEADER * COMMON HEADER
@@ -30,10 +30,10 @@ enum simtrace_msg_class {
SIMTRACE_MSGC_GENERIC = 0, SIMTRACE_MSGC_GENERIC = 0,
/* Card Emulation / Forwarding */ /* Card Emulation / Forwarding */
SIMTRACE_MSGC_CARDEM, SIMTRACE_MSGC_CARDEM,
/* Modem Control (if modem is attached next to device */ /* Modem Control (if modem is attached next to device) */
SIMTRACE_MSGC_MODEM, SIMTRACE_MSGC_MODEM,
/* SIM protocol tracing */ /* Reader/phone-car/SIM communication sniff */
SIMTRACE_MSGC_TRACE, SIMTRACE_MSGC_SNIFF,
/* first vendor-specific request */ /* first vendor-specific request */
_SIMTRACE_MGSC_VENDOR_FIRST = 127, _SIMTRACE_MGSC_VENDOR_FIRST = 127,
@@ -74,10 +74,18 @@ enum simtrace_msg_type_modem {
SIMTRACE_MSGT_BD_MODEM_STATUS, SIMTRACE_MSGT_BD_MODEM_STATUS,
}; };
/* SIMTRACE_MSGC_TRACE */ /* SIMTRACE_MSGC_SNIFF */
enum simtrace_msg_type_trace { enum simtrace_msg_type_sniff {
/* FIXME */ /* Status change (card inserted, reset, ...) */
_dummy, SIMTRACE_MSGT_SNIFF_CHANGE = 0,
/* Fi/Di baudrate change */
SIMTRACE_MSGT_SNIFF_FIDI,
/* ATR data */
SIMTRACE_MSGT_SNIFF_ATR,
/* PPS (request or response) data */
SIMTRACE_MSGT_SNIFF_PPS,
/* TPDU data */
SIMTRACE_MSGT_SNIFF_TPDU,
}; };
/* common message header */ /* common message header */
@@ -92,7 +100,7 @@ struct simtrace_msg_hdr {
} __attribute__ ((packed)); } __attribute__ ((packed));
/*********************************************************************** /***********************************************************************
* CARD EMULATOR / FORWARDER * Capabilities
***********************************************************************/ ***********************************************************************/
/* generic capabilities */ /* generic capabilities */
@@ -107,7 +115,7 @@ enum simtrace_capability_generic {
SIMTRACE_CAP_LED_1, SIMTRACE_CAP_LED_1,
/* Has LED2 */ /* Has LED2 */
SIMTRACE_CAP_LED_2, SIMTRACE_CAP_LED_2,
/* Has Single-Pole Dual-Throw (local/remote SIM */ /* Has Single-Pole Dual-Throw (local/remote SIM) */
SIMTRACE_CAP_SPDT, SIMTRACE_CAP_SPDT,
/* Has Bus-Switch (trace / MITM) */ /* Has Bus-Switch (trace / MITM) */
SIMTRACE_CAP_BUS_SWITCH, SIMTRACE_CAP_BUS_SWITCH,
@@ -127,7 +135,7 @@ enum simtrace_capability_generic {
SIMTRACE_CAP_ASSERT_MODEM_RST, SIMTRACE_CAP_ASSERT_MODEM_RST,
}; };
/* vendor-specific capabilities of sysmoocm devices */ /* vendor-specific capabilities of sysmocom devices */
enum simtrace_capability_vendor { enum simtrace_capability_vendor {
/* Can erase a peer SAM3 controller */ /* Can erase a peer SAM3 controller */
SIMTRACE_CAP_SYSMO_QMOD_ERASE_PEER, SIMTRACE_CAP_SYSMO_QMOD_ERASE_PEER,
@@ -137,7 +145,6 @@ enum simtrace_capability_vendor {
SIMTRACE_CAP_SYSMO_QMOD_RESET_HUB, SIMTRACE_CAP_SYSMO_QMOD_RESET_HUB,
}; };
/* SIMTRACE_CMD_BD_BOARD_INFO */ /* SIMTRACE_CMD_BD_BOARD_INFO */
struct simtrace_board_info { struct simtrace_board_info {
struct { struct {
@@ -221,11 +228,10 @@ struct cardemu_usb_msg_status {
uint32_t flags; uint32_t flags;
/* phone-applied target voltage in mV */ /* phone-applied target voltage in mV */
uint16_t voltage_mv; uint16_t voltage_mv;
/* Fi/Di related information */ uint8_t f; /*!< index of F and f_max values as encoded in ISO/IEC 7816-3:2006(E) Table 7 */
uint8_t fi; uint8_t d; /*!< index of D value as encoded in ISO/IEC 7816-3:2006(E) Table 8 */
uint8_t di; uint8_t wi; /*!< Waiting Integer as defined in ISO/IEC 7816-3:2006(E) Section 10.2 */
uint8_t wi; uint32_t wt; /*!< Waiting Time in ETU as defined in ISO/IEC 7816-3:2006(E) Section 8.1 */
uint32_t waiting_time;
} __attribute__ ((packed)); } __attribute__ ((packed));
/* CEMU_USB_MSGT_DO_PTS */ /* CEMU_USB_MSGT_DO_PTS */
@@ -253,7 +259,7 @@ struct cardemu_usb_msg_error {
/* SIMTRACE_MSGT_DT_MODEM_RESET */ /* SIMTRACE_MSGT_DT_MODEM_RESET */
struct st_modem_reset { struct st_modem_reset {
/* 0: de-assert reset, 1: assert reset, 2: poulse reset */ /* 0: de-assert reset, 1: assert reset, 2: pulse reset */
uint8_t asserted; uint8_t asserted;
/* if above is '2', duration of pulse in ms */ /* if above is '2', duration of pulse in ms */
uint16_t pulse_duration_msec; uint16_t pulse_duration_msec;
@@ -276,3 +282,40 @@ struct st_modem_status {
/* bit-field of changed status bits */ /* bit-field of changed status bits */
uint8_t changed_mask; uint8_t changed_mask;
} __attribute__((packed)); } __attribute__((packed));
/***********************************************************************
* SNIFF
***********************************************************************/
/* SIMTRACE_MSGT_SNIFF_CHANGE flags */
#define SNIFF_CHANGE_FLAG_CARD_INSERT (1<<0)
#define SNIFF_CHANGE_FLAG_CARD_EJECT (1<<1)
#define SNIFF_CHANGE_FLAG_RESET_ASSERT (1<<2)
#define SNIFF_CHANGE_FLAG_RESET_DEASSERT (1<<3)
#define SNIFF_CHANGE_FLAG_TIMEOUT_WT (1<<4)
/* SIMTRACE_MSGT_SNIFF_ATR, SIMTRACE_MSGT_SNIFF_PPS, SIMTRACE_MSGT_SNIFF_TPDU flags */
#define SNIFF_DATA_FLAG_ERROR_INCOMPLETE (1<<5)
#define SNIFF_DATA_FLAG_ERROR_MALFORMED (1<<6)
#define SNIFF_DATA_FLAG_ERROR_CHECKSUM (1<<7)
/* SIMTRACE_MSGT_SNIFF_CHANGE */
struct sniff_change {
/* SIMTRACE_MSGT_SNIFF_CHANGE flags */
uint32_t flags;
} __attribute__ ((packed));
/* SIMTRACE_MSGT_SNIFF_FIDI */
struct sniff_fidi {
/* Fi/Di values as encoded in TA1 */
uint8_t fidi;
} __attribute__ ((packed));
/* SIMTRACE_MSGT_SNIFF_ATR, SIMTRACE_MSGT_SNIFF_PPS, SIMTRACE_MSGT_SNIFF_TPDU */
struct sniff_data {
/* data flags */
uint32_t flags;
/* data length */
uint16_t length;
/* data */
uint8_t data[0];
} __attribute__ ((packed));

View File

@@ -0,0 +1,67 @@
/* SIMtrace 2 USB definitions
*
* (C) 2018 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
/* SIMtrace USB IDs */
#define USB_VENDOR_OPENMOKO 0x1d50
#define USB_PRODUCT_OWHW_SAM3_DFU 0x4001 /* was 0x4000 */
#define USB_PRODUCT_OWHW_SAM3 0x4001
#define USB_PRODUCT_QMOD_HUB 0x4002
#define USB_PRODUCT_QMOD_SAM3_DFU 0x4004 /* was 0x4003 */
#define USB_PRODUCT_QMOD_SAM3 0x4004
#define USB_PRODUCT_SIMTRACE2_DFU 0x60e3 /* was 0x60e2 */
#define USB_PRODUCT_SIMTRACE2 0x60e3
/* USB proprietary class */
#define USB_CLASS_PROPRIETARY 0xff
/* SIMtrace USB sub-classes */
/*! Sniffer USB sub-class */
#define SIMTRACE_SNIFFER_USB_SUBCLASS 1
/*! Card-emulation USB sub-class */
#define SIMTRACE_CARDEM_USB_SUBCLASS 2
/* Generic USB endpoint numbers */
/*! Card-side USB data out (host to device) endpoint number */
#define SIMTRACE_USB_EP_CARD_DATAOUT 1
/*! Card-side USB data in (device to host) endpoint number */
#define SIMTRACE_USB_EP_CARD_DATAIN 2
/*! Card-side USB interrupt endpoint number */
#define SIMTRACE_USB_EP_CARD_INT 3
/*! Phone-side USB data out (host to device) endpoint number */
#define SIMTRACE_USB_EP_PHONE_DATAOUT 4
/*! Phone-side USB data in (device to host) endpoint number */
#define SIMTRACE_USB_EP_PHONE_DATAIN 5
/*! Phone-side USB interrupt endpoint number */
#define SIMTRACE_USB_EP_PHONE_INT 6
/* Card-emulation USB endpoint numbers */
/*! USIM1 USB data out (host to device) endpoint number */
#define SIMTRACE_CARDEM_USB_EP_USIM1_DATAOUT 4
/*! USIM1 USB data in (device to host) endpoint number */
#define SIMTRACE_CARDEM_USB_EP_USIM1_DATAIN 5
/*! USIM1 USB interrupt endpoint number */
#define SIMTRACE_CARDEM_USB_EP_USIM1_INT 6
/*! USIM2 USB data out (host to device) endpoint number */
#define SIMTRACE_CARDEM_USB_EP_USIM2_DATAOUT 1
/*! USIM2 USB data in (device to host) endpoint number */
#define SIMTRACE_CARDEM_USB_EP_USIM2_DATAIN 2
/*! USIM2 USB interrupt endpoint number */
#define SIMTRACE_CARDEM_USB_EP_USIM2_INT 3
/*! Maximum number of endpoints */
#define BOARD_USB_NUMENDPOINTS 6

View File

@@ -1,3 +1,31 @@
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2008, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
#pragma once #pragma once
#include <stddef.h> #include <stddef.h>
#include <stdarg.h> #include <stdarg.h>
@@ -24,9 +52,14 @@ signed int printf(const char *pFormat, ...);
signed int sprintf(char *pStr, const char *pFormat, ...); signed int sprintf(char *pStr, const char *pFormat, ...);
signed int puts(const char *pStr); signed int puts(const char *pStr);
int fputc(int c, FILE *stream); int fputc(int c, FILE *stream);
int fputs(const char *s, FILE *stream); int fputs(const char *s, FILE *stream);
#define putc(c, stream) fputc(c, stream) #define putc(c, stream) fputc(c, stream)
#define putchar(c) fputc(c, stdout) #define putchar(c) fputc(c, stdout)
signed int vfprintf_sync(FILE *pStream, const char *pFormat, va_list ap);
signed int vprintf_sync(const char *pFormat, va_list ap);
signed int printf_sync(const char *pFormat, ...);
int fputc_sync(int c, FILE *stream);
int fputs_sync(const char *s, FILE *stream);

View File

@@ -1,3 +1,19 @@
/* Memory allocation library
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#pragma once #pragma once
#include <stdlib.h> #include <stdlib.h>

View File

@@ -1,7 +1,23 @@
/* USB buffer library
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#pragma once #pragma once
#include "osmocom/core/linuxlist.h" #include <osmocom/core/linuxlist.h>
#include "osmocom/core/msgb.h" #include <osmocom/core/msgb.h>
/* buffered USB endpoint (with queue of msgb) */ /* buffered USB endpoint (with queue of msgb) */
struct usb_buffered_ep { struct usb_buffered_ep {

View File

@@ -1,3 +1,19 @@
/* General utilities
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#pragma once #pragma once
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

View File

@@ -1,24 +1,22 @@
/* ISO7816-3 state machine for the card side */ /* ISO7816-3 state machine for the card side
/* (C) 2010-2017 by Harald Welte <hwelte@hmw-consulting.de>
* *
* This program is free software; you can redistribute it and/or modify * (C) 2010-2017 by Harald Welte <laforge@gnumonks.org>
* it under the terms of the GNU General Public License as published by * (C) 2018-2019 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is free software; you can redistribute it and/or modify
* but WITHOUT ANY WARRANTY; without even the implied warranty of * it under the terms of the GNU General Public License as published by
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * the Free Software Foundation; either version 2 of the License, or
* GNU General Public License for more details. * (at your option) any later version.
* *
* You should have received a copy of the GNU General Public License * This program is distributed in the hope that it will be useful,
* along with this program; if not, write to the Free Software * but WITHOUT ANY WARRANTY; without even the implied warranty of
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/ */
//#define TRACE_LEVEL 6
#include <stdio.h> #include <stdio.h>
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
@@ -28,14 +26,12 @@
#include "utils.h" #include "utils.h"
#include "trace.h" #include "trace.h"
#include "iso7816_fidi.h" #include "iso7816_3.h"
#include "tc_etu.h"
#include "card_emu.h" #include "card_emu.h"
#include "simtrace_prot.h" #include "simtrace_prot.h"
#include "usb_buf.h" #include "usb_buf.h"
#include "osmocom/core/linuxlist.h" #include <osmocom/core/linuxlist.h>
#include "osmocom/core/msgb.h" #include <osmocom/core/msgb.h>
#define NUM_SLOTS 2 #define NUM_SLOTS 2
@@ -56,6 +52,46 @@ enum iso7816_3_card_state {
ISO_S_IN_TPDU, /* inside a TPDU */ ISO_S_IN_TPDU, /* inside a TPDU */
}; };
const struct value_string iso7816_3_card_state_names[] = {
{
.value = ISO_S_WAIT_POWER,
.str = "WAIT_POWER",
},
{
.value = ISO_S_WAIT_CLK,
.str = "WAIT_CLK",
},
{
.value = ISO_S_WAIT_RST,
.str = "WAIT_RST",
},
{
.value = ISO_S_WAIT_ATR,
.str = "WAIT_ATR",
},
{
.value = ISO_S_IN_ATR,
.str = "IN_ATR",
},
{
.value = ISO_S_IN_PTS,
.str = "IN_PTS",
},
{
.value = ISO_S_WAIT_TPDU,
.str = "WAIT_TPDU",
},
{
.value = ISO_S_IN_TPDU,
.str = "IN_TPDU",
},
{
.value = 0,
.str = NULL,
},
};
/* detailed sub-states of ISO_S_IN_PTS */ /* detailed sub-states of ISO_S_IN_PTS */
enum pts_state { enum pts_state {
PTS_S_WAIT_REQ_PTSS, PTS_S_WAIT_REQ_PTSS,
@@ -72,6 +108,7 @@ enum pts_state {
PTS_S_WAIT_RESP_PCK = PTS_S_WAIT_REQ_PCK | 0x10, PTS_S_WAIT_RESP_PCK = PTS_S_WAIT_REQ_PCK | 0x10,
}; };
/* PTS field byte index */
#define _PTSS 0 #define _PTSS 0
#define _PTS0 1 #define _PTS0 1
#define _PTS1 2 #define _PTS1 2
@@ -87,10 +124,50 @@ enum tpdu_state {
TPDU_S_WAIT_P2, /* waiting for P2 byte from reader */ TPDU_S_WAIT_P2, /* waiting for P2 byte from reader */
TPDU_S_WAIT_P3, /* waiting for P3 byte from reader */ TPDU_S_WAIT_P3, /* waiting for P3 byte from reader */
TPDU_S_WAIT_PB, /* waiting for Tx of procedure byte */ TPDU_S_WAIT_PB, /* waiting for Tx of procedure byte */
TPDU_S_WAIT_RX, /* waiitng for more data from reader */ TPDU_S_WAIT_RX, /* waiting for more data from reader */
TPDU_S_WAIT_TX, /* waiting for more data to reader */ TPDU_S_WAIT_TX, /* waiting for more data to reader */
}; };
const struct value_string tpdu_state_names[] = {
{
.value = TPDU_S_WAIT_CLA,
.str = "WAIT_CLA",
},
{
.value = TPDU_S_WAIT_INS,
.str = "WAIT_INS",
},
{
.value = TPDU_S_WAIT_P1,
.str = "WAIT_P1",
},
{
.value = TPDU_S_WAIT_P2,
.str = "WAIT_P2",
},
{
.value = TPDU_S_WAIT_P3,
.str = "WAIT_P3",
},
{
.value = TPDU_S_WAIT_PB,
.str = "WAIT_PB",
},
{
.value = TPDU_S_WAIT_RX,
.str = "WAIT_RX",
},
{
.value = TPDU_S_WAIT_TX,
.str = "WAIT_TX",
},
{
.value = 0,
.str = NULL,
},
};
/* TPDU field byte index */
#define _CLA 0 #define _CLA 0
#define _INS 1 #define _INS 1
#define _P1 2 #define _P1 2
@@ -98,7 +175,7 @@ enum tpdu_state {
#define _P3 4 #define _P3 4
struct card_handle { struct card_handle {
uint32_t num; unsigned int num;
enum iso7816_3_card_state state; enum iso7816_3_card_state state;
@@ -107,18 +184,53 @@ struct card_handle {
uint8_t in_reset; /* 1 = RST low, 0 = RST high */ uint8_t in_reset; /* 1 = RST low, 0 = RST high */
uint8_t clocked; /* 1 = active, 0 = inactive */ uint8_t clocked; /* 1 = active, 0 = inactive */
/* timing parameters, from PTS */
uint8_t fi;
uint8_t di;
uint8_t wi;
uint8_t tc_chan; /* TC channel number */ uint8_t tc_chan; /* TC channel number */
uint8_t uart_chan; /* UART channel */ uint8_t uart_chan; /* UART channel */
uint8_t in_ep; /* USB IN EP */ uint8_t in_ep; /* USB IN EP */
uint8_t irq_ep; /* USB IN EP */ uint8_t irq_ep; /* USB IN EP */
uint32_t waiting_time; /* in clocks */ /*! clock rate conversion integer F
* @implements ISO/IEC 7816-3:2006(E) section 7.1
* @note this represents the current value used
*/
uint16_t f;
/*! baud rate adjustment factor D
* @implements ISO/IEC 7816-3:2006(E) section 7.1
* @note this represents the current value used
*/
uint8_t d;
/*! clock frequency in Hz
* @implements ISO/IEC 7816-3:2006(E) section 7.1
* @note the USART peripheral in slave mode does not provide the current value. we could measure it but this is not really useful. instead we remember the maximum possible value corresponding to the selected F value
*/
uint32_t f_cur;
/*! clock rate conversion integer Fi
* @implements ISO/IEC 7816-3:2006(E) Table 7
* @note this represents the maximum value supported by the card, and can be indicated in TA1
* @note this value can be set in TA1
*/
uint16_t fi;
/*! baud rate adjustment factor Di
* @implements ISO/IEC 7816-3:2006(E) Table 8
* @note this represents the maximum value supported by the card, and can be indicated in TA1
*/
uint8_t di;
/*! clock frequency, in Hz
* @implements ISO/IEC 7816-3:2006(E) Table 7
* @note this represents the maximum value supported by the card, and can be indicated in TA1
*/
uint32_t f_max;
/*! Waiting Integer
* @implements ISO/IEC 7816-3:2006(E) Section 10.2
* @note this value can be set in TA2
*/
uint8_t wi;
/*! Waiting Time, in ETU
* @implements ISO/IEC 7816-3:2006(E) Section 8.1
* @note this depends on Fi, Di, and WI if T=0 is used
*/
uint32_t wt;
/* ATR state machine */ /* ATR state machine */
struct { struct {
@@ -192,7 +304,7 @@ struct msgb *usb_buf_alloc_st(uint8_t ep, uint8_t msg_class, uint8_t msg_type)
return msg; return msg;
} }
/* Update cardemu_usb_msg_rx_data length + submit bufffer */ /* Update cardemu_usb_msg_rx_data length + submit buffer */
static void flush_rx_buffer(struct card_handle *ch) static void flush_rx_buffer(struct card_handle *ch)
{ {
struct msgb *msg; struct msgb *msg;
@@ -205,14 +317,17 @@ static void flush_rx_buffer(struct card_handle *ch)
ch->uart_rx_msg = NULL; ch->uart_rx_msg = NULL;
/* store length of data payload fild in header */ /* store length of data payload field in header */
rd = (struct cardemu_usb_msg_rx_data *) msg->l2h; rd = (struct cardemu_usb_msg_rx_data *) msg->l2h;
rd->data_len = msgb_l2len(msg) - sizeof(*rd); rd->data_len = msgb_l2len(msg) - sizeof(*rd);
TRACE_INFO("%u: %s (%u)\n\r",
ch->num, __func__, rd->data_len);
usb_buf_upd_len_and_submit(msg); usb_buf_upd_len_and_submit(msg);
} }
/* convert a non-contiguous PTS request/responsei into a contiguous /* convert a non-contiguous PTS request/response into a contiguous
* buffer, returning the number of bytes used in the buffer */ * buffer, returning the number of bytes used in the buffer */
static int serialize_pts(uint8_t *out, const uint8_t *in) static int serialize_pts(uint8_t *out, const uint8_t *in)
{ {
@@ -263,23 +378,6 @@ static void flush_pts(struct card_handle *ch)
usb_buf_upd_len_and_submit(msg); usb_buf_upd_len_and_submit(msg);
} }
static void emu_update_fidi(struct card_handle *ch)
{
int rc;
rc = compute_fidi_ratio(ch->fi, ch->di);
if (rc > 0 && rc < 0x400) {
TRACE_INFO("%u: computed Fi(%u) Di(%u) ratio: %d\r\n",
ch->num, ch->fi, ch->di, rc);
/* make sure UART uses new F/D ratio */
card_emu_uart_update_fidi(ch->uart_chan, rc);
/* notify ETU timer about this */
tc_etu_set_etu(ch->tc_chan, rc);
} else
TRACE_INFO("%u: computed FiDi ration %d unsupported\r\n",
ch->num, rc);
}
/* Update the ISO 7816-3 TPDU receiver state */ /* Update the ISO 7816-3 TPDU receiver state */
static void card_set_state(struct card_handle *ch, static void card_set_state(struct card_handle *ch,
enum iso7816_3_card_state new_state) enum iso7816_3_card_state new_state)
@@ -287,44 +385,59 @@ static void card_set_state(struct card_handle *ch,
if (ch->state == new_state) if (ch->state == new_state)
return; return;
TRACE_DEBUG("%u: 7816 card state %u -> %u\r\n", ch->num, TRACE_DEBUG("%u: 7816 card state %s -> %s\r\n", ch->num,
ch->state, new_state); get_value_string(iso7816_3_card_state_names, ch->state),
get_value_string(iso7816_3_card_state_names, new_state));
ch->state = new_state; ch->state = new_state;
switch (new_state) { switch (new_state) {
case ISO_S_WAIT_POWER: case ISO_S_WAIT_POWER:
case ISO_S_WAIT_CLK: case ISO_S_WAIT_CLK:
case ISO_S_WAIT_RST: case ISO_S_WAIT_RST:
/* disable Rx and Tx of UART */ card_emu_uart_enable(ch->uart_chan, 0); // disable Rx and Tx of UART
card_emu_uart_enable(ch->uart_chan, 0); card_emu_uart_update_wt(ch->uart_chan, 0); // disable timeout
if (ISO_S_WAIT_POWER == new_state) {
card_emu_uart_io_set(ch->uart_chan, false); // pull I/O line low
} else {
card_emu_uart_io_set(ch->uart_chan, true); // pull I/O line high
}
break; break;
case ISO_S_WAIT_ATR: case ISO_S_WAIT_ATR:
set_pts_state(ch, PTS_S_WAIT_REQ_PTSS); // reset the ETU-related values
/* Reset to initial Fi / Di ratio */ ch->f = ISO7816_3_DEFAULT_FD;
ch->fi = 1; ch->d = ISO7816_3_DEFAULT_DD;
ch->di = 1; card_emu_uart_update_fd(ch->uart_chan, ch->f, ch->d); // set baud rate
emu_update_fidi(ch);
/* initialize todefault WI, this will be overwritten if we // reset values optionally specified in the ATR
* receive TC2, and it will be programmed into hardware after ch->fi = ISO7816_3_DEFAULT_FI;
* ATR is finished */ ch->di = ISO7816_3_DEFAULT_DI;
ch->wi = ISO7816_3_DEFAULT_WI; ch->wi = ISO7816_3_DEFAULT_WI;
/* update waiting time to initial waiting time */ int32_t wt = iso7816_3_calculate_wt(ch->wi, ch->fi, ch->di, ch->f, ch->d); // get default waiting time
ch->waiting_time = ISO7816_3_INIT_WTIME; if (wt <= 0) {
tc_etu_set_wtime(ch->tc_chan, ch->waiting_time); TRACE_FATAL("%u: invalid WT %ld\r\n", ch->num, wt);
}
ch->wt = wt;
card_emu_uart_enable(ch->uart_chan, ENABLE_TX); // enable TX to be able to use the timeout
/* the ATR should only be sent 400 to 40k clock cycles after the RESET.
* we use the tc_etu mechanism to wait this time.
* since the initial ETU is Fd=372/Dd=1 clock cycles long, we have to wait 2-107 ETU.
*/
card_emu_uart_update_wt(ch->uart_chan, 2);
break;
case ISO_S_IN_ATR:
// FIXME disable timeout while sending ATR
/* Set ATR sub-state to initial state */ /* Set ATR sub-state to initial state */
ch->atr.idx = 0; ch->atr.idx = 0;
//set_atr_state(ch, ATR_S_WAIT_TS); /* enable USART transmission to reader */
/* Notice that we are just coming out of reset */
//ch->sh.flags |= SIMTRACE_FLAG_ATR;
card_emu_uart_enable(ch->uart_chan, ENABLE_TX); card_emu_uart_enable(ch->uart_chan, ENABLE_TX);
break; /* trigger USART TX IRQ to sent first ATR byte TS */
card_emu_uart_interrupt(ch->uart_chan);
break; break;
case ISO_S_WAIT_TPDU: case ISO_S_WAIT_TPDU:
/* enable the receiver, disable transmitter */ /* enable the receiver, disable transmitter */
set_tpdu_state(ch, TPDU_S_WAIT_CLA); set_tpdu_state(ch, TPDU_S_WAIT_CLA);
card_emu_uart_enable(ch->uart_chan, ENABLE_RX); card_emu_uart_enable(ch->uart_chan, ENABLE_RX);
break; break;
case ISO_S_IN_ATR:
case ISO_S_IN_PTS: case ISO_S_IN_PTS:
case ISO_S_IN_TPDU: case ISO_S_IN_TPDU:
/* do nothing */ /* do nothing */
@@ -332,12 +445,77 @@ static void card_set_state(struct card_handle *ch,
} }
} }
/**********************************************************************
* ATR handling
**********************************************************************/
/*! Transmit ATR data to reader
* @param[in] ch card interface connected to reader
* @return numbers of bytes transmitted
*/
static int tx_byte_atr(struct card_handle *ch)
{
if (NULL == ch) {
TRACE_ERROR("ATR TX: no card handle provided\n\r");
return 0;
}
if (ISO_S_IN_ATR != ch->state) {
TRACE_ERROR("%u: ATR TX: no in ATR state\n\r", ch->num);
return 0;
}
/* Transmit ATR */
if (ch->atr.idx < ch->atr.len) {
uint8_t byte = ch->atr.atr[ch->atr.idx++];
card_emu_uart_tx(ch->uart_chan, byte);
return 1;
} else { /* The ATR has been completely transmitted */
/* search for TC2 to updated WI */
if (ch->atr.len >= 2 && ch->atr.atr[1] & 0xf0) { /* Y1 has some data */
uint8_t atr_td1 = 2;
if (ch->atr.atr[1] & 0x10) { /* TA1 is present */
atr_td1++;
}
if (ch->atr.atr[1] & 0x20) { /* TB1 is present */
atr_td1++;
}
if (ch->atr.atr[1] & 0x40) { /* TC1 is present */
atr_td1++;
}
if (ch->atr.atr[1] & 0x80) { /* TD1 is present */
if (ch->atr.len > atr_td1 && ch->atr.atr[atr_td1] & 0xf0) { /* Y2 has some data */
uint8_t atr_tc2 = atr_td1+1;
if (ch->atr.atr[atr_td1] & 0x10) { /* TA2 is present */
atr_tc2++;
}
if (ch->atr.atr[atr_td1] & 0x20) { /* TB2 is present */
atr_tc2++;
}
if (ch->atr.atr[atr_td1] & 0x40) { /* TC2 is present */
if (ch->atr.len > atr_tc2 && ch->atr.atr[atr_tc2]) { /* TC2 encodes WI */
ch->wi = ch->atr.atr[atr_tc2]; /* set WI */
}
}
}
}
}
/* FIXME update waiting time in case of card is specific mode */
/* reset PTS to initial state */
set_pts_state(ch, PTS_S_WAIT_REQ_PTSS);
/* go to next state */
card_set_state(ch, ISO_S_WAIT_TPDU);
return 0;
}
/* return number of bytes transmitted */
return 1;
}
/********************************************************************** /**********************************************************************
* PTS / PPS handling * PTS / PPS handling
**********************************************************************/ **********************************************************************/
/* Update the ATR sub-state */ /* Update the PTS sub-state */
static void set_pts_state(struct card_handle *ch, enum pts_state new_ptss) static void set_pts_state(struct card_handle *ch, enum pts_state new_ptss)
{ {
TRACE_DEBUG("%u: 7816 PTS state %u -> %u\r\n", TRACE_DEBUG("%u: 7816 PTS state %u -> %u\r\n",
@@ -388,9 +566,12 @@ from_pts3:
return PTS_S_WAIT_REQ_PCK | is_resp; return PTS_S_WAIT_REQ_PCK | is_resp;
} }
/*! process incoming PTS byte
static int * @param[in] ch card handle on which the byte has been received
process_byte_pts(struct card_handle *ch, uint8_t byte) * @param[in] byte received PTS byte
* @return new iso7816_3_card_state or -1 at the end of PTS request
*/
static int process_byte_pts(struct card_handle *ch, uint8_t byte)
{ {
switch (ch->pts.state) { switch (ch->pts.state) {
case PTS_S_WAIT_REQ_PTSS: case PTS_S_WAIT_REQ_PTSS:
@@ -417,7 +598,7 @@ process_byte_pts(struct card_handle *ch, uint8_t byte)
set_pts_state(ch, PTS_S_WAIT_REQ_PTSS); set_pts_state(ch, PTS_S_WAIT_REQ_PTSS);
return ISO_S_WAIT_TPDU; return ISO_S_WAIT_TPDU;
} }
/* FIXME: check if proposal matches capabilities in ATR */ /* FIXME check if proposal matches capabilities in TA1 */
memcpy(ch->pts.resp, ch->pts.req, sizeof(ch->pts.resp)); memcpy(ch->pts.resp, ch->pts.req, sizeof(ch->pts.resp));
break; break;
default: default:
@@ -456,11 +637,17 @@ static int tx_byte_pts(struct card_handle *ch)
break; break;
case PTS_S_WAIT_RESP_PTS1: case PTS_S_WAIT_RESP_PTS1:
byte = ch->pts.resp[_PTS1]; byte = ch->pts.resp[_PTS1];
/* This must be TA1 */ // TODO the value should have been validated when receiving the request
ch->fi = byte >> 4; ch->f = iso7816_3_fi_table[byte >> 4]; // save selected Fn
ch->di = byte & 0xf; if (0 == ch->f) {
TRACE_DEBUG("%u: found Fi=%u Di=%u\r\n", ch->num, TRACE_ERROR("%u: invalid F index in PPS response: %u\r\n", ch->num, byte >> 4);
ch->fi, ch->di); // TODO become unresponsive to signal error condition
}
ch->d = iso7816_3_di_table[byte & 0xf]; // save selected Dn
if (0 == ch->d) {
TRACE_ERROR("%u: invalid D index in PPS response: %u\r\n", ch->num, byte & 0xf);
// TODO become unresponsive to signal error condition
}
break; break;
case PTS_S_WAIT_RESP_PTS2: case PTS_S_WAIT_RESP_PTS2:
byte = ch->pts.resp[_PTS2]; byte = ch->pts.resp[_PTS2];
@@ -485,8 +672,15 @@ static int tx_byte_pts(struct card_handle *ch)
switch (ch->pts.state) { switch (ch->pts.state) {
case PTS_S_WAIT_RESP_PCK: case PTS_S_WAIT_RESP_PCK:
card_emu_uart_wait_tx_idle(ch->uart_chan); card_emu_uart_wait_tx_idle(ch->uart_chan);
/* update baud rate generator with Fi/Di */ card_emu_uart_update_fd(ch->uart_chan, ch->f, ch->d); // set selected baud rate
emu_update_fidi(ch); int32_t wt = iso7816_3_calculate_wt(ch->wi, ch->fi, ch->di, ch->f, ch->d); // get new waiting time
if (wt <= 0) {
TRACE_ERROR("%u: invalid WT calculated: %ld\r\n", ch->num, wt);
// TODO become unresponsive to signal error condition
} else {
ch->wt = wt;
}
// FIXME disable WT
/* Wait for the next TPDU */ /* Wait for the next TPDU */
card_set_state(ch, ISO_S_WAIT_TPDU); card_set_state(ch, ISO_S_WAIT_TPDU);
set_pts_state(ch, PTS_S_WAIT_REQ_PTSS); set_pts_state(ch, PTS_S_WAIT_REQ_PTSS);
@@ -557,22 +751,31 @@ static void set_tpdu_state(struct card_handle *ch, enum tpdu_state new_ts)
{ {
if (ch->tpdu.state == new_ts) if (ch->tpdu.state == new_ts)
return; return;
if (ISO_S_IN_TPDU != ch->state && ISO_S_WAIT_TPDU != ch->state) {
TRACE_ERROR("%u: setting TPDU state in %s state\r\n", ch->num,
get_value_string(iso7816_3_card_state_names, ch->state));
}
TRACE_DEBUG("%u: 7816 TPDU state %u -> %u\r\n", ch->num, TRACE_DEBUG("%u: 7816 TPDU state %s -> %s\r\n", ch->num,
ch->tpdu.state, new_ts); get_value_string(tpdu_state_names, ch->tpdu.state),
get_value_string(tpdu_state_names, new_ts));
ch->tpdu.state = new_ts; ch->tpdu.state = new_ts;
switch (new_ts) { switch (new_ts) {
case TPDU_S_WAIT_CLA: case TPDU_S_WAIT_CLA: // we will be waiting for the next incoming TDPU
case TPDU_S_WAIT_RX: card_emu_uart_enable(ch->uart_chan, ENABLE_RX); // switch back to receiving mode
card_emu_uart_enable(ch->uart_chan, ENABLE_RX); card_emu_uart_update_wt(ch->uart_chan, 0); // disable waiting time since we don't expect any data
break;
case TPDU_S_WAIT_INS: // the reader started sending the TPDU header
card_emu_uart_update_wt(ch->uart_chan, ch->wt); // start waiting for the rest of the header/body
break;
case TPDU_S_WAIT_RX: // the reader should send us the TPDU body data
card_emu_uart_enable(ch->uart_chan, ENABLE_RX); // switch to receive mode to receive the body
card_emu_uart_update_wt(ch->uart_chan, ch->wt); // start waiting for the rest body
break; break;
case TPDU_S_WAIT_PB: case TPDU_S_WAIT_PB:
/* we just completed the TPDU header from reader to card card_emu_uart_enable(ch->uart_chan, ENABLE_TX); // header is completely received, now we need to transmit the procedure byte
* and now need to disable the receiver, enable the card_emu_uart_update_wt(ch->uart_chan, ch->wt); // prepare to extend the waiting time once half of it is reached
* transmitter and transmit the procedure byte */
card_emu_uart_enable(ch->uart_chan, ENABLE_TX);
break; break;
default: default:
break; break;
@@ -718,7 +921,7 @@ static int tx_byte_tpdu(struct card_handle *ch)
card_emu_uart_tx(ch->uart_chan, byte); card_emu_uart_tx(ch->uart_chan, byte);
/* this must happen _after_ the byte has been transmittd */ /* this must happen _after_ the byte has been transmitted */
switch (ch->tpdu.state) { switch (ch->tpdu.state) {
case TPDU_S_WAIT_PB: case TPDU_S_WAIT_PB:
/* if we just transmitted the procedure byte, we need to decide /* if we just transmitted the procedure byte, we need to decide
@@ -765,14 +968,6 @@ void card_emu_process_rx_byte(struct card_handle *ch, uint8_t byte)
ch->stats.rx_bytes++; ch->stats.rx_bytes++;
switch (ch->state) { switch (ch->state) {
case ISO_S_WAIT_POWER:
case ISO_S_WAIT_CLK:
case ISO_S_WAIT_RST:
case ISO_S_WAIT_ATR:
TRACE_ERROR("%u: Received UART char in invalid 7816 state "
"%u\r\n", ch->num, ch->state);
/* we shouldn't receive any data from the reader yet! */
break;
case ISO_S_WAIT_TPDU: case ISO_S_WAIT_TPDU:
if (byte == 0xff) { if (byte == 0xff) {
new_state = process_byte_pts(ch, byte); new_state = process_byte_pts(ch, byte);
@@ -786,6 +981,10 @@ void card_emu_process_rx_byte(struct card_handle *ch, uint8_t byte)
case ISO_S_IN_PTS: case ISO_S_IN_PTS:
new_state = process_byte_pts(ch, byte); new_state = process_byte_pts(ch, byte);
goto out_silent; goto out_silent;
default:
TRACE_ERROR("%u: Received UART char in invalid 7816 state "
"%u\r\n", ch->num, ch->state);
break;
} }
out_silent: out_silent:
@@ -800,17 +999,7 @@ int card_emu_tx_byte(struct card_handle *ch)
switch (ch->state) { switch (ch->state) {
case ISO_S_IN_ATR: case ISO_S_IN_ATR:
if (ch->atr.idx < ch->atr.len) { rc = tx_byte_atr(ch);
uint8_t byte;
byte = ch->atr.atr[ch->atr.idx++];
rc = 1;
card_emu_uart_tx(ch->uart_chan, byte);
/* detect end of ATR */
if (ch->atr.idx >= ch->atr.len)
card_set_state(ch, ISO_S_WAIT_TPDU);
}
break; break;
case ISO_S_IN_PTS: case ISO_S_IN_PTS:
rc = tx_byte_pts(ch); rc = tx_byte_pts(ch);
@@ -865,11 +1054,11 @@ void card_emu_report_status(struct card_handle *ch)
sts->flags |= CEMU_STATUS_F_CLK_ACTIVE; sts->flags |= CEMU_STATUS_F_CLK_ACTIVE;
if (ch->in_reset) if (ch->in_reset)
sts->flags |= CEMU_STATUS_F_RESET_ACTIVE; sts->flags |= CEMU_STATUS_F_RESET_ACTIVE;
/* FIXME: voltage + card insert */ /* FIXME set voltage and card insert values */
sts->fi = ch->fi; sts->f = ch->f;
sts->di = ch->di; sts->d = ch->d;
sts->wi = ch->wi; sts->wi = ch->wi;
sts->waiting_time = ch->waiting_time; sts->wt = ch->wt;
usb_buf_upd_len_and_submit(msg); usb_buf_upd_len_and_submit(msg);
} }
@@ -881,7 +1070,6 @@ void card_emu_io_statechg(struct card_handle *ch, enum card_io io, int active)
case CARD_IO_VCC: case CARD_IO_VCC:
if (active == 0 && ch->vcc_active == 1) { if (active == 0 && ch->vcc_active == 1) {
TRACE_INFO("%u: VCC deactivated\r\n", ch->num); TRACE_INFO("%u: VCC deactivated\r\n", ch->num);
tc_etu_disable(ch->tc_chan);
card_set_state(ch, ISO_S_WAIT_POWER); card_set_state(ch, ISO_S_WAIT_POWER);
} else if (active == 1 && ch->vcc_active == 0) { } else if (active == 1 && ch->vcc_active == 0) {
TRACE_INFO("%u: VCC activated\r\n", ch->num); TRACE_INFO("%u: VCC activated\r\n", ch->num);
@@ -902,19 +1090,18 @@ void card_emu_io_statechg(struct card_handle *ch, enum card_io io, int active)
case CARD_IO_RST: case CARD_IO_RST:
if (active == 0 && ch->in_reset) { if (active == 0 && ch->in_reset) {
TRACE_INFO("%u: RST released\r\n", ch->num); TRACE_INFO("%u: RST released\r\n", ch->num);
if (ch->vcc_active && ch->clocked) { if (ch->vcc_active && ch->clocked && ISO_S_WAIT_RST == ch->state) {
/* enable the TC/ETU counter once reset has been released */ /* prepare to send the ATR */
tc_etu_enable(ch->tc_chan);
card_set_state(ch, ISO_S_WAIT_ATR); card_set_state(ch, ISO_S_WAIT_ATR);
/* FIXME: wait 400 to 40k clock cycles before sending ATR */
card_set_state(ch, ISO_S_IN_ATR);
} }
} else if (active && !ch->in_reset) { } else if (active && !ch->in_reset) {
TRACE_INFO("%u: RST asserted\r\n", ch->num); TRACE_INFO("%u: RST asserted\r\n", ch->num);
tc_etu_disable(ch->tc_chan); card_set_state(ch, ISO_S_WAIT_RST);
} }
ch->in_reset = active; ch->in_reset = active;
break; break;
default:
break;
} }
} }
@@ -924,46 +1111,61 @@ int card_emu_set_atr(struct card_handle *ch, const uint8_t *atr, uint8_t len)
if (len > sizeof(ch->atr.atr)) if (len > sizeof(ch->atr.atr))
return -1; return -1;
/* ignore new ATR for now since we PPS has not been tested
memcpy(ch->atr.atr, atr, len); memcpy(ch->atr.atr, atr, len);
ch->atr.len = len; ch->atr.len = len;
ch->atr.idx = 0; ch->atr.idx = 0;
*/
/* FIXME: race condition with trasmitting ATR to reader? */ #if TRACE_LEVEL >= TRACE_LEVEL_INFO
uint8_t i;
TRACE_INFO("%u: ATR set: ", ch->num);
for (i = 0; i < len; i++) {
TRACE_INFO_WP("%02x ", atr[i]);
}
TRACE_INFO_WP("\n\r");
TRACE_INFO("%u: ATR set currently ignored\n\r", ch->num);
#endif
/* FIXME: race condition with transmitting ATR to reader? */
return 0; return 0;
} }
/* hardware driver informs us that one (more) ETU has expired */ void card_emu_wt_halfed(struct card_handle *ch)
void tc_etu_wtime_half_expired(void *handle)
{ {
struct card_handle *ch = handle;
/* transmit NULL procedure byte well before waiting time expires */
switch (ch->state) { switch (ch->state) {
case ISO_S_IN_TPDU: case ISO_S_IN_TPDU:
switch (ch->tpdu.state) { switch (ch->tpdu.state) {
case TPDU_S_WAIT_PB:
case TPDU_S_WAIT_TX: case TPDU_S_WAIT_TX:
case TPDU_S_WAIT_PB:
putchar('N'); putchar('N');
card_emu_uart_tx(ch->uart_chan, ISO7816_3_PB_NULL); card_emu_uart_tx(ch->uart_chan, ISO7816_3_PB_NULL); // we are waiting for data from the user. send a procedure byte to ask the reader to wait more time
card_emu_uart_reset_wt(ch->uart_chan); // reset WT
break; break;
default: default:
break; break;
} }
break;
default: default:
break; break;
} }
} }
/* hardware driver informs us that one (more) ETU has expired */ void card_emu_wt_expired(struct card_handle *ch)
void tc_etu_wtime_expired(void *handle)
{ {
struct card_handle *ch = handle; switch (ch->state) {
TRACE_ERROR("%u: wtime_exp\r\n", ch->num); case ISO_S_WAIT_ATR:
/* ISO 7816-3 6.2.1 time tc has passed, we can now send the ATR */
card_set_state(ch, ISO_S_IN_ATR);
break;
default:
// TODO become unresponsive
TRACE_ERROR("%u: wtime_exp\r\n", ch->num);
break;
}
} }
/* shortest ATR found in smartcard_list.txt */ /* shortest ATR possible (uses default speed and no options) */
static const uint8_t default_atr[] = { 0x3B, 0x02, 0x14, 0x50 }; static const uint8_t default_atr[] = { 0x3B, 0x00 };
static struct card_handle card_handles[NUM_SLOTS]; static struct card_handle card_handles[NUM_SLOTS];
@@ -981,7 +1183,7 @@ struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uar
INIT_LLIST_HEAD(&ch->uart_tx_queue); INIT_LLIST_HEAD(&ch->uart_tx_queue);
/* initialize the card_handle with reasonabe defaults */ /* initialize the card_handle with reasonable defaults */
ch->num = slot_num; ch->num = slot_num;
ch->irq_ep = irq_ep; ch->irq_ep = irq_ep;
ch->in_ep = in_ep; ch->in_ep = in_ep;
@@ -990,13 +1192,13 @@ struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uar
ch->in_reset = 1; ch->in_reset = 1;
ch->clocked = 0; ch->clocked = 0;
ch->fi = 0; ch->fi = ISO7816_3_DEFAULT_FI;
ch->di = 1; ch->di = ISO7816_3_DEFAULT_DI;
ch->wi = ISO7816_3_DEFAULT_WI; ch->wi = ISO7816_3_DEFAULT_WI;
ch->wt = ISO7816_3_DEFAULT_WT;;
ch->tc_chan = tc_chan; ch->tc_chan = tc_chan;
ch->uart_chan = uart_chan; ch->uart_chan = uart_chan;
ch->waiting_time = ISO7816_3_INIT_WTIME;
ch->atr.idx = 0; ch->atr.idx = 0;
ch->atr.len = sizeof(default_atr); ch->atr.len = sizeof(default_atr);
@@ -1005,7 +1207,5 @@ struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uar
ch->pts.state = PTS_S_WAIT_REQ_PTSS; ch->pts.state = PTS_S_WAIT_REQ_PTSS;
ch->tpdu.state = TPDU_S_WAIT_CLA; ch->tpdu.state = TPDU_S_WAIT_CLA;
tc_etu_init(ch->tc_chan, ch);
return ch; return ch;
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,19 @@
/* UART print output
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdio.h> #include <stdio.h>
#include "uart_console.h" #include "uart_console.h"
@@ -10,6 +26,19 @@ int fputc(int c, FILE *stream)
int fputs(const char *s, FILE *stream) int fputs(const char *s, FILE *stream)
{ {
while (*s != '\0') while (*s != '\0')
UART_PutChar(*s++); fputc(*s++, stream);
return 0;
}
int fputc_sync(int c, FILE *stream)
{
UART_PutChar_Sync(c);
return c;
}
int fputs_sync(const char *s, FILE *stream)
{
while (*s != '\0')
fputc_sync(*s++, stream);
return 0; return 0;
} }

View File

@@ -1,9 +1,26 @@
/* USB communication methods
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#include "board.h" #include "board.h"
#include "llist_irqsafe.h" #include "llist_irqsafe.h"
#include "usb_buf.h" #include "usb_buf.h"
#include "utils.h"
#include "osmocom/core/linuxlist.h" #include <osmocom/core/linuxlist.h>
#include "osmocom/core/msgb.h" #include <osmocom/core/msgb.h>
#include <errno.h> #include <errno.h>
/*********************************************************************** /***********************************************************************
@@ -16,12 +33,13 @@ static void usb_write_cb(uint8_t *arg, uint8_t status, uint32_t transferred,
{ {
struct msgb *msg = (struct msgb *) arg; struct msgb *msg = (struct msgb *) arg;
struct usb_buffered_ep *bep = msg->dst; struct usb_buffered_ep *bep = msg->dst;
unsigned long x;
TRACE_DEBUG("%s (EP=0x%02x)\r\n", __func__, bep->ep); TRACE_DEBUG("%s (EP=0x%02x)\r\n", __func__, bep->ep);
__disable_irq(); local_irq_save(x);
bep->in_progress--; bep->in_progress--;
__enable_irq(); local_irq_restore(x);
TRACE_DEBUG("%u: in_progress=%d\n", bep->ep, bep->in_progress); TRACE_DEBUG("%u: in_progress=%d\n", bep->ep, bep->in_progress);
if (status != USBD_STATUS_SUCCESS) if (status != USBD_STATUS_SUCCESS)
@@ -34,6 +52,7 @@ int usb_refill_to_host(uint8_t ep)
{ {
struct usb_buffered_ep *bep = usb_get_buf_ep(ep); struct usb_buffered_ep *bep = usb_get_buf_ep(ep);
struct msgb *msg; struct msgb *msg;
unsigned long x;
int rc; int rc;
#if 0 #if 0
@@ -43,14 +62,14 @@ int usb_refill_to_host(uint8_t ep)
} }
#endif #endif
__disable_irq(); local_irq_save(x);
if (bep->in_progress) { if (bep->in_progress) {
__enable_irq(); local_irq_restore(x);
return 0; return 0;
} }
if (llist_empty(&bep->queue)) { if (llist_empty(&bep->queue)) {
__enable_irq(); local_irq_restore(x);
return 0; return 0;
} }
@@ -58,7 +77,7 @@ int usb_refill_to_host(uint8_t ep)
msg = msgb_dequeue(&bep->queue); msg = msgb_dequeue(&bep->queue);
__enable_irq(); local_irq_restore(x);
TRACE_DEBUG("%s (EP=0x%02x), in_progress=%d\r\n", __func__, ep, bep->in_progress); TRACE_DEBUG("%s (EP=0x%02x), in_progress=%d\r\n", __func__, ep, bep->in_progress);
@@ -70,9 +89,9 @@ int usb_refill_to_host(uint8_t ep)
TRACE_ERROR("%s error %x\n", __func__, rc); TRACE_ERROR("%s error %x\n", __func__, rc);
/* re-insert to head of queue */ /* re-insert to head of queue */
llist_add_irqsafe(&msg->list, &bep->queue); llist_add_irqsafe(&msg->list, &bep->queue);
__disable_irq(); local_irq_save(x);
bep->in_progress--; bep->in_progress--;
__enable_irq(); local_irq_restore(x);
TRACE_DEBUG("%02x: in_progress=%d\n", bep->ep, bep->in_progress); TRACE_DEBUG("%02x: in_progress=%d\n", bep->ep, bep->in_progress);
return 0; return 0;
} }
@@ -105,6 +124,7 @@ int usb_refill_from_host(uint8_t ep)
{ {
struct usb_buffered_ep *bep = usb_get_buf_ep(ep); struct usb_buffered_ep *bep = usb_get_buf_ep(ep);
struct msgb *msg; struct msgb *msg;
unsigned long x;
int rc; int rc;
#if 0 #if 0
@@ -130,7 +150,7 @@ int usb_refill_from_host(uint8_t ep)
rc = USBD_Read(ep, msg->head, msgb_tailroom(msg), rc = USBD_Read(ep, msg->head, msgb_tailroom(msg),
(TransferCallback) &usb_read_cb, msg); (TransferCallback) &usb_read_cb, msg);
if (rc != USBD_STATUS_SUCCESS) { if (rc != USBD_STATUS_SUCCESS) {
TRACE_ERROR("%s error %s\n", __func__, rc); TRACE_ERROR("%s error %d\n", __func__, rc);
usb_buf_free(msg); usb_buf_free(msg);
bep->in_progress = 0; bep->in_progress = 0;
} }
@@ -142,16 +162,17 @@ int usb_drain_queue(uint8_t ep)
{ {
struct usb_buffered_ep *bep = usb_get_buf_ep(ep); struct usb_buffered_ep *bep = usb_get_buf_ep(ep);
struct msgb *msg; struct msgb *msg;
unsigned long x;
int ret = 0; int ret = 0;
/* wait until no transfers are in progress anymore and block /* wait until no transfers are in progress anymore and block
* further interrupts */ * further interrupts */
while (1) { while (1) {
__disable_irq(); local_irq_save(x);
if (!bep->in_progress) { if (!bep->in_progress) {
break; break;
} }
__enable_irq(); local_irq_restore(x);
/* retry */ /* retry */
} }
@@ -162,7 +183,7 @@ int usb_drain_queue(uint8_t ep)
} }
/* re-enable interrupts and return number of free'd msgbs */ /* re-enable interrupts and return number of free'd msgbs */
__enable_irq(); local_irq_restore(x);
return ret; return ret;
} }

View File

@@ -0,0 +1,123 @@
/*
* Copyright (C) 2019 sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdint.h>
#include <stddef.h>
#include "utils.h"
#include "iso7816_3.h"
const uint16_t iso7816_3_fi_table[16] = {
372, 372, 558, 744, 1116, 1488, 1860, 0,
0, 512, 768, 1024, 1536, 2048, 0, 0
};
const uint32_t iso7816_3_fmax_table[16] = {
4000000, 5000000, 6000000, 8000000, 12000000, 16000000, 20000000, 0,
0, 5000000, 7500000, 10000000, 15000000, 20000000, 0, 0
};
const uint8_t iso7816_3_di_table[16] = {
0, 1, 2, 4, 8, 16, 32, 64,
12, 20, 0, 0, 0, 0, 0, 0,
};
/* all values are based on the Elementary Time Unit (ETU), defined in ISO/IEC 7816-3 section 7.1
* this is the time required to transmit a bit, and is calculated as follows: 1 ETU = (F / D) x (1 / f) where:
* - F is the clock rate conversion integer
* - D is the baud rate adjustment factor
* - f is the clock frequency
* the possible F, f(max), and D values are defined in ISO/IEC 7816-3 table 7 and 8
* - the initial value for F (after reset) is Fd = 372
* - the initial value for D (after reset) is Dd = 1
* - the initial maximum frequency f(max) is 5 MHz
* the card must measure the ETU based on the clock signal provided by the reader
* one ETU (e.g. 1 bit) takes F/D clock cycles, which the card must count
*
* the card can indicate an alternative set of supported values Fi (with corresponding f(max)) and Di for higher baud rate in TA1 in the ATR (see ISO/IEC 7816-3 section 8.3)
* these values are selected according to ISO/IEC 7816-3 section 6.3.1:
* - card in specific mode: they are enforced if TA2 is present (the reader can deactivate the card if it does not support these values)
* - card in negotiable mode:
* -- they can be selected by the reader using the Protocol and Parameters Selection (PPS) procedure
* -- the first offered protocol and default values are used when no PPS is started
*
* PPS is done with Fd and Dd (see ISO/IEC 7816-3 section 9)
* the reader can propose any F and D values between from Fd to Fi, and from Dd to Di (Fi and Di are indicated in TA1)
* the in PPS agreed values F and D are called Fn and Dn and are applied after a successful exchange, corresponding to PPS1_Response bit 5
*
* the F and D values must be provided to the SAM3S USART peripheral (after reset and PPS)
*/
bool iso7816_3_valid_f(uint16_t f)
{
if (0 == f) {
return false;
}
uint8_t i = 0;
for (i = 0; i < ARRAY_SIZE(iso7816_3_fi_table) && iso7816_3_fi_table[i] != f; i++);
return (i < ARRAY_SIZE(iso7816_3_fi_table) && iso7816_3_fi_table[i] == f);
}
bool iso7816_3_valid_d(uint8_t d)
{
if (0 == d) {
return false;
}
uint8_t i = 0;
for (i = 0; i < ARRAY_SIZE(iso7816_3_di_table) && iso7816_3_di_table[i] != d; i++);
return (i < ARRAY_SIZE(iso7816_3_di_table) && iso7816_3_di_table[i] == d);
}
/*
* the ETU is not only used to define the baud rate, but also the Waiting Time (WT) (see ISO/IEC 7816-3 section 8.1)
* when exceeding WT without card response, the reader flags the card as unresponsive, and resets it
* this can be used by the card to indicate errors or unsupported operations
* if the card requires more time to respond, it shall send a procedure byte to restart WT
* WT is calculated as follows (for T=0, see ISO/IEC 7816-3 section 10.2): WT = WI x 960 x (Fi / f(max)) where
* - WI is encoded in TC2 in the ATR (10 if absent)
* - WI does not depend on D/Di (used for the ETU)
* - after reset WT is 9600 ETU
* - WI (e.g. the new WT) is applied when T=0 is used (after 6.3.1), even if Fi is not Fn (this WT extension is important to know for the reader so to have the right timeout)
*/
int32_t iso7816_3_calculate_wt(uint8_t wi, uint16_t fi, uint8_t di, uint16_t f, uint8_t d)
{
// sanity checks
if (0 == wi) {
return -1;
}
if (!iso7816_3_valid_f(fi)) {
return -2;
}
if (!iso7816_3_valid_d(di)) {
return -3;
}
if (!iso7816_3_valid_f(f)) {
return -4;
}
if (!iso7816_3_valid_d(d)) {
return -5;
}
if (f > fi) {
return -6;
}
if (d > di) {
return -7;
}
return wi * 960UL * (fi/f) * (di/d); // calculate timeout value in ETU
}

View File

@@ -76,44 +76,45 @@ struct Usart_info usart_sim = {.base = USART_SIM, .id = ID_USART_SIM, .state = U
*/ */
uint32_t ISO7816_GetChar( uint8_t *pCharToReceive, Usart_info *usart) uint32_t ISO7816_GetChar( uint8_t *pCharToReceive, Usart_info *usart)
{ {
uint32_t status; uint32_t status;
uint32_t timeout=0; uint32_t timeout=0;
Usart *us_base = usart->base; Usart *us_base = usart->base;
uint32_t us_id = usart->id; uint32_t us_id = usart->id;
if( usart->state == USART_SEND ) { if( usart->state == USART_SEND ) {
while((us_base->US_CSR & US_CSR_TXEMPTY) == 0) {} while((us_base->US_CSR & US_CSR_TXEMPTY) == 0) {}
us_base->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK; us_base->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
usart->state = USART_RCV; usart->state = USART_RCV;
} }
/* Wait USART ready for reception */ /* Wait USART ready for reception */
while( ((us_base->US_CSR & US_CSR_RXRDY) == 0) ) { while( ((us_base->US_CSR & US_CSR_RXRDY) == 0) ) {
if(timeout++ > 12000 * (BOARD_MCK/1000000)) { WDT_Restart(WDT);
TRACE_WARNING("TimeOut\n\r"); if(timeout++ > 12000 * (BOARD_MCK/1000000)) {
return( 0 ); TRACE_WARNING("TimeOut\n\r");
} return( 0 );
} }
}
/* At least one complete character has been received and US_RHR has not yet been read. */ /* At least one complete character has been received and US_RHR has not yet been read. */
/* Get a char */ /* Get a char */
*pCharToReceive = ((us_base->US_RHR) & 0xFF); *pCharToReceive = ((us_base->US_RHR) & 0xFF);
status = (us_base->US_CSR&(US_CSR_OVRE|US_CSR_FRAME| status = (us_base->US_CSR&(US_CSR_OVRE|US_CSR_FRAME|
US_CSR_PARE|US_CSR_TIMEOUT|US_CSR_NACK| US_CSR_PARE|US_CSR_TIMEOUT|US_CSR_NACK|
(1<<10))); (1<<10)));
if (status != 0 ) { if (status != 0 ) {
TRACE_DEBUG("R:0x%" PRIX32 "\n\r", status); TRACE_DEBUG("R:0x%" PRIX32 "\n\r", status);
TRACE_DEBUG("R:0x%" PRIX32 "\n\r", us_base->US_CSR); TRACE_DEBUG("R:0x%" PRIX32 "\n\r", us_base->US_CSR);
TRACE_DEBUG("Nb:0x%" PRIX32 "\n\r", us_base->US_NER ); TRACE_DEBUG("Nb:0x%" PRIX32 "\n\r", us_base->US_NER );
us_base->US_CR = US_CR_RSTSTA; us_base->US_CR = US_CR_RSTSTA;
} }
/* Return status */ /* Return status */
return( status ); return( status );
} }
@@ -124,50 +125,50 @@ uint32_t ISO7816_GetChar( uint8_t *pCharToReceive, Usart_info *usart)
*/ */
uint32_t ISO7816_SendChar( uint8_t CharToSend, Usart_info *usart ) uint32_t ISO7816_SendChar( uint8_t CharToSend, Usart_info *usart )
{ {
uint32_t status; uint32_t status;
Usart *us_base = usart->base; Usart *us_base = usart->base;
uint32_t us_id = usart->id; uint32_t us_id = usart->id;
if( usart->state == USART_RCV ) { if( usart->state == USART_RCV ) {
us_base->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK; us_base->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
usart->state = USART_SEND; usart->state = USART_SEND;
} }
/* Wait USART ready for transmit */ /* Wait USART ready for transmit */
int i = 0; int i = 0;
while((us_base->US_CSR & (US_CSR_TXRDY)) == 0) { while((us_base->US_CSR & (US_CSR_TXRDY)) == 0) {
i++; i++;
if (!(i%1000000)) { if (!(i%1000000)) {
printf("s: %x ", us_base->US_CSR); printf("s: %lx ", us_base->US_CSR);
printf("s: %x\r\n", us_base->US_RHR & 0xFF); printf("s: %lx\r\n", us_base->US_RHR & 0xFF);
us_base->US_CR = US_CR_RSTTX; us_base->US_CR = US_CR_RSTTX;
us_base->US_CR = US_CR_RSTRX; us_base->US_CR = US_CR_RSTRX;
} }
} }
/* There is no character in the US_THR */ /* There is no character in the US_THR */
/* Transmit a char */ /* Transmit a char */
us_base->US_THR = CharToSend; us_base->US_THR = CharToSend;
TRACE_ERROR("Sx%02X\r\n", CharToSend); TRACE_ERROR("Sx%02X\r\n", CharToSend);
status = (us_base->US_CSR&(US_CSR_OVRE|US_CSR_FRAME| status = (us_base->US_CSR&(US_CSR_OVRE|US_CSR_FRAME|
US_CSR_PARE|US_CSR_TIMEOUT|US_CSR_NACK| US_CSR_PARE|US_CSR_TIMEOUT|US_CSR_NACK|
(1<<10))); (1<<10)));
if (status != 0 ) { if (status != 0 ) {
TRACE_INFO("******* status: 0x%" PRIX32 " (Overrun: %" PRIX32 TRACE_INFO("******* status: 0x%" PRIX32 " (Overrun: %" PRIX32
", NACK: %" PRIX32 ", Timeout: %" PRIX32 ", underrun: %" PRIX32 ")\n\r", ", NACK: %" PRIX32 ", Timeout: %" PRIX32 ", underrun: %" PRIX32 ")\n\r",
status, ((status & US_CSR_OVRE)>> 5), ((status & US_CSR_NACK) >> 13), status, ((status & US_CSR_OVRE)>> 5), ((status & US_CSR_NACK) >> 13),
((status & US_CSR_TIMEOUT) >> 8), ((status & (1 << 10)) >> 10)); ((status & US_CSR_TIMEOUT) >> 8), ((status & (1 << 10)) >> 10));
TRACE_INFO("E (USART CSR reg):0x%" PRIX32 "\n\r", us_base->US_CSR); TRACE_INFO("E (USART CSR reg):0x%" PRIX32 "\n\r", us_base->US_CSR);
TRACE_INFO("Nb (Number of errors):0x%" PRIX32 "\n\r", us_base->US_NER ); TRACE_INFO("Nb (Number of errors):0x%" PRIX32 "\n\r", us_base->US_NER );
us_base->US_CR = US_CR_RSTSTA; us_base->US_CR = US_CR_RSTSTA;
} }
/* Return status */ /* Return status */
return( status ); return( status );
} }
@@ -176,10 +177,10 @@ uint32_t ISO7816_SendChar( uint8_t CharToSend, Usart_info *usart )
*/ */
static void ISO7816_IccPowerOn( void ) static void ISO7816_IccPowerOn( void )
{ {
/* Set RESET Master Card */ /* Set RESET Master Card */
if (st_pinIso7816RstMC) { if (st_pinIso7816RstMC) {
PIO_Set(st_pinIso7816RstMC); PIO_Set(st_pinIso7816RstMC);
} }
} }
/*---------------------------------------------------------------------------- /*----------------------------------------------------------------------------
@@ -191,10 +192,10 @@ static void ISO7816_IccPowerOn( void )
*/ */
void ISO7816_IccPowerOff( void ) void ISO7816_IccPowerOff( void )
{ {
/* Clear RESET Master Card */ /* Clear RESET Master Card */
if (st_pinIso7816RstMC) { if (st_pinIso7816RstMC) {
PIO_Clear(st_pinIso7816RstMC); PIO_Clear(st_pinIso7816RstMC);
} }
} }
/** /**
@@ -206,159 +207,159 @@ void ISO7816_IccPowerOff( void )
* \return 0 on success, content of US_CSR otherwise * \return 0 on success, content of US_CSR otherwise
*/ */
uint32_t ISO7816_XfrBlockTPDU_T0(const uint8_t *pAPDU, uint32_t ISO7816_XfrBlockTPDU_T0(const uint8_t *pAPDU,
uint8_t *pMessage, uint8_t *pMessage,
uint16_t wLength, uint16_t wLength,
uint16_t *retlen ) uint16_t *retlen )
{ {
uint16_t NeNc; uint16_t NeNc;
uint16_t indexApdu = 4; uint16_t indexApdu = 4;
uint16_t indexMsg = 0; uint16_t indexMsg = 0;
uint8_t SW1 = 0; uint8_t SW1 = 0;
uint8_t procByte; uint8_t procByte;
uint8_t cmdCase; uint8_t cmdCase;
uint32_t status = 0; uint32_t status = 0;
TRACE_INFO("pAPDU[0]=0x%X\n\r",pAPDU[0]); TRACE_INFO("pAPDU[0]=0x%X\n\r",pAPDU[0]);
TRACE_INFO("pAPDU[1]=0x%X\n\r",pAPDU[1]); TRACE_INFO("pAPDU[1]=0x%X\n\r",pAPDU[1]);
TRACE_INFO("pAPDU[2]=0x%X\n\r",pAPDU[2]); TRACE_INFO("pAPDU[2]=0x%X\n\r",pAPDU[2]);
TRACE_INFO("pAPDU[3]=0x%X\n\r",pAPDU[3]); TRACE_INFO("pAPDU[3]=0x%X\n\r",pAPDU[3]);
TRACE_INFO("pAPDU[4]=0x%X\n\r",pAPDU[4]); TRACE_INFO("pAPDU[4]=0x%X\n\r",pAPDU[4]);
TRACE_INFO("pAPDU[5]=0x%X\n\r",pAPDU[5]); TRACE_INFO("pAPDU[5]=0x%X\n\r",pAPDU[5]);
TRACE_INFO("wlength=%d\n\r",wLength); TRACE_INFO("wlength=%d\n\r",wLength);
ISO7816_SendChar( pAPDU[0], &usart_sim ); /* CLA */ ISO7816_SendChar( pAPDU[0], &usart_sim ); /* CLA */
ISO7816_SendChar( pAPDU[1], &usart_sim ); /* INS */ ISO7816_SendChar( pAPDU[1], &usart_sim ); /* INS */
ISO7816_SendChar( pAPDU[2], &usart_sim ); /* P1 */ ISO7816_SendChar( pAPDU[2], &usart_sim ); /* P1 */
ISO7816_SendChar( pAPDU[3], &usart_sim ); /* P2 */ ISO7816_SendChar( pAPDU[3], &usart_sim ); /* P2 */
ISO7816_SendChar( pAPDU[4], &usart_sim ); /* P3 */ ISO7816_SendChar( pAPDU[4], &usart_sim ); /* P3 */
/* Handle the four structures of command APDU */ /* Handle the four structures of command APDU */
indexApdu = 5; indexApdu = 5;
if( wLength == 4 ) { if( wLength == 4 ) {
cmdCase = CASE1; cmdCase = CASE1;
NeNc = 0; NeNc = 0;
} }
else if( wLength == 5) { else if( wLength == 5) {
cmdCase = CASE2; cmdCase = CASE2;
NeNc = pAPDU[4]; /* C5 */ NeNc = pAPDU[4]; /* C5 */
if (NeNc == 0) { if (NeNc == 0) {
NeNc = 256; NeNc = 256;
} }
} }
else if( wLength == 6) { else if( wLength == 6) {
NeNc = pAPDU[4]; /* C5 */ NeNc = pAPDU[4]; /* C5 */
cmdCase = CASE3; cmdCase = CASE3;
} }
else if( wLength == 7) { else if( wLength == 7) {
NeNc = pAPDU[4]; /* C5 */ NeNc = pAPDU[4]; /* C5 */
if( NeNc == 0 ) { if( NeNc == 0 ) {
cmdCase = CASE2; cmdCase = CASE2;
NeNc = (pAPDU[5]<<8)+pAPDU[6]; NeNc = (pAPDU[5]<<8)+pAPDU[6];
} }
else { else {
cmdCase = CASE3; cmdCase = CASE3;
} }
} }
else { else {
NeNc = pAPDU[4]; /* C5 */ NeNc = pAPDU[4]; /* C5 */
if( NeNc == 0 ) { if( NeNc == 0 ) {
cmdCase = CASE3; cmdCase = CASE3;
NeNc = (pAPDU[5]<<8)+pAPDU[6]; NeNc = (pAPDU[5]<<8)+pAPDU[6];
} }
else { else {
cmdCase = CASE3; cmdCase = CASE3;
} }
} }
TRACE_DEBUG("CASE=0x%X NeNc=0x%X\n\r", cmdCase, NeNc); TRACE_DEBUG("CASE=0x%X NeNc=0x%X\n\r", cmdCase, NeNc);
/* Handle Procedure Bytes */ /* Handle Procedure Bytes */
do { do {
status = ISO7816_GetChar(&procByte, &usart_sim); status = ISO7816_GetChar(&procByte, &usart_sim);
if (status != 0) { if (status != 0) {
return status; return status;
} }
TRACE_INFO("procByte: 0x%X\n\r", procByte); TRACE_INFO("procByte: 0x%X\n\r", procByte);
/* Handle NULL */ /* Handle NULL */
if ( procByte == ISO_NULL_VAL ) { if ( procByte == ISO_NULL_VAL ) {
TRACE_INFO("INS\n\r"); TRACE_INFO("INS\n\r");
continue; continue;
} }
/* Handle SW1 */ /* Handle SW1 */
else if ( ((procByte & 0xF0) ==0x60) || ((procByte & 0xF0) ==0x90) ) { else if ( ((procByte & 0xF0) ==0x60) || ((procByte & 0xF0) ==0x90) ) {
TRACE_INFO("SW1\n\r"); TRACE_INFO("SW1\n\r");
SW1 = 1; SW1 = 1;
} }
/* Handle INS */ /* Handle INS */
else if ( pAPDU[1] == procByte) { else if ( pAPDU[1] == procByte) {
TRACE_INFO("HdlINS\n\r"); TRACE_INFO("HdlINS\n\r");
if (cmdCase == CASE2) { if (cmdCase == CASE2) {
/* receive data from card */ /* receive data from card */
do { do {
status = ISO7816_GetChar(&pMessage[indexMsg++], &usart_sim); status = ISO7816_GetChar(&pMessage[indexMsg++], &usart_sim);
} while(( 0 != --NeNc) && (status == 0) ); } while(( 0 != --NeNc) && (status == 0) );
if (status != 0) { if (status != 0) {
return status; return status;
} }
} }
else { else {
/* Send data */ /* Send data */
do { do {
TRACE_INFO("Send %X", pAPDU[indexApdu]); TRACE_INFO("Send %X", pAPDU[indexApdu]);
ISO7816_SendChar(pAPDU[indexApdu++], &usart_sim); ISO7816_SendChar(pAPDU[indexApdu++], &usart_sim);
} while( 0 != --NeNc ); } while( 0 != --NeNc );
} }
} }
/* Handle INS ^ 0xff */ /* Handle INS ^ 0xff */
else else
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-compare" #pragma GCC diagnostic ignored "-Wsign-compare"
if ( pAPDU[1] == (procByte ^ 0xff)) { if ( pAPDU[1] == (procByte ^ 0xff)) {
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
TRACE_INFO("HdlINS+\n\r"); TRACE_INFO("HdlINS+\n\r");
if (cmdCase == CASE2) { if (cmdCase == CASE2) {
/* receive data from card */ /* receive data from card */
status = ISO7816_GetChar(&pMessage[indexMsg++], &usart_sim); status = ISO7816_GetChar(&pMessage[indexMsg++], &usart_sim);
if (status != 0) { if (status != 0) {
return status; return status;
} }
TRACE_INFO("Rcv: 0x%X\n\r", pMessage[indexMsg-1]); TRACE_INFO("Rcv: 0x%X\n\r", pMessage[indexMsg-1]);
} }
else { else {
status = ISO7816_SendChar(pAPDU[indexApdu++], &usart_sim); status = ISO7816_SendChar(pAPDU[indexApdu++], &usart_sim);
if (status != 0) { if (status != 0) {
return status; return status;
} }
} }
NeNc--; NeNc--;
} }
else { else {
/* ?? */ /* ?? */
TRACE_INFO("procByte=0x%X\n\r", procByte); TRACE_INFO("procByte=0x%X\n\r", procByte);
break; break;
} }
} while (NeNc != 0); } while (NeNc != 0);
/* Status Bytes */ /* Status Bytes */
if (SW1 == 0) { if (SW1 == 0) {
status = ISO7816_GetChar(&pMessage[indexMsg++], &usart_sim); /* SW1 */ status = ISO7816_GetChar(&pMessage[indexMsg++], &usart_sim); /* SW1 */
if (status != 0) { if (status != 0) {
return status; return status;
} }
} }
else { else {
pMessage[indexMsg++] = procByte; pMessage[indexMsg++] = procByte;
} }
status = ISO7816_GetChar(&pMessage[indexMsg++], &usart_sim); /* SW2 */ status = ISO7816_GetChar(&pMessage[indexMsg++], &usart_sim); /* SW2 */
if (status != 0) { if (status != 0) {
return status; return status;
} }
TRACE_WARNING("SW1=0x%X, SW2=0x%X\n\r", pMessage[indexMsg-2], pMessage[indexMsg-1]); TRACE_WARNING("SW1=0x%X, SW2=0x%X\n\r", pMessage[indexMsg-2], pMessage[indexMsg-1]);
*retlen = indexMsg; *retlen = indexMsg;
return status; return status;
} }
@@ -367,7 +368,7 @@ uint32_t ISO7816_XfrBlockTPDU_T0(const uint8_t *pAPDU,
*/ */
void ISO7816_Escape( void ) void ISO7816_Escape( void )
{ {
TRACE_DEBUG("For user, if needed\n\r"); TRACE_DEBUG("For user, if needed\n\r");
} }
/** /**
@@ -375,8 +376,8 @@ void ISO7816_Escape( void )
*/ */
void ISO7816_RestartClock( void ) void ISO7816_RestartClock( void )
{ {
TRACE_DEBUG("ISO7816_RestartClock\n\r"); TRACE_DEBUG("ISO7816_RestartClock\n\r");
USART_SIM->US_BRGR = 13; USART_SIM->US_BRGR = 13;
} }
/** /**
@@ -384,8 +385,8 @@ void ISO7816_RestartClock( void )
*/ */
void ISO7816_StopClock( void ) void ISO7816_StopClock( void )
{ {
TRACE_DEBUG("ISO7816_StopClock\n\r"); TRACE_DEBUG("ISO7816_StopClock\n\r");
USART_SIM->US_BRGR = 0; USART_SIM->US_BRGR = 0;
} }
/** /**
@@ -393,8 +394,8 @@ void ISO7816_StopClock( void )
*/ */
void ISO7816_toAPDU( void ) void ISO7816_toAPDU( void )
{ {
TRACE_DEBUG("ISO7816_toAPDU\n\r"); TRACE_DEBUG("ISO7816_toAPDU\n\r");
TRACE_DEBUG("Not supported at this time\n\r"); TRACE_DEBUG("Not supported at this time\n\r");
} }
/** /**
@@ -405,64 +406,64 @@ void ISO7816_toAPDU( void )
*/ */
uint32_t ISO7816_Datablock_ATR( uint8_t* pAtr, uint8_t* pLength ) uint32_t ISO7816_Datablock_ATR( uint8_t* pAtr, uint8_t* pLength )
{ {
uint32_t i; uint32_t i;
uint32_t j; uint32_t j;
uint32_t y; uint32_t y;
uint32_t status = 0; uint32_t status = 0;
*pLength = 0; *pLength = 0;
/* Read ATR TS */ /* Read ATR TS */
// FIXME: There should always be a check for the GetChar return value..0 means timeout // FIXME: There should always be a check for the GetChar return value..0 means timeout
status = ISO7816_GetChar(&pAtr[0], &usart_sim); status = ISO7816_GetChar(&pAtr[0], &usart_sim);
if (status != 0) { if (status != 0) {
return status; return status;
} }
/* Read ATR T0 */ /* Read ATR T0 */
status = ISO7816_GetChar(&pAtr[1], &usart_sim); status = ISO7816_GetChar(&pAtr[1], &usart_sim);
if (status != 0) { if (status != 0) {
return status; return status;
} }
y = pAtr[1] & 0xF0; y = pAtr[1] & 0xF0;
i = 2; i = 2;
/* Read ATR Ti */ /* Read ATR Ti */
while (y && (status == 0)) { while (y && (status == 0)) {
if (y & 0x10) { /* TA[i] */ if (y & 0x10) { /* TA[i] */
status = ISO7816_GetChar(&pAtr[i++], &usart_sim); status = ISO7816_GetChar(&pAtr[i++], &usart_sim);
} }
if (y & 0x20) { /* TB[i] */ if (y & 0x20) { /* TB[i] */
status = ISO7816_GetChar(&pAtr[i++], &usart_sim); status = ISO7816_GetChar(&pAtr[i++], &usart_sim);
} }
if (y & 0x40) { /* TC[i] */ if (y & 0x40) { /* TC[i] */
status = ISO7816_GetChar(&pAtr[i++], &usart_sim); status = ISO7816_GetChar(&pAtr[i++], &usart_sim);
} }
if (y & 0x80) { /* TD[i] */ if (y & 0x80) { /* TD[i] */
status = ISO7816_GetChar(&pAtr[i], &usart_sim); status = ISO7816_GetChar(&pAtr[i], &usart_sim);
y = pAtr[i++] & 0xF0; y = pAtr[i++] & 0xF0;
} }
else { else {
y = 0; y = 0;
} }
} }
if (status != 0) { if (status != 0) {
return status; return status;
} }
/* Historical Bytes */ /* Historical Bytes */
y = pAtr[1] & 0x0F; y = pAtr[1] & 0x0F;
for( j=0; (j < y) && (status == 0); j++ ) { for( j=0; (j < y) && (status == 0); j++ ) {
status = ISO7816_GetChar(&pAtr[i++], &usart_sim); status = ISO7816_GetChar(&pAtr[i++], &usart_sim);
} }
if (status != 0) { if (status != 0) {
return status; return status;
} }
*pLength = i; *pLength = i;
return status; return status;
} }
/** /**
@@ -472,18 +473,18 @@ uint32_t ISO7816_Datablock_ATR( uint8_t* pAtr, uint8_t* pLength )
*/ */
void ISO7816_SetDataRateandClockFrequency( uint32_t dwClockFrequency, uint32_t dwDataRate ) void ISO7816_SetDataRateandClockFrequency( uint32_t dwClockFrequency, uint32_t dwDataRate )
{ {
uint8_t ClockFrequency; uint8_t ClockFrequency;
/* Define the baud rate divisor register */ /* Define the baud rate divisor register */
/* CD = MCK / SCK */ /* CD = MCK / SCK */
/* SCK = FIDI x BAUD = 372 x 9600 */ /* SCK = FIDI x BAUD = 372 x 9600 */
/* BOARD_MCK */ /* BOARD_MCK */
/* CD = MCK/(FIDI x BAUD) = 48000000 / (372x9600) = 13 */ /* CD = MCK/(FIDI x BAUD) = 48000000 / (372x9600) = 13 */
USART_SIM->US_BRGR = BOARD_MCK / (dwClockFrequency*1000); USART_SIM->US_BRGR = BOARD_MCK / (dwClockFrequency*1000);
ClockFrequency = BOARD_MCK / USART_SIM->US_BRGR; ClockFrequency = BOARD_MCK / USART_SIM->US_BRGR;
USART_SIM->US_FIDI = (ClockFrequency)/dwDataRate; USART_SIM->US_FIDI = (ClockFrequency)/dwDataRate;
} }
@@ -493,10 +494,10 @@ void ISO7816_SetDataRateandClockFrequency( uint32_t dwClockFrequency, uint32_t d
*/ */
uint8_t ISO7816_StatusReset( void ) uint8_t ISO7816_StatusReset( void )
{ {
if (st_pinIso7816RstMC) { if (st_pinIso7816RstMC) {
return PIO_Get(st_pinIso7816RstMC); return PIO_Get(st_pinIso7816RstMC);
} }
return 0; return 0;
} }
/** /**
@@ -504,16 +505,16 @@ uint8_t ISO7816_StatusReset( void )
*/ */
void ISO7816_cold_reset( void ) void ISO7816_cold_reset( void )
{ {
volatile uint32_t i; volatile uint32_t i;
/* tb: wait ??? cycles*/ /* tb: wait ??? cycles*/
for( i=0; i<(400*(BOARD_MCK/1000000)); i++ ) { for( i=0; i<(400*(BOARD_MCK/1000000)); i++ ) {
} }
USART_SIM->US_RHR; USART_SIM->US_RHR;
USART_SIM->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK; USART_SIM->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
ISO7816_IccPowerOn(); ISO7816_IccPowerOn();
} }
/** /**
@@ -521,20 +522,20 @@ void ISO7816_cold_reset( void )
*/ */
void ISO7816_warm_reset( void ) void ISO7816_warm_reset( void )
{ {
volatile uint32_t i; volatile uint32_t i;
// Clears Reset // Clears Reset
ISO7816_IccPowerOff(); ISO7816_IccPowerOff();
/* tb: wait ??? cycles */ /* tb: wait ??? cycles */
for( i=0; i<(400*(BOARD_MCK/1000000)); i++ ) { for( i=0; i<(400*(BOARD_MCK/1000000)); i++ ) {
} }
USART_SIM->US_RHR; USART_SIM->US_RHR;
USART_SIM->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK; USART_SIM->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
// Sets Reset // Sets Reset
ISO7816_IccPowerOn(); ISO7816_IccPowerOn();
} }
/** /**
@@ -543,99 +544,99 @@ void ISO7816_warm_reset( void )
*/ */
void ISO7816_Decode_ATR( uint8_t* pAtr ) void ISO7816_Decode_ATR( uint8_t* pAtr )
{ {
uint32_t i; uint32_t i;
uint32_t j; uint32_t j;
uint32_t y; uint32_t y;
uint8_t offset; uint8_t offset;
printf("\n\r"); printf("\n\r");
printf("ATR: Answer To Reset:\n\r"); printf("ATR: Answer To Reset:\n\r");
printf("TS = 0x%X Initial character ",pAtr[0]); printf("TS = 0x%X Initial character ",pAtr[0]);
if( pAtr[0] == 0x3B ) { if( pAtr[0] == 0x3B ) {
printf("Direct Convention\n\r"); printf("Direct Convention\n\r");
} }
else { else {
if( pAtr[0] == 0x3F ) { if( pAtr[0] == 0x3F ) {
printf("Inverse Convention\n\r"); printf("Inverse Convention\n\r");
} }
else { else {
printf("BAD Convention\n\r"); printf("BAD Convention\n\r");
} }
} }
printf("T0 = 0x%X Format caracter\n\r",pAtr[1]); printf("T0 = 0x%X Format caracter\n\r",pAtr[1]);
printf(" Number of historical bytes: K = %d\n\r", pAtr[1]&0x0F); printf(" Number of historical bytes: K = %d\n\r", pAtr[1]&0x0F);
printf(" Presence further interface byte:\n\r"); printf(" Presence further interface byte:\n\r");
if( pAtr[1]&0x80 ) { if( pAtr[1]&0x80 ) {
printf("TA "); printf("TA ");
} }
if( pAtr[1]&0x40 ) { if( pAtr[1]&0x40 ) {
printf("TB "); printf("TB ");
} }
if( pAtr[1]&0x20 ) { if( pAtr[1]&0x20 ) {
printf("TC "); printf("TC ");
} }
if( pAtr[1]&0x10 ) { if( pAtr[1]&0x10 ) {
printf("TD "); printf("TD ");
} }
if( pAtr[1] != 0 ) { if( pAtr[1] != 0 ) {
printf(" present\n\r"); printf(" present\n\r");
} }
i = 2; i = 2;
y = pAtr[1] & 0xF0; y = pAtr[1] & 0xF0;
/* Read ATR Ti */ /* Read ATR Ti */
offset = 1; offset = 1;
while (y) { while (y) {
if (y & 0x10) { /* TA[i] */ if (y & 0x10) { /* TA[i] */
printf("TA[%d] = 0x%X ", offset, pAtr[i]); printf("TA[%d] = 0x%X ", offset, pAtr[i]);
if( offset == 1 ) { if( offset == 1 ) {
printf("FI = %d ", (pAtr[i]>>8)); printf("FI = %d ", (pAtr[i]>>8));
printf("DI = %d", (pAtr[i]&0x0F)); printf("DI = %d", (pAtr[i]&0x0F));
} }
printf("\n\r"); printf("\n\r");
i++; i++;
} }
if (y & 0x20) { /* TB[i] */ if (y & 0x20) { /* TB[i] */
printf("TB[%d] = 0x%X\n\r", offset, pAtr[i]); printf("TB[%d] = 0x%X\n\r", offset, pAtr[i]);
i++; i++;
} }
if (y & 0x40) { /* TC[i] */ if (y & 0x40) { /* TC[i] */
printf("TC[%d] = 0x%X ", offset, pAtr[i]); printf("TC[%d] = 0x%X ", offset, pAtr[i]);
if( offset == 1 ) { if( offset == 1 ) {
printf("Extra Guard Time: N = %d", pAtr[i]); printf("Extra Guard Time: N = %d", pAtr[i]);
} }
printf("\n\r"); printf("\n\r");
i++; i++;
} }
if (y & 0x80) { /* TD[i] */ if (y & 0x80) { /* TD[i] */
printf("TD[%d] = 0x%X\n\r", offset, pAtr[i]); printf("TD[%d] = 0x%X\n\r", offset, pAtr[i]);
y = pAtr[i++] & 0xF0; y = pAtr[i++] & 0xF0;
} }
else { else {
y = 0; y = 0;
} }
offset++; offset++;
} }
/* Historical Bytes */ /* Historical Bytes */
printf("Historical bytes:\n\r"); printf("Historical bytes:\n\r");
y = pAtr[1] & 0x0F; y = pAtr[1] & 0x0F;
for( j=0; j < y; j++ ) { for( j=0; j < y; j++ ) {
printf(" 0x%X", pAtr[i]); printf(" 0x%X", pAtr[i]);
i++; i++;
} }
printf("\n\r\n\r"); printf("\n\r\n\r");
} }
void ISO7816_Set_Reset_Pin(const Pin *pPinIso7816RstMC) { void ISO7816_Set_Reset_Pin(const Pin *pPinIso7816RstMC) {
/* Pin ISO7816 initialize */ /* Pin ISO7816 initialize */
st_pinIso7816RstMC = (Pin *)pPinIso7816RstMC; st_pinIso7816RstMC = (Pin *)pPinIso7816RstMC;
} }
/** Initializes a ISO driver /** Initializes a ISO driver
@@ -643,46 +644,46 @@ void ISO7816_Set_Reset_Pin(const Pin *pPinIso7816RstMC) {
*/ */
void ISO7816_Init( Usart_info *usart, bool master_clock ) void ISO7816_Init( Usart_info *usart, bool master_clock )
{ {
uint32_t clk; uint32_t clk;
TRACE_DEBUG("ISO_Init\n\r"); TRACE_DEBUG("ISO_Init\n\r");
Usart *us_base = usart->base; Usart *us_base = usart->base;
uint32_t us_id = usart->id; uint32_t us_id = usart->id;
if (master_clock == true) { if (master_clock == true) {
clk = US_MR_USCLKS_MCK; clk = US_MR_USCLKS_MCK;
} else { } else {
clk = US_MR_USCLKS_SCK; clk = US_MR_USCLKS_SCK;
} }
USART_Configure( us_base, USART_Configure( us_base,
US_MR_USART_MODE_IS07816_T_0 US_MR_USART_MODE_IS07816_T_0
| clk | clk
| US_MR_NBSTOP_1_BIT | US_MR_NBSTOP_1_BIT
| US_MR_PAR_EVEN | US_MR_PAR_EVEN
| US_MR_CHRL_8_BIT | US_MR_CHRL_8_BIT
| US_MR_CLKO | US_MR_CLKO
| US_MR_INACK /* Inhibit errors */ | US_MR_INACK /* Inhibit errors */
| (3<<24), /* MAX_ITERATION */ | (3<<24), /* MAX_ITERATION */
1, 1,
0); 0);
/* Disable interrupts */ /* Disable interrupts */
us_base->US_IDR = (uint32_t) -1; us_base->US_IDR = (uint32_t) -1;
/* Configure USART */ /* Configure USART */
PMC_EnablePeripheral(us_id); PMC_EnablePeripheral(us_id);
us_base->US_FIDI = 372; /* by default */ us_base->US_FIDI = 372; /* by default */
/* Define the baud rate divisor register */ /* Define the baud rate divisor register */
/* CD = MCK / SCK */ /* CD = MCK / SCK */
/* SCK = FIDI x BAUD = 372 x 9600 */ /* SCK = FIDI x BAUD = 372 x 9600 */
/* BOARD_MCK */ /* BOARD_MCK */
/* CD = MCK/(FIDI x BAUD) = 48000000 / (372x9600) = 13 */ /* CD = MCK/(FIDI x BAUD) = 48000000 / (372x9600) = 13 */
if (master_clock == true) { if (master_clock == true) {
us_base->US_BRGR = BOARD_MCK / (372*9600); us_base->US_BRGR = BOARD_MCK / (372*9600);
} else { } else {
us_base->US_BRGR = US_BRGR_CD(1); us_base->US_BRGR = US_BRGR_CD(1);
} }
} }

View File

@@ -1,22 +1,21 @@
/* ISO7816-3 Fi/Di tables + computation */ /* ISO7816-3 Fi/Di tables + computation
/* (C) 2010-2015 by Harald Welte <hwelte@hmw-consulting.de>
* *
* This program is free software; you can redistribute it and/or modify * (C) 2010-2015 by Harald Welte <laforge@gnumonks.org>
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is free software; you can redistribute it and/or modify
* but WITHOUT ANY WARRANTY; without even the implied warranty of * it under the terms of the GNU General Public License as published by
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * the Free Software Foundation; either version 2 of the License, or
* GNU General Public License for more details. * (at your option) any later version.
* *
* You should have received a copy of the GNU General Public License * This program is distributed in the hope that it will be useful,
* along with this program; if not, write to the Free Software * but WITHOUT ANY WARRANTY; without even the implied warranty of
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/ */
#include <stdint.h> #include <stdint.h>
#include <errno.h> #include <errno.h>
@@ -24,13 +23,13 @@
#include "iso7816_fidi.h" #include "iso7816_fidi.h"
/* Table 7 of ISO 7816-3:2006 */ /* Table 7 of ISO 7816-3:2006 */
static const uint16_t fi_table[] = { const uint16_t fi_table[] = {
372, 372, 558, 744, 1116, 1488, 1860, 0, 372, 372, 558, 744, 1116, 1488, 1860, 0,
0, 512, 768, 1024, 1536, 2048, 0, 0 0, 512, 768, 1024, 1536, 2048, 0, 0
}; };
/* Table 8 from ISO 7816-3:2006 */ /* Table 8 from ISO 7816-3:2006 */
static const uint8_t di_table[] = { const uint8_t di_table[] = {
0, 1, 2, 4, 8, 16, 32, 64, 0, 1, 2, 4, 8, 16, 32, 64,
12, 20, 2, 4, 8, 16, 32, 64, 12, 20, 2, 4, 8, 16, 32, 64,
}; };

View File

@@ -1,17 +1,35 @@
//#define TRACE_LEVEL 6 /* card emulation mode
*
* (C) 2015-2017 by Harald Welte <laforge@gnumonks.org>
* (C) 2018-2019 by sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#include "board.h" #include "board.h"
#include "boardver_adc.h"
#include "simtrace.h" #include "simtrace.h"
#include "ringbuffer.h" #include "ringbuffer.h"
#include "card_emu.h" #include "card_emu.h"
#include "iso7816_fidi.h" #include "iso7816_3.h"
#include "utils.h" #include "utils.h"
#include "osmocom/core/linuxlist.h" #include <osmocom/core/linuxlist.h>
#include "osmocom/core/msgb.h" #include <osmocom/core/msgb.h>
#include "llist_irqsafe.h" #include "llist_irqsafe.h"
#include "usb_buf.h" #include "usb_buf.h"
#include "simtrace_usb.h"
#include "simtrace_prot.h" #include "simtrace_prot.h"
#include "wwan_perst.h"
#include "sim_switch.h" #include "sim_switch.h"
#define TRACE_ENTRY() TRACE_DEBUG("%s entering\r\n", __func__) #define TRACE_ENTRY() TRACE_DEBUG("%s entering\r\n", __func__)
@@ -32,15 +50,19 @@ static const Pin pin_usim2_vcc = PIN_USIM2_VCC;
#endif #endif
struct cardem_inst { struct cardem_inst {
uint32_t num; unsigned int num;
struct card_handle *ch; struct card_handle *ch;
struct llist_head usb_out_queue; struct llist_head usb_out_queue;
struct ringbuf rb; struct ringbuf rb;
uint32_t wt; /*!< receiver waiting time to trigger timeout (0 to deactivate it) */
uint32_t wt_remaining; /*!< remaining waiting time */
bool wt_halfed; /*!< if at least half of the waiting time passed */
struct Usart_info usart_info; struct Usart_info usart_info;
int usb_pending_old; int usb_pending_old;
uint8_t ep_out; uint8_t ep_out;
uint8_t ep_in; uint8_t ep_in;
uint8_t ep_int; uint8_t ep_int;
const Pin pin_io;
const Pin pin_insert; const Pin pin_insert;
uint32_t vcc_uv; uint32_t vcc_uv;
uint32_t vcc_uv_last; uint32_t vcc_uv_last;
@@ -54,9 +76,10 @@ struct cardem_inst cardem_inst[] = {
.id = ID_USART1, .id = ID_USART1,
.state = USART_RCV .state = USART_RCV
}, },
.ep_out = PHONE_DATAOUT, .ep_out = SIMTRACE_CARDEM_USB_EP_USIM1_DATAOUT,
.ep_in = PHONE_DATAIN, .ep_in = SIMTRACE_CARDEM_USB_EP_USIM1_DATAIN,
.ep_int = PHONE_INT, .ep_int = SIMTRACE_CARDEM_USB_EP_USIM1_INT,
.pin_io = PIN_USIM1_IO,
#ifdef PIN_SET_USIM1_PRES #ifdef PIN_SET_USIM1_PRES
.pin_insert = PIN_SET_USIM1_PRES, .pin_insert = PIN_SET_USIM1_PRES,
#endif #endif
@@ -69,9 +92,10 @@ struct cardem_inst cardem_inst[] = {
.id = ID_USART0, .id = ID_USART0,
.state = USART_RCV .state = USART_RCV
}, },
.ep_out = CARDEM_USIM2_DATAOUT, .ep_out = SIMTRACE_CARDEM_USB_EP_USIM2_DATAOUT,
.ep_in = CARDEM_USIM2_DATAIN, .ep_in = SIMTRACE_CARDEM_USB_EP_USIM2_DATAIN,
.ep_int = CARDEM_USIM2_INT, .ep_int = SIMTRACE_CARDEM_USB_EP_USIM2_INT,
.pin_io = PIN_USIM2_IO,
#ifdef PIN_SET_USIM2_PRES #ifdef PIN_SET_USIM2_PRES
.pin_insert = PIN_SET_USIM2_PRES, .pin_insert = PIN_SET_USIM2_PRES,
#endif #endif
@@ -81,15 +105,11 @@ struct cardem_inst cardem_inst[] = {
static Usart *get_usart_by_chan(uint8_t uart_chan) static Usart *get_usart_by_chan(uint8_t uart_chan)
{ {
switch (uart_chan) { if (uart_chan < ARRAY_SIZE(cardem_inst)) {
case 0: return cardem_inst[uart_chan].usart_info.base;
return USART1; } else {
#ifdef CARDEMU_SECOND_UART return NULL;
case 1:
return USART0;
#endif
} }
return NULL;
} }
/*********************************************************************** /***********************************************************************
@@ -103,7 +123,7 @@ static void wait_tx_idle(Usart *usart)
/* wait until last char has been fully transmitted */ /* wait until last char has been fully transmitted */
while ((usart->US_CSR & (US_CSR_TXEMPTY)) == 0) { while ((usart->US_CSR & (US_CSR_TXEMPTY)) == 0) {
if (!(i%1000000)) { if (!(i%1000000)) {
TRACE_ERROR("s: %x \r\n", usart->US_CSR); TRACE_ERROR("s: %lx \r\n", usart->US_CSR);
} }
i++; i++;
} }
@@ -126,7 +146,7 @@ void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx)
* receiver enabled during transmit */ * receiver enabled during transmit */
USART_SetReceiverEnabled(usart, 1); USART_SetReceiverEnabled(usart, 1);
usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK; usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
USART_EnableIt(usart, US_IER_TXRDY); USART_EnableIt(usart, US_IER_TXRDY | US_IER_TIMEOUT);
USART_SetTransmitterEnabled(usart, 1); USART_SetTransmitterEnabled(usart, 1);
break; break;
case ENABLE_RX: case ENABLE_RX:
@@ -136,7 +156,7 @@ void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx)
USART_SetTransmitterEnabled(usart, 1); USART_SetTransmitterEnabled(usart, 1);
wait_tx_idle(usart); wait_tx_idle(usart);
usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK; usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
USART_EnableIt(usart, US_IER_RXRDY); USART_EnableIt(usart, US_IER_RXRDY | US_IER_TIMEOUT);
USART_SetReceiverEnabled(usart, 1); USART_SetReceiverEnabled(usart, 1);
break; break;
case 0: case 0:
@@ -160,7 +180,7 @@ int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte)
int i = 1; int i = 1;
while ((usart->US_CSR & (US_CSR_TXRDY)) == 0) { while ((usart->US_CSR & (US_CSR_TXRDY)) == 0) {
if (!(i%1000000)) { if (!(i%1000000)) {
TRACE_ERROR("%u: s: %x %02X\r\n", TRACE_ERROR("%u: s: %lx %02lX\r\n",
uart_chan, usart->US_CSR, uart_chan, usart->US_CSR,
usart->US_RHR & 0xFF); usart->US_RHR & 0xFF);
usart->US_CR = US_CR_RSTTX; usart->US_CR = US_CR_RSTTX;
@@ -174,56 +194,171 @@ int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte)
return 1; return 1;
} }
/* FIXME: integrate this with actual irq handler */ /* FIXME: integrate this with actual irq handler */
static void usart_irq_rx(uint8_t inst_num) static void usart_irq_rx(uint8_t inst_num)
{ {
if (inst_num >= ARRAY_SIZE(cardem_inst)) {
TRACE_ERROR("%u: UART channel out of bounds\r\n", inst_num);
return;
}
Usart *usart = get_usart_by_chan(inst_num); Usart *usart = get_usart_by_chan(inst_num);
struct cardem_inst *ci = &cardem_inst[inst_num]; struct cardem_inst *ci = &cardem_inst[inst_num];
uint32_t csr; uint32_t csr;
uint8_t byte = 0; uint8_t byte = 0;
csr = usart->US_CSR & usart->US_IMR; csr = usart->US_CSR & usart->US_IMR; // save state/flags before they get changed
if (csr & US_CSR_RXRDY) { if (csr & US_CSR_RXRDY) { // bytes has been received
byte = (usart->US_RHR) & 0xFF; byte = (usart->US_RHR) & 0xFF; // ready out byte
rbuf_write(&ci->rb, byte); if (rbuf_write(&ci->rb, byte) < 0) // store byte in buffer
TRACE_ERROR("rbuf overrun\r\n"); // error if could not store in buffer
} }
if (csr & US_CSR_TXRDY) { if (csr & US_CSR_TXRDY) { // ready to transmit the next byte
if (card_emu_tx_byte(ci->ch) == 0) if (card_emu_tx_byte(ci->ch) == 0) // transmit next byte, and check if a byte is being transmitted
USART_DisableIt(usart, US_IER_TXRDY); USART_DisableIt(usart, US_IER_TXRDY); // stop the TX ready signal if not byte has been transmitted
} }
if (csr & (US_CSR_OVRE|US_CSR_FRAME|US_CSR_PARE| if (csr & (US_CSR_OVRE | US_CSR_FRAME | US_CSR_PARE | US_CSR_NACK | (1 << 10))) { // error flag set
US_CSR_TIMEOUT|US_CSR_NACK|(1<<10))) { usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK; // reset UART state to clear flag
usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK; TRACE_ERROR("%u USART error on 0x%x status: 0x%lx\n", ci->num, byte, csr); // warn user about error
TRACE_ERROR("%u e 0x%x st: 0x%x\n", ci->num, byte, csr); }
// handle timeout
if (csr & US_CSR_TIMEOUT) { // RX has been inactive for some time
if (ci->wt_remaining <= (usart->US_RTOR & 0xffff)) { // waiting time has passed
ci->wt_remaining = 0; // timeout reached (will stop the timer)
} else {
ci->wt_remaining -= (usart->US_RTOR & 0xffff); // be sure to subtract the actual timeout since the new might not have been set and reloaded yet
}
if (0 == ci->wt_remaining) {
card_emu_wt_expired(ci->ch); // let the state know WT has expired
} else if (ci->wt_remaining <= ci->wt / 2 && !ci->wt_halfed) {
ci->wt_halfed = true;
card_emu_wt_halfed(ci->ch); // let the state know WT has half expired
}
if (ci->wt_remaining > 0xffff) { // value exceeds the USART TO range
usart->US_RTOR = 0xffff; // use the MAX
} else {
usart->US_RTOR = ci->wt_remaining;
}
usart->US_CR |= US_CR_STTTO; // clear timeout flag (and stop timeout until next character is received)
usart->US_CR |= US_CR_RETTO; // restart the counter (it wt is 0, the timeout is not started)
} }
} }
/*! ISR called for USART0 */
void mode_cardemu_usart0_irq(void) void mode_cardemu_usart0_irq(void)
{ {
/* USART0 == Instance 1 == USIM 2 */ /* USART0 == Instance 1 == USIM 2 */
usart_irq_rx(1); usart_irq_rx(1);
} }
/*! ISR called for USART1 */
void mode_cardemu_usart1_irq(void) void mode_cardemu_usart1_irq(void)
{ {
/* USART1 == Instance 0 == USIM 1 */ /* USART1 == Instance 0 == USIM 1 */
usart_irq_rx(0); usart_irq_rx(0);
} }
/* call-back from card_emu.c to change UART baud rate */ // call-back from card_emu.c to change UART baud rate
int card_emu_uart_update_fidi(uint8_t uart_chan, unsigned int fidi)
{
int rc;
Usart *usart = get_usart_by_chan(uart_chan);
usart->US_CR |= US_CR_RXDIS | US_CR_RSTRX; void card_emu_uart_update_fd(uint8_t uart_chan, uint16_t f, uint8_t d)
usart->US_FIDI = fidi & 0x3ff; {
usart->US_CR |= US_CR_RXEN | US_CR_STTTO; Usart *usart = get_usart_by_chan(uart_chan); // get the USART based on the card handle
return 0; if (NULL == usart) {
TRACE_ERROR("%u: USART not found by chan\r\n", uart_chan);
return;
}
if (!iso7816_3_valid_f(f)) {
TRACE_ERROR("%u: invalid F: %u\r\n", uart_chan, f);
return;
}
if (!iso7816_3_valid_d(d)) {
TRACE_ERROR("%u: invalid D: %u\r\n", uart_chan, d);
return;
}
uint16_t ratio = f / d;
if (ratio > 0 && ratio < 2048) {
/* make sure USART uses new F/D ratio */
usart->US_CR |= US_CR_RXDIS | US_CR_RSTRX; // disable USART before changing baud rate
usart->US_FIDI = (ratio & 0x7ff); // change baud rate (ratio)
usart->US_CR |= US_CR_RXEN | US_CR_STTTO; // re-enable USART (and stop timeout)
TRACE_INFO("%u: USART F/D set to %u/%u\r\n", uart_chan, f, d);
} else {
TRACE_ERROR("%u: USART could not set F/D to %u/%u\r\n", uart_chan, f, d);
// TODO become unresponsive
}
}
void card_emu_uart_update_wt(uint8_t uart_chan, uint32_t wt)
{
if (uart_chan >= ARRAY_SIZE(cardem_inst)) {
TRACE_ERROR("%u: UART channel out of bounds\r\n", uart_chan);
return;
}
struct cardem_inst *ci = &cardem_inst[uart_chan];
Usart *usart = get_usart_by_chan(uart_chan); // get the USART based on the card handle
if (NULL == usart) {
TRACE_ERROR("%u: USART not found by chan\r\n", uart_chan);
return;
}
ci->wt = wt; // save value
card_emu_uart_reset_wt(uart_chan); // reset and start timer
TRACE_INFO("%u: USART WT set to %lu ETU\r\n", uart_chan, wt);
}
void card_emu_uart_reset_wt(uint8_t uart_chan)
{
if (uart_chan >= ARRAY_SIZE(cardem_inst)) {
TRACE_ERROR("%u: UART channel out of bounds\r\n", uart_chan);
return;
}
struct cardem_inst *ci = &cardem_inst[uart_chan];
Usart *usart = get_usart_by_chan(uart_chan); // get the USART based on the card handle
if (NULL == usart) {
TRACE_ERROR("%u: USART not found by chan\r\n", uart_chan);
return;
}
ci->wt_remaining = ci->wt; // reload WT value
ci->wt_halfed = false; // reset half expired
if (ci->wt_remaining > 0xffff) { // value exceeds the USART TO range
usart->US_RTOR = 0xffff; // use the MAX
} else {
usart->US_RTOR = ci->wt_remaining;
}
usart->US_CR |= US_CR_RETTO; // restart the counter (if wt is 0, the timeout is not started)
}
void card_emu_uart_io_set(uint8_t uart_chan, bool set)
{
if (uart_chan >= ARRAY_SIZE(cardem_inst)) {
TRACE_ERROR("%u: UART channel out of bounds\r\n", uart_chan);
return;
}
struct cardem_inst *ci = &cardem_inst[uart_chan];
if (set) {
PIO_Set(&ci->pin_io);
} else {
PIO_Clear(&ci->pin_io);
}
}
/* call-back from card_emu.c to force a USART interrupt */
void card_emu_uart_interrupt(uint8_t uart_chan)
{
Usart *usart = get_usart_by_chan(uart_chan);
if (!usart) {
return;
}
if (USART0 == usart) {
NVIC_SetPendingIRQ(USART0_IRQn);
} else if (USART1 == usart) {
NVIC_SetPendingIRQ(USART1_IRQn);
}
} }
/*********************************************************************** /***********************************************************************
@@ -279,7 +414,6 @@ static int card_vcc_adc_init(void)
return 0; return 0;
} }
#define UV_PER_LSB ((3300 * 1000) / 4096)
#define VCC_UV_THRESH_1V8 1500000 #define VCC_UV_THRESH_1V8 1500000
#define VCC_UV_THRESH_3V 2800000 #define VCC_UV_THRESH_3V 2800000
@@ -299,12 +433,6 @@ static void process_vcc_adc(struct cardem_inst *ci)
ci->vcc_uv_last = ci->vcc_uv; ci->vcc_uv_last = ci->vcc_uv;
} }
static uint32_t adc2uv(uint16_t adc)
{
uint32_t uv = (uint32_t) adc * UV_PER_LSB;
return uv;
}
void ADC_IrqHandler(void) void ADC_IrqHandler(void)
{ {
#ifdef CARDEMU_SECOND_UART #ifdef CARDEMU_SECOND_UART
@@ -330,7 +458,7 @@ void ADC_IrqHandler(void)
#endif /* DETECT_VCC_BY_ADC */ #endif /* DETECT_VCC_BY_ADC */
/*********************************************************************** /***********************************************************************
* Core USB / mainloop integration * Core USB / main loop integration
***********************************************************************/ ***********************************************************************/
static void usim1_rst_irqhandler(const Pin *pPin) static void usim1_rst_irqhandler(const Pin *pPin)
@@ -344,7 +472,7 @@ static void usim1_vcc_irqhandler(const Pin *pPin)
{ {
int active = PIO_Get(&pin_usim1_vcc) ? 1 : 0; int active = PIO_Get(&pin_usim1_vcc) ? 1 : 0;
card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_VCC, active); card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_VCC, active);
/* FIXME do this for real */ /* FIXME readers enable clock after providing power and before releasing reset, but we should check it */
card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_CLK, active); card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_CLK, active);
} }
#endif /* !DETECT_VCC_BY_ADC */ #endif /* !DETECT_VCC_BY_ADC */
@@ -361,7 +489,7 @@ static void usim2_vcc_irqhandler(const Pin *pPin)
{ {
int active = PIO_Get(&pin_usim2_vcc) ? 1 : 0; int active = PIO_Get(&pin_usim2_vcc) ? 1 : 0;
card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_VCC, active); card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_VCC, active);
/* FIXME do this for real */ /* FIXME readers enable clock after providing power and before releasing reset, but we should check it */
card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_CLK, active); card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_CLK, active);
} }
#endif /* !DETECT_VCC_BY_ADC */ #endif /* !DETECT_VCC_BY_ADC */
@@ -380,31 +508,47 @@ void mode_cardemu_init(void)
TRACE_ENTRY(); TRACE_ENTRY();
#ifdef PINS_PWR_CARDEMU
// enable power on required peripherals, else disable
Pin pins_pwr_cardemu[] = { PINS_PWR_CARDEMU };
PIO_Configure(pins_pwr_cardemu, PIO_LISTSIZE(pins_pwr_cardemu));
#endif /* PINS_PWR_CARDEMU */
#ifdef PINS_CARDSIM #ifdef PINS_CARDSIM
PIO_Configure(pins_cardsim, PIO_LISTSIZE(pins_cardsim)); PIO_Configure(pins_cardsim, PIO_LISTSIZE(pins_cardsim));
#endif #endif
// ADC channel 6 and 7 are used to measure VCC (else they are grounded)
ADC->ADC_CHER |= ADC_CHER_CH6 | ADC_CHER_CH7; // enable the ADC channels to put them in high impedance (else they leak current)
#ifdef DETECT_VCC_BY_ADC #ifdef DETECT_VCC_BY_ADC
card_vcc_adc_init(); card_vcc_adc_init(); // configure the ADC to measure VCC
#endif /* DETECT_VCC_BY_ADC */ #endif /* DETECT_VCC_BY_ADC */
// TODO pull SIMtrace board SIM lines low, else they can leak current back to VCC
INIT_LLIST_HEAD(&cardem_inst[0].usb_out_queue); INIT_LLIST_HEAD(&cardem_inst[0].usb_out_queue);
rbuf_reset(&cardem_inst[0].rb); rbuf_reset(&cardem_inst[0].rb);
PIO_Configure(pins_usim1, PIO_LISTSIZE(pins_usim1)); PIO_Configure(pins_usim1, PIO_LISTSIZE(pins_usim1));
ISO7816_Init(&cardem_inst[0].usart_info, CLK_SLAVE); ISO7816_Init(&cardem_inst[0].usart_info, CLK_SLAVE); // configure USART as ISO-7816 slave (e.g. card)
NVIC_EnableIRQ(USART1_IRQn); cardem_inst[0].usart_info.base->US_RTOR = 0; // don't use receive timeout timer for now
PIO_ConfigureIt(&pin_usim1_rst, usim1_rst_irqhandler); USART_EnableIt(cardem_inst[0].usart_info.base, US_IER_RXRDY | US_IER_TIMEOUT); // enable interrupts to indicate when data has been received or timeout occurred
PIO_EnableIt(&pin_usim1_rst); NVIC_EnableIRQ(USART1_IRQn); // enable interrupt requests for the USART peripheral
PIO_ConfigureIt(&pin_usim1_rst, usim1_rst_irqhandler); // register ISR to handle reset signal change
PIO_EnableIt(&pin_usim1_rst); // enable interrupt for reset pin change
#ifndef DETECT_VCC_BY_ADC #ifndef DETECT_VCC_BY_ADC
PIO_ConfigureIt(&pin_usim1_vcc, usim1_vcc_irqhandler); PIO_ConfigureIt(&pin_usim1_vcc, usim1_vcc_irqhandler); // register ISR to handle VCC signal change
PIO_EnableIt(&pin_usim1_vcc); PIO_EnableIt(&pin_usim1_vcc); // enable interrupt for VCC pin change
#endif /* DETECT_VCC_BY_ADC */ #endif /* DETECT_VCC_BY_ADC */
cardem_inst[0].ch = card_emu_init(0, 2, 0, PHONE_DATAIN, PHONE_INT); cardem_inst[0].ch = card_emu_init(0, 2, 0, SIMTRACE_CARDEM_USB_EP_USIM1_DATAIN, SIMTRACE_CARDEM_USB_EP_USIM1_INT);
sim_switch_use_physical(0, 1);
#ifndef DETECT_VCC_BY_ADC
usim1_vcc_irqhandler(NULL); // check VCC/CLK state
#endif
usim1_rst_irqhandler(NULL); // force RST state
#ifdef CARDEMU_SECOND_UART #ifdef CARDEMU_SECOND_UART
INIT_LLIST_HEAD(&cardem_inst[1].usb_out_queue); INIT_LLIST_HEAD(&cardem_inst[1].usb_out_queue);
rbuf_reset(&cardem_inst[1].rb); rbuf_reset(&cardem_inst[1].rb);
PIO_Configure(pins_usim2, PIO_LISTSIZE(pins_usim2)); PIO_Configure(pins_usim2, PIO_LISTSIZE(pins_usim2));
ISO7816_Init(&cardem_inst[1].usart_info, CLK_SLAVE); ISO7816_Init(&cardem_inst[1].usart_info, CLK_SLAVE);
// TODO enable timeout
NVIC_EnableIRQ(USART0_IRQn); NVIC_EnableIRQ(USART0_IRQn);
PIO_ConfigureIt(&pin_usim2_rst, usim2_rst_irqhandler); PIO_ConfigureIt(&pin_usim2_rst, usim2_rst_irqhandler);
PIO_EnableIt(&pin_usim2_rst); PIO_EnableIt(&pin_usim2_rst);
@@ -412,8 +556,11 @@ void mode_cardemu_init(void)
PIO_ConfigureIt(&pin_usim2_vcc, usim2_vcc_irqhandler); PIO_ConfigureIt(&pin_usim2_vcc, usim2_vcc_irqhandler);
PIO_EnableIt(&pin_usim2_vcc); PIO_EnableIt(&pin_usim2_vcc);
#endif /* DETECT_VCC_BY_ADC */ #endif /* DETECT_VCC_BY_ADC */
cardem_inst[1].ch = card_emu_init(1, 0, 1, CARDEM_USIM2_DATAIN, CARDEM_USIM2_INT); cardem_inst[1].ch = card_emu_init(1, 0, 1, SIMTRACE_CARDEM_USB_EP_USIM2_DATAIN, SIMTRACE_CARDEM_USB_EP_USIM2_INT);
sim_switch_use_physical(1, 1);
// TODO check rst and vcc
#endif /* CARDEMU_SECOND_UART */ #endif /* CARDEMU_SECOND_UART */
} }
/* called if config is deactivated */ /* called if config is deactivated */
@@ -478,6 +625,11 @@ static void dispatch_usb_command_cardem(struct msgb *msg, struct cardem_inst *ci
break; break;
case SIMTRACE_MSGT_DT_CEMU_CARDINSERT: case SIMTRACE_MSGT_DT_CEMU_CARDINSERT:
cardins = (struct cardemu_usb_msg_cardinsert *) msg->l2h; cardins = (struct cardemu_usb_msg_cardinsert *) msg->l2h;
if (!ci->pin_insert.pio) {
TRACE_INFO("%u: skipping unsupported card_insert to %s\r\n",
ci->num, cardins->card_insert ? "INSERTED" : "REMOVED");
break;
}
TRACE_INFO("%u: set card_insert to %s\r\n", ci->num, TRACE_INFO("%u: set card_insert to %s\r\n", ci->num,
cardins->card_insert ? "INSERTED" : "REMOVED"); cardins->card_insert ? "INSERTED" : "REMOVED");
if (cardins->card_insert) if (cardins->card_insert)
@@ -498,6 +650,10 @@ static void dispatch_usb_command_cardem(struct msgb *msg, struct cardem_inst *ci
} }
} }
#ifdef PINS_PERST
#include "wwan_perst.h"
#endif
static int usb_command_modem_reset(struct msgb *msg, struct cardem_inst *ci) static int usb_command_modem_reset(struct msgb *msg, struct cardem_inst *ci)
{ {
struct st_modem_reset *mr = (struct st_modem_reset *) msg->l2h; struct st_modem_reset *mr = (struct st_modem_reset *) msg->l2h;
@@ -506,6 +662,7 @@ static int usb_command_modem_reset(struct msgb *msg, struct cardem_inst *ci)
return -1; return -1;
switch (mr->asserted) { switch (mr->asserted) {
#ifdef PINS_PERST
case 0: case 0:
wwan_perst_set(ci->num, 0); wwan_perst_set(ci->num, 0);
break; break;
@@ -515,6 +672,7 @@ static int usb_command_modem_reset(struct msgb *msg, struct cardem_inst *ci)
case 2: case 2:
wwan_perst_do_reset_pulse(ci->num, mr->pulse_duration_msec); wwan_perst_do_reset_pulse(ci->num, mr->pulse_duration_msec);
break; break;
#endif
default: default:
return -1; return -1;
} }
@@ -568,6 +726,7 @@ static void dispatch_usb_command(struct msgb *msg, struct cardem_inst *ci)
usb_buf_free(msg); usb_buf_free(msg);
return; return;
} }
msg->l2h = msg->l1h + sizeof(*sh);
switch (sh->msg_class) { switch (sh->msg_class) {
case SIMTRACE_MSGC_GENERIC: case SIMTRACE_MSGC_GENERIC:
@@ -579,7 +738,6 @@ static void dispatch_usb_command(struct msgb *msg, struct cardem_inst *ci)
case SIMTRACE_MSGC_MODEM: case SIMTRACE_MSGC_MODEM:
/* FIXME: Find out why this fails if used for != /* FIXME: Find out why this fails if used for !=
* MSGC_MODEM ?!? */ * MSGC_MODEM ?!? */
msg->l2h = msg->l1h + sizeof(*sh);
dispatch_usb_command_modem(msg, ci); dispatch_usb_command_modem(msg, ci);
break; break;
default: default:

View File

@@ -27,14 +27,15 @@
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
#include "board.h"
#include "simtrace.h"
#ifdef HAVE_CCID #ifdef HAVE_CCID
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
* Headers * Headers
*------------------------------------------------------------------------------*/ *------------------------------------------------------------------------------*/
#include "board.h"
#include <string.h> #include <string.h>
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
@@ -83,11 +84,11 @@ static const Pin pinSmartCard = SMARTCARD_CONNECT_PIN;
static void ISR_PioSmartCard(const Pin * pPin) static void ISR_PioSmartCard(const Pin * pPin)
{ {
/* FIXME: why is pinSmartCard.pio->PIO_ISR the wrong number? /* FIXME: why is pinSmartCard.pio->PIO_ISR the wrong number?
printf("+++++ Trying to check for pending interrupts (PIO ISR: 0x%X)\n\r", pinSmartCard.pio->PIO_ISR); printf("+++++ Trying to check for pending interrupts (PIO ISR: 0x%X)\n\r", pinSmartCard.pio->PIO_ISR);
printf("+++++ Mask: 0x%X\n\r", pinSmartCard.mask); printf("+++++ Mask: 0x%X\n\r", pinSmartCard.mask);
Output: Output:
+++++ Trying to check for pending interrupts (PIO ISR: 0x400)) = 1<<10 +++++ Trying to check for pending interrupts (PIO ISR: 0x400)) = 1<<10
+++++ Mask: 0x100 = 1<<8 +++++ Mask: 0x100 = 1<<8
*/ */
// PA10 is DTXD, which is the debug uart transmit pin // PA10 is DTXD, which is the debug uart transmit pin
@@ -125,6 +126,7 @@ static void ConfigureCardDetection(void)
*-----------------------------------------------------------------------------*/ *-----------------------------------------------------------------------------*/
extern CCIDDriverConfigurationDescriptors configurationDescriptorCCID; extern CCIDDriverConfigurationDescriptors configurationDescriptorCCID;
/* Called during USB enumeration after device is enumerated by host */
void CCID_configure(void) void CCID_configure(void)
{ {
CCIDDriver_Initialize(); CCIDDriver_Initialize();
@@ -132,6 +134,7 @@ void CCID_configure(void)
PIO_ConfigureIt(&pinSmartCard, ISR_PioSmartCard); PIO_ConfigureIt(&pinSmartCard, ISR_PioSmartCard);
} }
/* called when *different* configuration is set by host */
void CCID_exit(void) void CCID_exit(void)
{ {
PIO_DisableIt(&pinSmartCard); PIO_DisableIt(&pinSmartCard);
@@ -139,6 +142,7 @@ void CCID_exit(void)
USART_SetReceiverEnabled(usart_info.base, 0); USART_SetReceiverEnabled(usart_info.base, 0);
} }
/* called when *CCID* configuration is set by host */
void CCID_init(void) void CCID_init(void)
{ {
uint8_t pAtr[MAX_ATR_SIZE]; uint8_t pAtr[MAX_ATR_SIZE];
@@ -178,6 +182,7 @@ void CCID_init(void)
} }
} }
/* main (idle/busy) loop of this USB configuration */
void CCID_run(void) void CCID_run(void)
{ {

View File

@@ -1,196 +0,0 @@
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2009, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
/*------------------------------------------------------------------------------
* Headers
*------------------------------------------------------------------------------*/
#include "board.h"
#include <string.h>
/*------------------------------------------------------------------------------
* Internal definitions
*------------------------------------------------------------------------------*/
/** Maximum ucSize in bytes of the smartcard answer to a command.*/
#define MAX_ANSWER_SIZE 10
/** Maximum ATR ucSize in bytes.*/
#define MAX_ATR_SIZE 55
/** USB states */
/// Use for power management
#define STATE_IDLE 0
/// The USB device is in suspend state
#define STATE_SUSPEND 4
/// The USB device is in resume state
#define STATE_RESUME 5
extern volatile uint8_t timeout_occured;
/*------------------------------------------------------------------------------
* Internal variables
*------------------------------------------------------------------------------*/
/** USB state: suspend, resume, idle */
unsigned char USBState = STATE_IDLE;
/** ISO7816 pins */
static const Pin pinsISO7816_PHONE[] = { PINS_ISO7816_PHONE };
/** Bus switch pins */
#if DEBUG_PHONE_SNIFF
#warning "Debug phone sniff via logic analyzer is enabled"
// Logic analyzer probes are easier to attach to the SIM card slot
static const Pin pins_bus[] = { PINS_BUS_SNIFF };
#else
static const Pin pins_bus[] = { PINS_BUS_DEFAULT };
#endif
/** ISO7816 RST pin */
static uint8_t sim_inserted = 0;
static const Pin pPwr[] = {
/* Enable power converter 4.5-6V to 3.3V; low: off */
{SIM_PWEN, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT},
/* Enable second power converter: VCC_PHONE to VCC_SIM; high: off */
{VCC_FWD, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
};
const Pin pinPhoneRST = PIN_ISO7816_RST_PHONE;
static struct Usart_info usart_info = {
.base = USART_PHONE,
.id = ID_USART_PHONE,
.state = USART_RCV,
};
/* ===================================================*/
/* Taken from iso7816_4.c */
/* ===================================================*/
/** Flip flop for send and receive char */
#define USART_SEND 0
#define USART_RCV 1
/*-----------------------------------------------------------------------------
* Internal variables
*-----------------------------------------------------------------------------*/
static uint8_t host_to_sim_buf[BUFLEN];
static bool change_fidi = false;
static void receive_from_host(void);
static void sendResponse_to_phone(uint8_t * pArg, uint8_t status,
uint32_t transferred, uint32_t remaining)
{
if (status != USBD_STATUS_SUCCESS) {
TRACE_ERROR("USB err status: %d (%s)\n", __FUNCTION__, status);
return;
}
TRACE_DEBUG("sendResp, stat: %X, trnsf: %x, rem: %x\n\r", status,
transferred, remaining);
TRACE_DEBUG("Resp: %x %x %x .. %x\n", host_to_sim_buf[0],
host_to_sim_buf[1], host_to_sim_buf[2],
host_to_sim_buf[transferred - 1]);
USART_SetReceiverEnabled(USART_PHONE, 0);
USART_SetTransmitterEnabled(USART_PHONE, 1);
uint32_t i = 0;
if (host_to_sim_buf[0] == 0xff) {
printf("Change FIDI detected\n");
// PTS command, change FIDI after command
i = 2;
change_fidi = true;
}
for (; i < transferred; i++) {
ISO7816_SendChar(host_to_sim_buf[i], &usart_info);
}
USART_SetTransmitterEnabled(USART_PHONE, 0);
USART_SetReceiverEnabled(USART_PHONE, 1);
if (change_fidi == true) {
printf("Change FIDI: %x\n", host_to_sim_buf[2]);
update_fidi(host_to_sim_buf[2]);
change_fidi = false;
}
receive_from_host();
}
static void receive_from_host()
{
int ret;
if ((ret = USBD_Read(PHONE_DATAOUT, &host_to_sim_buf,
sizeof(host_to_sim_buf),
(TransferCallback) &sendResponse_to_phone,
0)) == USBD_STATUS_SUCCESS) {
} else {
TRACE_ERROR("USB Err: %X\n", ret);
}
}
void Phone_configure(void)
{
PIO_ConfigureIt(&pinPhoneRST, ISR_PhoneRST);
NVIC_EnableIRQ(PIOA_IRQn);
}
void Phone_exit(void)
{
PIO_DisableIt(&pinPhoneRST);
NVIC_DisableIRQ(USART1_IRQn);
USART_DisableIt(USART_PHONE, US_IER_RXRDY);
USART_SetTransmitterEnabled(USART_PHONE, 0);
USART_SetReceiverEnabled(USART_PHONE, 0);
}
void Phone_init(void)
{
PIO_Configure(pinsISO7816_PHONE, PIO_LISTSIZE(pinsISO7816_PHONE));
PIO_Configure(pins_bus, PIO_LISTSIZE(pins_bus));
PIO_Configure(&pinPhoneRST, 1);
PIO_EnableIt(&pinPhoneRST);
ISO7816_Init(&usart_info, CLK_SLAVE);
USART_SetTransmitterEnabled(USART_PHONE, 0);
USART_SetReceiverEnabled(USART_PHONE, 1);
USART_EnableIt(USART_PHONE, US_IER_RXRDY);
NVIC_EnableIRQ(USART1_IRQn);
receive_from_host();
}
void Phone_run(void)
{
check_data_from_phone();
}

View File

@@ -1,8 +1,25 @@
/* Memory allocation library
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#include <stdint.h> #include <stdint.h>
#include "talloc.h" #include "talloc.h"
#include "trace.h" #include "trace.h"
#include "osmocom/core/utils.h" #include "utils.h"
#include <osmocom/core/utils.h>
#define NUM_RCTX_SMALL 10 #define NUM_RCTX_SMALL 10
#define RCTX_SIZE_SMALL 348 #define RCTX_SIZE_SMALL 348
@@ -13,8 +30,11 @@ static uint8_t msgb_inuse[NUM_RCTX_SMALL];
void *_talloc_zero(const void *ctx, size_t size, const char *name) void *_talloc_zero(const void *ctx, size_t size, const char *name)
{ {
unsigned int i; unsigned int i;
unsigned long x;
local_irq_save(x);
if (size > RCTX_SIZE_SMALL) { if (size > RCTX_SIZE_SMALL) {
local_irq_restore(x);
TRACE_ERROR("%s() request too large(%d > %d)\r\n", __func__, size, RCTX_SIZE_SMALL); TRACE_ERROR("%s() request too large(%d > %d)\r\n", __func__, size, RCTX_SIZE_SMALL);
return NULL; return NULL;
} }
@@ -24,9 +44,11 @@ void *_talloc_zero(const void *ctx, size_t size, const char *name)
uint8_t *out = msgb_data[i]; uint8_t *out = msgb_data[i];
msgb_inuse[i] = 1; msgb_inuse[i] = 1;
memset(out, 0, size); memset(out, 0, size);
local_irq_restore(x);
return out; return out;
} }
} }
local_irq_restore(x);
TRACE_ERROR("%s() out of memory!\r\n", __func__); TRACE_ERROR("%s() out of memory!\r\n", __func__);
return NULL; return NULL;
} }
@@ -34,17 +56,22 @@ void *_talloc_zero(const void *ctx, size_t size, const char *name)
int _talloc_free(void *ptr, const char *location) int _talloc_free(void *ptr, const char *location)
{ {
unsigned int i; unsigned int i;
unsigned long x;
local_irq_save(x);
for (i = 0; i < ARRAY_SIZE(msgb_inuse); i++) { for (i = 0; i < ARRAY_SIZE(msgb_inuse); i++) {
if (ptr == msgb_data[i]) { if (ptr == msgb_data[i]) {
if (!msgb_inuse[i]) { if (!msgb_inuse[i]) {
TRACE_ERROR("%s: double_free by \r\n", __func__, location); TRACE_ERROR("%s: double_free by %s\r\n", __func__, location);
} else { } else {
msgb_inuse[i] = 0; msgb_inuse[i] = 0;
} }
local_irq_restore(x);
return 0; return 0;
} }
} }
local_irq_restore(x);
TRACE_ERROR("%s: invalid pointer %p from %s\r\n", __func__, ptr, location); TRACE_ERROR("%s: invalid pointer %p from %s\r\n", __func__, ptr, location);
return -1; return -1;
} }

View File

@@ -1,7 +1,27 @@
/* Ring buffer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*/
#include "ringbuffer.h" #include "ringbuffer.h"
#include "trace.h" #include "trace.h"
#include "utils.h" #include "utils.h"
/* WARNING: Since console output is internally using this ringbuffer to implement
* buffered writes, we cannot use any TRACE_*() or printf() style functions here,
* as it would create infinite recursion! */
void rbuf_reset(volatile ringbuf * rb) void rbuf_reset(volatile ringbuf * rb)
{ {
unsigned long state; unsigned long state;
@@ -52,7 +72,7 @@ bool rbuf_is_full(volatile ringbuf * rb)
return rc; return rc;
} }
void rbuf_write(volatile volatile ringbuf * rb, uint8_t item) int rbuf_write(volatile ringbuf * rb, uint8_t item)
{ {
unsigned long state; unsigned long state;
@@ -61,9 +81,10 @@ void rbuf_write(volatile volatile ringbuf * rb, uint8_t item)
rb->buf[rb->iwr] = item; rb->buf[rb->iwr] = item;
rb->iwr = (rb->iwr + 1) % RING_BUFLEN; rb->iwr = (rb->iwr + 1) % RING_BUFLEN;
local_irq_restore(state); local_irq_restore(state);
return 0;
} else { } else {
local_irq_restore(state); local_irq_restore(state);
TRACE_ERROR("Ringbuffer full, losing bytes!"); return -1;
} }
} }

View File

@@ -33,6 +33,7 @@
#include "board.h" #include "board.h"
#include "simtrace.h" #include "simtrace.h"
#include "simtrace_usb.h"
#include "ringbuffer.h" #include "ringbuffer.h"
#include "iso7816_fidi.h" #include "iso7816_fidi.h"
@@ -57,7 +58,7 @@ void ISR_PhoneRST(const Pin * pPin)
{ {
int ret; int ret;
// FIXME: no printfs in ISRs? // FIXME: no printfs in ISRs?
printf("+++ Int!! %x\n\r", pinPhoneRST.pio->PIO_ISR); printf("+++ Int!! %lx\n\r", pinPhoneRST.pio->PIO_ISR);
if (((pinPhoneRST.pio->PIO_ISR & pinPhoneRST.mask) != 0)) { if (((pinPhoneRST.pio->PIO_ISR & pinPhoneRST.mask) != 0)) {
if (PIO_Get(&pinPhoneRST) == 0) { if (PIO_Get(&pinPhoneRST) == 0) {
printf(" 0 "); printf(" 0 ");
@@ -67,7 +68,7 @@ void ISR_PhoneRST(const Pin * pPin)
} }
if ((ret = if ((ret =
USBD_Write(PHONE_INT, "R", 1, USBD_Write(SIMTRACE_USB_EP_PHONE_INT, "R", 1,
(TransferCallback) & Callback_PhoneRST_ISR, (TransferCallback) & Callback_PhoneRST_ISR,
0)) != USBD_STATUS_SUCCESS) { 0)) != USBD_STATUS_SUCCESS) {
TRACE_ERROR("USB err status: %d (%s)\n", ret, __FUNCTION__); TRACE_ERROR("USB err status: %d (%s)\n", ret, __FUNCTION__);
@@ -79,7 +80,7 @@ void ISR_PhoneRST(const Pin * pPin)
} }
/* /*
* char_stat is zero if no error occured. * char_stat is zero if no error occurred.
* Otherwise it is filled with the content of the status register. * Otherwise it is filled with the content of the status register.
*/ */
void mode_trace_usart1_irq(void) void mode_trace_usart1_irq(void)
@@ -109,27 +110,34 @@ void mode_trace_usart1_irq(void)
rbuf_write(&sim_rcv_buf, c); rbuf_write(&sim_rcv_buf, c);
} else { } else {
TRACE_DEBUG("e %x st: %x\n", c, stat); TRACE_DEBUG("e %x st: %x\n", c, stat);
} /* else: error occured */ } /* else: error occurred */
char_stat = stat; char_stat = stat;
} }
} }
/* FIDI update functions */ /* FIDI update functions */
void update_fidi(uint8_t fidi) void update_fidi(Usart_info *usart, uint8_t fidi)
{ {
int rc; if (NULL==usart) {
return;
}
uint8_t fi = fidi >> 4; uint8_t fi = fidi >> 4;
uint8_t di = fidi & 0xf; uint8_t di = fidi & 0xf;
int ratio = compute_fidi_ratio(fi, di);
rc = compute_fidi_ratio(fi, di); if (ratio > 0 && ratio < 0x8000) {
if (rc > 0 && rc < 0x400) { /* make sure USART uses new F/D ratio */
TRACE_INFO("computed Fi(%u) Di(%u) ratio: %d", fi, di, rc); usart->base->US_CR |= US_CR_RXDIS | US_CR_RSTRX;
/* make sure UART uses new F/D ratio */ /* disable write protection */
USART_PHONE->US_CR |= US_CR_RXDIS | US_CR_RSTRX; if (usart->base->US_WPMR) {
USART_PHONE->US_FIDI = rc & 0x3ff; usart->base->US_WPMR = US_WPMR_WPKEY(0x555341);
USART_PHONE->US_CR |= US_CR_RXEN | US_CR_STTTO; }
} else usart->base->US_FIDI = (ratio & 0x7ff);
TRACE_INFO("computed FiDi ratio %d unsupported", rc); usart->base->US_CR |= US_CR_RXEN | US_CR_STTTO;
//TRACE_INFO("updated USART(%u) Fi(%u)/Di(%u) ratio(%d): %u\n\r", usart->id, fi, di, ratio, usart->base->US_FIDI);
} else {
//TRACE_WARNING("computed Fi/Di ratio %d unsupported\n\r", ratio); /* don't print since this is function is also called by ISRs */
}
} }

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More