105 Commits

Author SHA1 Message Date
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
98 changed files with 10098 additions and 8097 deletions

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

View File

@@ -9,6 +9,7 @@ fi
set -e
publish="$1"
base="$PWD"
deps="$base/deps"
inst="$deps/install"
@@ -24,7 +25,7 @@ export PKG_CONFIG_PATH="$inst/lib/pkgconfig:$PKG_CONFIG_PATH"
export LD_LIBRARY_PATH="$inst/lib"
BUILDS=""
BUILDS+="simtrace/dfu simtrace/cardem " # simtrace/trace simtrace/triple_play
BUILDS+="simtrace/dfu simtrace/cardem simtrace/trace " # simtrace/triple_play
BUILDS+="qmod/dfu qmod/cardem "
BUILDS+="owhw/dfu owhw/cardem "
@@ -35,7 +36,6 @@ for build in $BUILDS; do
echo
echo "=============== $board / $app START =============="
make BOARD="$board" APP="$app"
make BOARD="$board" APP="$app" clean
echo "=============== $board / $app RES:$? =============="
done
@@ -54,4 +54,26 @@ 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

5
debian/changelog vendored Normal file
View File

@@ -0,0 +1,5 @@
simtrace2 (0.5) UNRELEASED; 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

30
debian/control vendored Normal file
View File

@@ -0,0 +1,30 @@
Source: simtrace2
Maintainer: Harald Welte <laforge@gnumonks.org>
Section: devel
Priority: optional
Build-Depends: debhelper (>= 9),
libosmocore-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

@@ -141,13 +141,12 @@ INCLUDES += -Ilibosmocore/include
INCLUDES += -Isrc_simtrace -Iinclude
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 += -Wsequence-point -Wreturn-type -Wswitch -Wtrigraphs #-Wunused
CFLAGS += -Wuninitialized -Wunknown-pragmas -Wfloat-equal #-Wundef
CFLAGS += -Wshadow -Wpointer-arith -Wbad-function-cast -Wwrite-strings
CFLAGS += -Waggregate-return #-Wsign-compare
CFLAGS += -Wformat=0
CFLAGS += -Wmissing-format-attribute -Wno-deprecated-declarations
CFLAGS += #-Wpacked
CFLAGS += -Wredundant-decls -Wnested-externs #-Winline -Wlong-long
@@ -234,3 +233,7 @@ log:
clean:
-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,4 +1,21 @@
// FIXME: Copyright license here
/* SIMtrace 2 firmware card emulation 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
*------------------------------------------------------------------------------*/
@@ -108,6 +125,8 @@ static void check_exec_dbg_cmd(void)
return;
ch = UART_GetChar();
/* We must echo the character to make python fdexpect happy, whcih we use in factory testing */
fputc(ch, stdout);
board_exec_dbg_cmd(ch);
}
@@ -125,24 +144,38 @@ extern int main(void)
led_init();
led_blink(LED_RED, BLINK_3O_5F);
/* 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_GetPeriod(500) << 16) | WDT_GetPeriod(500));
(WDT_GetPeriod(2000) << 16) | WDT_GetPeriod(2000));
PIO_InitializeInterrupts(0);
EEFC_ReadUniqueID(g_unique_id);
printf("\n\r\n\r"
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%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",
g_unique_id[0], g_unique_id[1],
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();

View File

@@ -1,8 +1,28 @@
/* SIMtrace 2 firmware USB DFU bootloader
*
* (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.
*/
#include "board.h"
#include "utils.h"
#include "usb/device/dfu/dfu.h"
#include "usb/common/dfu/usb_dfu.h"
#include "manifest.h"
#include "USBD_HAL.h"
#include <osmocom/core/timer.h>
@@ -94,7 +114,6 @@ int USBDFU_handle_dnload(uint8_t altif, unsigned int offset,
rc = DFU_RET_ZLP;
break;
default:
/* FIXME: set error codes */
TRACE_ERROR("DFU download for unknown AltIf %d\n\r", altif);
rc = DFU_RET_STALL;
break;
@@ -160,22 +179,30 @@ WEAK int board_override_enter_dfu(void)
int USBDFU_OverrideEnterDFU(void)
{
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 (board_override_enter_dfu())
return 1;
if (board_override_enter_dfu()) {
return 2;
}
/* if the first word of the application partition doesn't look
* like a stack pointer (i.e. point to RAM), enter DFU mode */
if ((app_part[0] < IRAM_ADDR) ||
((uint8_t *)app_part[0] > IRAM_END))
return 1;
if ((app_part[0] < IRAM_ADDR) || ((uint8_t *)app_part[0] > IRAM_END)) {
return 3;
}
/* if the second word of the application partition doesn't look
* like a function from flash (reset vector), enter DFU mode */
if (((uint32_t *)app_part[1] < app_part) ||
((uint8_t *)app_part[1] > IFLASH_END))
return 1;
((uint8_t *)app_part[1] > IFLASH_END)) {
return 4;
}
return 0;
}
@@ -215,15 +242,11 @@ extern int main(void)
PIO_Clear(&pinsLeds[LED_NUM_GREEN]);
#endif
/* Enable watchdog for 500ms, with no window */
WDT_Enable(WDT, WDT_MR_WDRSTEN | WDT_MR_WDDBGHLT | WDT_MR_WDIDLEHLT |
(WDT_GetPeriod(500) << 16) | WDT_GetPeriod(500));
PIO_InitializeInterrupts(0);
EEFC_ReadUniqueID(g_unique_id);
printf("\n\r\n\r"
printf("\n\r\n\r"
"=============================================================================\n\r"
"DFU bootloader %s for board %s (C) 2010-2017 by Harald Welte\n\r"
"=============================================================================\n\r",
@@ -235,6 +258,35 @@ extern int main(void)
g_unique_id[2], g_unique_id[3]);
TRACE_INFO("Reset Cause: 0x%x\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 */
if (reset_cause == 0)
memset(g_dfu, 0, sizeof(*g_dfu));
@@ -243,11 +295,18 @@ extern int main(void)
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);
mdelay(15);
#endif
USBD_HAL_Suspend();
mdelay(20);
#ifdef PIN_USB_PULLUP
PIO_Clear(&usb_dp_pullup);
#endif
USBD_HAL_Activate();
USBDFU_Initialize(&dfu_descriptors);
while (USBD_GetState() < USBD_STATE_CONFIGURED) {

View File

@@ -1,21 +1,21 @@
/*
* (C) 2010-2017 by Harald Welte <hwelte@sysmocom.de>
* (C) 2018 by Kevin Redon <kredon@sysmocom.de>
* All Rights Reserved
/* SIMtrace 2 firmware sniffer application
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
* (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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* 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
@@ -104,9 +104,6 @@ static volatile enum confNum simtrace_config = CFG_NUM_CCID;
void USBDDriverCallbacks_ConfigurationChanged(uint8_t cfgnum)
{
TRACE_INFO_WP("cfgChanged%d ", cfgnum);
if (cfgnum >= sizeof(config_func_ptrs)/sizeof(config_func_ptrs[0])) {
TRACE_FATAL_WP("no functions defined for configuration %d\n\r", cfgnum);
}
simtrace_config = cfgnum;
}
@@ -145,10 +142,15 @@ extern int main(void)
enum confNum last_simtrace_config = simtrace_config;
unsigned int i = 0;
/* Configure LED output (red = on, green = activity */
/* 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_OFF);
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 |
@@ -158,23 +160,22 @@ extern int main(void)
EEFC_ReadUniqueID(g_unique_id);
printf("\n\r\n\r"
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%08x (Ext 0x%08x)\n\r", CHIPID->CHIPID_CIDR, CHIPID->CHIPID_EXID);
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%x\n\r", (RSTC->RSTC_SR & RSTC_SR_RSTTYP_Msk) >> RSTC_SR_RSTTYP_Pos);
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();
TRACE_INFO_WP("USBD_Inited\n\r");
while (USBD_GetState() < USBD_STATE_CONFIGURED) {
WDT_Restart(WDT);
@@ -191,26 +192,13 @@ extern int main(void)
}
TRACE_INFO("calling configure of all configurations...\n\r");
for (i = 1; i < sizeof(config_func_ptrs) / sizeof(config_func_ptrs[0]); ++i) {
if (config_func_ptrs[i].configure) {
for (i = 1; i < ARRAY_SIZE(config_func_ptrs); i++) {
if (config_func_ptrs[i].configure)
config_func_ptrs[i].configure();
} else {
TRACE_WARNING("no configure function defined for configuration %d\n\r", i);
}
}
TRACE_INFO("cfg %d\n\r", simtrace_config);
TRACE_INFO("calling init of config %u...\n\r", simtrace_config);
if (simtrace_config >= sizeof(config_func_ptrs)/sizeof(config_func_ptrs[0])) {
TRACE_ERROR("no functions defined for configuration %d\n\r", simtrace_config);
} else {
if (config_func_ptrs[simtrace_config].init) {
config_func_ptrs[simtrace_config].init();
} else {
TRACE_ERROR("no init function defined for configuration %d\n\r", simtrace_config);
}
}
config_func_ptrs[simtrace_config].init();
last_simtrace_config = simtrace_config;
TRACE_INFO("entering main loop...\n\r");
@@ -238,31 +226,11 @@ extern int main(void)
if (last_simtrace_config != simtrace_config) {
TRACE_INFO("USB config chg %u -> %u\n\r",
last_simtrace_config, simtrace_config);
if (last_simtrace_config < sizeof(config_func_ptrs)/sizeof(config_func_ptrs[0])) {
if (config_func_ptrs[last_simtrace_config].exit) {
config_func_ptrs[last_simtrace_config].exit();
} else {
TRACE_WARNING("exit not defined for configuration %d\n\r", last_simtrace_config);
}
} else {
TRACE_ERROR("no functions defined for configuration %d\n\r", last_simtrace_config);
}
if (simtrace_config < sizeof(config_func_ptrs)/sizeof(config_func_ptrs[0])) {
if (config_func_ptrs[simtrace_config].init) {
config_func_ptrs[simtrace_config].init();
} else {
TRACE_WARNING("init not defined for configuration %d\n\r", simtrace_config);
}
} else {
TRACE_FATAL("no functions defined for configuration %d\n\r", simtrace_config);
}
config_func_ptrs[last_simtrace_config].exit();
config_func_ptrs[simtrace_config].init();
last_simtrace_config = simtrace_config;
} else {
if (config_func_ptrs[simtrace_config].run) {
config_func_ptrs[simtrace_config].run();
} else {
TRACE_ERROR("run not defined for configuration %d\n\r", simtrace_config);
}
config_func_ptrs[simtrace_config].run();
}
}
}

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
*------------------------------------------------------------------------------*/
@@ -134,7 +151,7 @@ extern int main(void)
EEFC_ReadUniqueID(g_unique_id);
printf("\r\n\r\n"
printf("\r\n\r\n"
"=============================================================================\r\n"
"SIMtrace2 firmware " GIT_REVISION " (C) 2010-2017 by Harald Welte\r\n"
"=============================================================================\r\n");

View File

@@ -1,113 +1,113 @@
/* ----------------------------------------------------------------------------
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* \section Purpose
*
* Interface for configuration the Enhanced Embedded Flash Controller (EEFC) peripheral.
*
* \section Usage
*
* -# Enable/disable %flash ready interrupt sources using EFC_EnableFrdyIt()
* and EFC_DisableFrdyIt().
* -# Translates the given address into which EEFC, page and offset values
* for difference density %flash memory using EFC_TranslateAddress().
* -# Computes the address of a %flash access given the EFC, page and offset
* for difference density %flash memory using EFC_ComputeAddress().
* -# Start the executing command with EFC_StartCommand()
* -# Retrieve the current status of the EFC using EFC_GetStatus().
* -# Retrieve the result of the last executed command with EFC_GetResult().
*/
#ifndef _EEFC_
#define _EEFC_
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include <stdint.h>
/*----------------------------------------------------------------------------
* Definitions
*----------------------------------------------------------------------------*/
/* EFC command */
#define EFC_FCMD_GETD 0x00
#define EFC_FCMD_WP 0x01
#define EFC_FCMD_WPL 0x02
#define EFC_FCMD_EWP 0x03
#define EFC_FCMD_EWPL 0x04
#define EFC_FCMD_EA 0x05
#define EFC_FCMD_SLB 0x08
#define EFC_FCMD_CLB 0x09
#define EFC_FCMD_GLB 0x0A
#define EFC_FCMD_SFB 0x0B
#define EFC_FCMD_CFB 0x0C
#define EFC_FCMD_GFB 0x0D
#define EFC_FCMD_STUI 0x0E /* Start unique ID */
#define EFC_FCMD_SPUI 0x0F /* Stop unique ID */
/* The IAP function entry addreass */
#define CHIP_FLASH_IAP_ADDRESS (0x00800008)
#ifdef __cplusplus
extern "C" {
#endif
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
extern void EFC_EnableFrdyIt( Efc* efc ) ;
extern void EFC_DisableFrdyIt( Efc* efc ) ;
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_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 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_GetResult( Efc* efc ) ;
#ifdef __cplusplus
}
#endif
#endif /* #ifndef _EEFC_ */
/* ----------------------------------------------------------------------------
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* \section Purpose
*
* Interface for configuration the Enhanced Embedded Flash Controller (EEFC) peripheral.
*
* \section Usage
*
* -# Enable/disable %flash ready interrupt sources using EFC_EnableFrdyIt()
* and EFC_DisableFrdyIt().
* -# Translates the given address into which EEFC, page and offset values
* for difference density %flash memory using EFC_TranslateAddress().
* -# Computes the address of a %flash access given the EFC, page and offset
* for difference density %flash memory using EFC_ComputeAddress().
* -# Start the executing command with EFC_StartCommand()
* -# Retrieve the current status of the EFC using EFC_GetStatus().
* -# Retrieve the result of the last executed command with EFC_GetResult().
*/
#ifndef _EEFC_
#define _EEFC_
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include <stdint.h>
/*----------------------------------------------------------------------------
* Definitions
*----------------------------------------------------------------------------*/
/* EFC command */
#define EFC_FCMD_GETD 0x00
#define EFC_FCMD_WP 0x01
#define EFC_FCMD_WPL 0x02
#define EFC_FCMD_EWP 0x03
#define EFC_FCMD_EWPL 0x04
#define EFC_FCMD_EA 0x05
#define EFC_FCMD_SLB 0x08
#define EFC_FCMD_CLB 0x09
#define EFC_FCMD_GLB 0x0A
#define EFC_FCMD_SFB 0x0B
#define EFC_FCMD_CFB 0x0C
#define EFC_FCMD_GFB 0x0D
#define EFC_FCMD_STUI 0x0E /* Start unique ID */
#define EFC_FCMD_SPUI 0x0F /* Stop unique ID */
/* The IAP function entry addreass */
#define CHIP_FLASH_IAP_ADDRESS (0x00800008)
#ifdef __cplusplus
extern "C" {
#endif
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
extern void EFC_EnableFrdyIt( Efc* efc ) ;
extern void EFC_DisableFrdyIt( Efc* efc ) ;
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_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 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_GetResult( Efc* efc ) ;
#ifdef __cplusplus
}
#endif
#endif /* #ifndef _EEFC_ */

View File

@@ -1,79 +1,79 @@
/* ----------------------------------------------------------------------------
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* The flash driver provides the unified interface for flash program operations.
*
*/
#ifndef _FLASHD_
#define _FLASHD_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
extern void FLASHD_Initialize( uint32_t dwMCk, uint32_t dwUseIAP ) ;
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_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_IsLocked( uint32_t dwStart, uint32_t dwEnd ) ;
extern uint32_t FLASHD_SetGPNVM( uint8_t gpnvm ) ;
extern uint32_t FLASHD_ClearGPNVM( uint8_t gpnvm ) ;
extern uint32_t FLASHD_IsGPNVMSet( uint8_t gpnvm ) ;
#define FLASHD_IsSecurityBitSet() FLASHD_IsGPNVMSet( 0 )
#define FLASHD_SetSecurityBit() FLASHD_SetGPNVM( 0 )
extern uint32_t FLASHD_ReadUniqueID( uint32_t* pdwUniqueID ) ;
#ifdef __cplusplus
}
#endif
#endif /* #ifndef _FLASHD_ */
/* ----------------------------------------------------------------------------
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* The flash driver provides the unified interface for flash program operations.
*
*/
#ifndef _FLASHD_
#define _FLASHD_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
extern void FLASHD_Initialize( uint32_t dwMCk, uint32_t dwUseIAP ) ;
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_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_IsLocked( uint32_t dwStart, uint32_t dwEnd ) ;
extern uint32_t FLASHD_SetGPNVM( uint8_t gpnvm ) ;
extern uint32_t FLASHD_ClearGPNVM( uint8_t gpnvm ) ;
extern uint32_t FLASHD_IsGPNVMSet( uint8_t gpnvm ) ;
#define FLASHD_IsSecurityBitSet() FLASHD_IsGPNVMSet( 0 )
#define FLASHD_SetSecurityBit() FLASHD_SetGPNVM( 0 )
extern uint32_t FLASHD_ReadUniqueID( uint32_t* pdwUniqueID ) ;
#ifdef __cplusplus
}
#endif
#endif /* #ifndef _FLASHD_ */

View File

@@ -1,290 +1,290 @@
/* ----------------------------------------------------------------------------
* 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.
* ----------------------------------------------------------------------------
*/
/** \addtogroup efc_module Working with EEFC
* The EEFC driver provides the interface to configure and use the EEFC
* peripheral.
*
* 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.
*
* It offers a function to send flash command to EEFC and waits for the
* flash to be ready.
*
* To send flash command, the user could do in either of following way:
* <ul>
* <li>Write a correct key, command and argument in EEFC_FCR. </li>
* <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>
* <li>Once the command is achieved, it can be detected even by polling EEFC_FSR or interrupt.
* </ul>
*
* 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
* flash address into a page number and vice verse.
*
* For more accurate information, please look at the EEFC section of the
* Datasheet.
*
* Related files :\n
* \ref efc.c\n
* \ref efc.h.\n
*/
/*@{*/
/*@}*/
/**
* \file
*
* Implementation of Enhanced Embedded Flash Controller (EEFC).
*
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include "efc.h"
#include <assert.h>
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/**
* \brief Enables the flash ready interrupt source on the EEFC peripheral.
*
* \param efc Pointer to a Efc instance
*/
extern void EFC_EnableFrdyIt( Efc* efc )
{
efc->EEFC_FMR |= EEFC_FMR_FRDY ;
}
/**
* \brief Disables the flash ready interrupt source on the EEFC peripheral.
*
* \param efc Pointer to a Efc instance
*/
extern void EFC_DisableFrdyIt( Efc* efc )
{
efc->EEFC_FMR &= ~((uint32_t)EEFC_FMR_FRDY) ;
}
/**
* \brief Set read/write wait state on the EEFC perpherial.
*
* \param efc Pointer to a Efc instance
* \param cycles the number of wait states in cycle.
*/
extern void EFC_SetWaitState( Efc* efc, uint8_t ucCycles )
{
uint32_t dwValue ;
dwValue = efc->EEFC_FMR ;
dwValue &= ~((uint32_t)EEFC_FMR_FWS_Msk) ;
dwValue |= EEFC_FMR_FWS(ucCycles);
efc->EEFC_FMR = dwValue ;
}
/**
* \brief Returns the current status of the EEFC.
*
* \note Keep in mind that this function clears the value of some status bits (LOCKE, PROGE).
*
* \param efc Pointer to a Efc instance
*/
extern uint32_t EFC_GetStatus( Efc* efc )
{
return efc->EEFC_FSR ;
}
/**
* \brief Returns the result of the last executed command.
*
* \param efc Pointer to a Efc instance
*/
extern uint32_t EFC_GetResult( Efc* efc )
{
return efc->EEFC_FRR ;
}
/**
* \brief Translates the given address page and offset values.
* \note The resulting values are stored in the provided variables if they are not null.
*
* \param efc Pointer to a Efc instance
* \param address Address to translate.
* \param pPage First page accessed.
* \param pOffset Byte offset in first page.
*/
extern void EFC_TranslateAddress( Efc** ppEfc, uint32_t dwAddress, uint16_t* pwPage, uint16_t* pwOffset )
{
Efc *pEfc ;
uint16_t wPage ;
uint16_t wOffset ;
assert( dwAddress >= IFLASH_ADDR ) ;
assert( dwAddress <= (IFLASH_ADDR + IFLASH_SIZE) ) ;
pEfc = EFC ;
wPage = (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 ) ;
/* Store values */
if ( pEfc )
{
*ppEfc = pEfc ;
}
if ( pwPage )
{
*pwPage = wPage ;
}
if ( pwOffset )
{
*pwOffset = wOffset ;
}
}
/**
* \brief Computes the address of a flash access given the page and offset.
*
* \param efc Pointer to a Efc instance
* \param page Page number.
* \param offset Byte offset inside page.
* \param pAddress Computed address (optional).
*/
extern void EFC_ComputeAddress( Efc *efc, uint16_t wPage, uint16_t wOffset, uint32_t *pdwAddress )
{
uint32_t dwAddress ;
assert( efc ) ;
assert( wPage <= IFLASH_NB_OF_PAGES ) ;
assert( wOffset < IFLASH_PAGE_SIZE ) ;
/* Compute address */
dwAddress = IFLASH_ADDR + wPage * IFLASH_PAGE_SIZE + wOffset ;
/* Store result */
if ( pdwAddress != NULL )
{
*pdwAddress = dwAddress ;
}
}
/**
* \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.
* \param efc Pointer to a Efc instance
* \param command Command to execute.
* \param argument Command argument (should be 0 if not used).
*/
extern void EFC_StartCommand( Efc* efc, uint32_t dwCommand, uint32_t dwArgument )
{
/* Check command & argument */
switch ( dwCommand )
{
case EFC_FCMD_WP:
case EFC_FCMD_WPL:
case EFC_FCMD_EWP:
case EFC_FCMD_EWPL:
case EFC_FCMD_SLB:
case EFC_FCMD_CLB:
assert( dwArgument < IFLASH_NB_OF_PAGES ) ;
break ;
case EFC_FCMD_SFB:
case EFC_FCMD_CFB:
assert( dwArgument < 2 ) ;
break;
case EFC_FCMD_GETD:
case EFC_FCMD_EA:
case EFC_FCMD_GLB:
case EFC_FCMD_GFB:
case EFC_FCMD_STUI:
assert( dwArgument == 0 ) ;
break;
default: assert( 0 ) ;
}
/* Start command Embedded flash */
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) ;
}
/**
* \brief Performs the given command and wait until its completion (or an error).
*
* \param efc Pointer to a Efc instance
* \param command Command to perform.
* \param argument Optional command argument.
*
* \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 )
{
if ( dwUseIAP != 0 )
{
/* Pointer on IAP function in ROM */
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( 0, EEFC_FCR_FKEY(0x5A) | EEFC_FCR_FARG(dwArgument) | EEFC_FCR_FCMD(dwCommand) ) ;
return (efc->EEFC_FSR & (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE)) ;
}
else
{
uint32_t dwStatus ;
efc->EEFC_FCR = EEFC_FCR_FKEY(0x5A) | EEFC_FCR_FARG(dwArgument) | EEFC_FCR_FCMD(dwCommand) ;
do
{
dwStatus = efc->EEFC_FSR ;
}
while ( (dwStatus & EEFC_FSR_FRDY) != EEFC_FSR_FRDY ) ;
return ( dwStatus & (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE) ) ;
}
}
/* ----------------------------------------------------------------------------
* 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.
* ----------------------------------------------------------------------------
*/
/** \addtogroup efc_module Working with EEFC
* The EEFC driver provides the interface to configure and use the EEFC
* peripheral.
*
* 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.
*
* It offers a function to send flash command to EEFC and waits for the
* flash to be ready.
*
* To send flash command, the user could do in either of following way:
* <ul>
* <li>Write a correct key, command and argument in EEFC_FCR. </li>
* <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>
* <li>Once the command is achieved, it can be detected even by polling EEFC_FSR or interrupt.
* </ul>
*
* 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
* flash address into a page number and vice verse.
*
* For more accurate information, please look at the EEFC section of the
* Datasheet.
*
* Related files :\n
* \ref efc.c\n
* \ref efc.h.\n
*/
/*@{*/
/*@}*/
/**
* \file
*
* Implementation of Enhanced Embedded Flash Controller (EEFC).
*
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include "efc.h"
#include <assert.h>
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/**
* \brief Enables the flash ready interrupt source on the EEFC peripheral.
*
* \param efc Pointer to a Efc instance
*/
extern void EFC_EnableFrdyIt( Efc* efc )
{
efc->EEFC_FMR |= EEFC_FMR_FRDY ;
}
/**
* \brief Disables the flash ready interrupt source on the EEFC peripheral.
*
* \param efc Pointer to a Efc instance
*/
extern void EFC_DisableFrdyIt( Efc* efc )
{
efc->EEFC_FMR &= ~((uint32_t)EEFC_FMR_FRDY) ;
}
/**
* \brief Set read/write wait state on the EEFC perpherial.
*
* \param efc Pointer to a Efc instance
* \param cycles the number of wait states in cycle.
*/
extern void EFC_SetWaitState( Efc* efc, uint8_t ucCycles )
{
uint32_t dwValue ;
dwValue = efc->EEFC_FMR ;
dwValue &= ~((uint32_t)EEFC_FMR_FWS_Msk) ;
dwValue |= EEFC_FMR_FWS(ucCycles);
efc->EEFC_FMR = dwValue ;
}
/**
* \brief Returns the current status of the EEFC.
*
* \note Keep in mind that this function clears the value of some status bits (LOCKE, PROGE).
*
* \param efc Pointer to a Efc instance
*/
extern uint32_t EFC_GetStatus( Efc* efc )
{
return efc->EEFC_FSR ;
}
/**
* \brief Returns the result of the last executed command.
*
* \param efc Pointer to a Efc instance
*/
extern uint32_t EFC_GetResult( Efc* efc )
{
return efc->EEFC_FRR ;
}
/**
* \brief Translates the given address page and offset values.
* \note The resulting values are stored in the provided variables if they are not null.
*
* \param efc Pointer to a Efc instance
* \param address Address to translate.
* \param pPage First page accessed.
* \param pOffset Byte offset in first page.
*/
extern void EFC_TranslateAddress( Efc** ppEfc, uint32_t dwAddress, uint16_t* pwPage, uint16_t* pwOffset )
{
Efc *pEfc ;
uint16_t wPage ;
uint16_t wOffset ;
assert( dwAddress >= IFLASH_ADDR ) ;
assert( dwAddress <= (IFLASH_ADDR + IFLASH_SIZE) ) ;
pEfc = EFC ;
wPage = (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 ) ;
/* Store values */
if ( pEfc )
{
*ppEfc = pEfc ;
}
if ( pwPage )
{
*pwPage = wPage ;
}
if ( pwOffset )
{
*pwOffset = wOffset ;
}
}
/**
* \brief Computes the address of a flash access given the page and offset.
*
* \param efc Pointer to a Efc instance
* \param page Page number.
* \param offset Byte offset inside page.
* \param pAddress Computed address (optional).
*/
extern void EFC_ComputeAddress( Efc *efc, uint16_t wPage, uint16_t wOffset, uint32_t *pdwAddress )
{
uint32_t dwAddress ;
assert( efc ) ;
assert( wPage <= IFLASH_NB_OF_PAGES ) ;
assert( wOffset < IFLASH_PAGE_SIZE ) ;
/* Compute address */
dwAddress = IFLASH_ADDR + wPage * IFLASH_PAGE_SIZE + wOffset ;
/* Store result */
if ( pdwAddress != NULL )
{
*pdwAddress = dwAddress ;
}
}
/**
* \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.
* \param efc Pointer to a Efc instance
* \param command Command to execute.
* \param argument Command argument (should be 0 if not used).
*/
extern void EFC_StartCommand( Efc* efc, uint32_t dwCommand, uint32_t dwArgument )
{
/* Check command & argument */
switch ( dwCommand )
{
case EFC_FCMD_WP:
case EFC_FCMD_WPL:
case EFC_FCMD_EWP:
case EFC_FCMD_EWPL:
case EFC_FCMD_SLB:
case EFC_FCMD_CLB:
assert( dwArgument < IFLASH_NB_OF_PAGES ) ;
break ;
case EFC_FCMD_SFB:
case EFC_FCMD_CFB:
assert( dwArgument < 2 ) ;
break;
case EFC_FCMD_GETD:
case EFC_FCMD_EA:
case EFC_FCMD_GLB:
case EFC_FCMD_GFB:
case EFC_FCMD_STUI:
assert( dwArgument == 0 ) ;
break;
default: assert( 0 ) ;
}
/* Start command Embedded flash */
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) ;
}
/**
* \brief Performs the given command and wait until its completion (or an error).
*
* \param efc Pointer to a Efc instance
* \param command Command to perform.
* \param argument Optional command argument.
*
* \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 )
{
if ( dwUseIAP != 0 )
{
/* Pointer on IAP function in ROM */
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( 0, EEFC_FCR_FKEY(0x5A) | EEFC_FCR_FARG(dwArgument) | EEFC_FCR_FCMD(dwCommand) ) ;
return (efc->EEFC_FSR & (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE)) ;
}
else
{
uint32_t dwStatus ;
efc->EEFC_FCR = EEFC_FCR_FKEY(0x5A) | EEFC_FCR_FARG(dwArgument) | EEFC_FCR_FCMD(dwCommand) ;
do
{
dwStatus = efc->EEFC_FSR ;
}
while ( (dwStatus & EEFC_FSR_FRDY) != EEFC_FSR_FRDY ) ;
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
* ----------------------------------------------------------------------------
* Copyright (c) 2010, 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.
* ----------------------------------------------------------------------------
*/
/** \file */
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include "pio.h"
#include "pmc.h"
/*----------------------------------------------------------------------------
* Local functions
*----------------------------------------------------------------------------*/
/**
* \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.
*
* \param pio Pointer to a PIO controller.
* \param mask Bitmask of one or more pin(s) to configure.
* \param enablePullUp Indicates if the pin(s) internal pull-up shall be
* configured.
*/
static void PIO_SetPeripheralA(
Pio *pio,
unsigned int mask,
unsigned char enablePullUp)
{
unsigned int abcdsr;
/* Disable interrupts on the pin(s) */
pio->PIO_IDR = mask;
/* Enable the pull-up(s) if necessary */
if (enablePullUp) {
pio->PIO_PUER = mask;
}
else {
pio->PIO_PUDR = mask;
}
abcdsr = pio->PIO_ABCDSR[0];
pio->PIO_ABCDSR[0] &= (~mask & abcdsr);
abcdsr = pio->PIO_ABCDSR[1];
pio->PIO_ABCDSR[1] &= (~mask & abcdsr);
pio->PIO_PDR = mask;
}
/**
* \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.
*
* \param pio Pointer to a PIO controller.
* \param mask Bitmask of one or more pin(s) to configure.
* \param enablePullUp Indicates if the pin(s) internal pull-up shall be
* configured.
*/
static void PIO_SetPeripheralB(
Pio *pio,
unsigned int mask,
unsigned char enablePullUp)
{
unsigned int abcdsr;
/* Disable interrupts on the pin(s) */
pio->PIO_IDR = mask;
/* Enable the pull-up(s) if necessary */
if (enablePullUp) {
pio->PIO_PUER = mask;
}
else {
pio->PIO_PUDR = mask;
}
abcdsr = pio->PIO_ABCDSR[0];
pio->PIO_ABCDSR[0] = (mask | abcdsr);
abcdsr = pio->PIO_ABCDSR[1];
pio->PIO_ABCDSR[1] &= (~mask & abcdsr);
pio->PIO_PDR = mask;
}
/**
* \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.
*
* \param pio Pointer to a PIO controller.
* \param mask Bitmask of one or more pin(s) to configure.
* \param enablePullUp Indicates if the pin(s) internal pull-up shall be
* configured.
*/
static void PIO_SetPeripheralC(
Pio *pio,
unsigned int mask,
unsigned char enablePullUp)
{
unsigned int abcdsr;
/* Disable interrupts on the pin(s) */
pio->PIO_IDR = mask;
/* Enable the pull-up(s) if necessary */
if (enablePullUp) {
pio->PIO_PUER = mask;
}
else {
pio->PIO_PUDR = mask;
}
abcdsr = pio->PIO_ABCDSR[0];
pio->PIO_ABCDSR[0] &= (~mask & abcdsr);
abcdsr = pio->PIO_ABCDSR[1];
pio->PIO_ABCDSR[1] = (mask | abcdsr);
pio->PIO_PDR = mask;
}
/**
* \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.
*
* \param pio Pointer to a PIO controller.
* \param mask Bitmask of one or more pin(s) to configure.
* \param enablePullUp Indicates if the pin(s) internal pull-up shall be
* configured.
*/
static void PIO_SetPeripheralD(
Pio *pio,
unsigned int mask,
unsigned char enablePullUp)
{
unsigned int abcdsr;
/* Disable interrupts on the pin(s) */
pio->PIO_IDR = mask;
/* Enable the pull-up(s) if necessary */
if (enablePullUp) {
pio->PIO_PUER = mask;
}
else {
pio->PIO_PUDR = mask;
}
abcdsr = pio->PIO_ABCDSR[0];
pio->PIO_ABCDSR[0] = (mask | abcdsr);
abcdsr = pio->PIO_ABCDSR[1];
pio->PIO_ABCDSR[1] = (mask | abcdsr);
pio->PIO_PDR = mask;
}
/**
* \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.
*
* \param pio Pointer to a PIO controller.
* \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 enableFilter Indicates if the glitch filter(s) must be enabled.
*/
static void PIO_SetInput(
Pio *pio,
unsigned int mask,
unsigned char attribute)
{
/* Disable interrupts */
pio->PIO_IDR = mask;
/* Enable pull-up(s) if necessary */
if (attribute & PIO_PULLUP)
pio->PIO_PUER = mask;
else
pio->PIO_PUDR = mask;
/* Enable Input Filter if necessary */
if (attribute & (PIO_DEGLITCH | PIO_DEBOUNCE))
pio->PIO_IFER = mask;
else
pio->PIO_IFDR = mask;
/* Enable de-glitch or de-bounce if necessary */
if (attribute & PIO_DEGLITCH)
{
pio->PIO_IFSCDR = mask;
}
else
{
if (attribute & PIO_DEBOUNCE)
{
pio->PIO_IFSCER = mask;
}
}
/* Configure pin as input */
pio->PIO_ODR = mask;
pio->PIO_PER = mask;
}
/**
* \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
* on the pin(s).
*
* \param pio Pointer to a PIO controller.
* \param mask Bitmask indicating which pin(s) to configure.
* \param defaultValue Default level on the pin(s).
* \param enableMultiDrive Indicates if the pin(s) shall be configured as
* open-drain.
* \param enablePullUp Indicates if the pin shall have its pull-up activated.
*/
static void PIO_SetOutput(
Pio *pio,
unsigned int mask,
unsigned char defaultValue,
unsigned char enableMultiDrive,
unsigned char enablePullUp)
{
/* Disable interrupts */
pio->PIO_IDR = mask;
/* Enable pull-up(s) if necessary */
if (enablePullUp) {
pio->PIO_PUER = mask;
}
else {
pio->PIO_PUDR = mask;
}
/* Enable multi-drive if necessary */
if (enableMultiDrive) {
pio->PIO_MDER = mask;
}
else {
pio->PIO_MDDR = mask;
}
/* Set default value */
if (defaultValue) {
pio->PIO_SODR = mask;
}
else {
pio->PIO_CODR = mask;
}
/* Configure pin(s) as output(s) */
pio->PIO_OER = mask;
pio->PIO_PER = mask;
}
/*----------------------------------------------------------------------------
* Global functions
*----------------------------------------------------------------------------*/
/**
* \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
* 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.
*
* \param list Pointer to a list of Pin instances.
* \param size Size of the Pin list (calculated using PIO_LISTSIZE).
*
* \return 1 if the pins have been configured properly; otherwise 0.
*/
uint8_t PIO_Configure( const Pin *list, uint32_t size )
{
/* Configure pins */
while ( size > 0 )
{
switch ( list->type )
{
case PIO_PERIPH_A:
PIO_SetPeripheralA(list->pio,
list->mask,
(list->attribute & PIO_PULLUP) ? 1 : 0);
break;
case PIO_PERIPH_B:
PIO_SetPeripheralB(list->pio,
list->mask,
(list->attribute & PIO_PULLUP) ? 1 : 0);
break;
case PIO_PERIPH_C:
PIO_SetPeripheralC(list->pio,
list->mask,
(list->attribute & PIO_PULLUP) ? 1 : 0);
break;
case PIO_PERIPH_D:
PIO_SetPeripheralD(list->pio,
list->mask,
(list->attribute & PIO_PULLUP) ? 1 : 0);
break;
case PIO_INPUT:
PMC_EnablePeripheral(list->id);
PIO_SetInput(list->pio,
list->mask,
list->attribute);
break;
case PIO_OUTPUT_0:
case PIO_OUTPUT_1:
PIO_SetOutput(list->pio,
list->mask,
(list->type == PIO_OUTPUT_1),
(list->attribute & PIO_OPENDRAIN) ? 1 : 0,
(list->attribute & PIO_PULLUP) ? 1 : 0);
break;
default: return 0;
}
list++;
size--;
}
return 1;
}
/**
* \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
* controller will memorize the value they are changed to outputs.
*
* \param pin Pointer to a Pin instance describing one or more pins.
*/
void PIO_Set(const Pin *pin)
{
pin->pio->PIO_SODR = pin->mask;
}
/**
* \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
* controller will memorize the value they are changed to outputs.
*
* \param pin Pointer to a Pin instance describing one or more pins.
*/
void PIO_Clear(const Pin *pin)
{
pin->pio->PIO_CODR = pin->mask;
}
/**
* \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
* is being read on the pin. To return the supposed output value of a pin, use
* PIO_GetOutputDataStatus() instead.
*
* \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
* a high level; otherwise 0.
*/
unsigned char PIO_Get( const Pin *pin )
{
unsigned int reg ;
if ( (pin->type == PIO_OUTPUT_0) || (pin->type == PIO_OUTPUT_1) )
{
reg = pin->pio->PIO_ODSR ;
}
else
{
reg = pin->pio->PIO_PDSR ;
}
if ( (reg & pin->mask) == 0 )
{
return 0 ;
}
else
{
return 1 ;
}
}
/**
* \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).
* To get the actual value of the pin, use PIO_Get() instead.
*
* \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
* to output a high level; otherwise 0.
*/
unsigned char PIO_GetOutputDataStatus(const Pin *pin)
{
if ((pin->pio->PIO_ODSR & pin->mask) == 0) {
return 0;
}
else {
return 1;
}
}
/*
* \brief Configures Glitch or Debouncing filter for input.
*
* \param pin Pointer to a Pin instance describing one or more pins.
* \param cuttoff Cutt off frequency for debounce filter.
*/
void PIO_SetDebounceFilter( const Pin *pin, uint32_t cuttoff )
{
Pio *pio = pin->pio;
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 */
}
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2010, 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.
* ----------------------------------------------------------------------------
*/
/** \file */
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include "pio.h"
#include "pmc.h"
/*----------------------------------------------------------------------------
* Local functions
*----------------------------------------------------------------------------*/
/**
* \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.
*
* \param pio Pointer to a PIO controller.
* \param mask Bitmask of one or more pin(s) to configure.
* \param enablePullUp Indicates if the pin(s) internal pull-up shall be
* configured.
*/
static void PIO_SetPeripheralA(
Pio *pio,
unsigned int mask,
unsigned char enablePullUp)
{
unsigned int abcdsr;
/* Disable interrupts on the pin(s) */
pio->PIO_IDR = mask;
/* Enable the pull-up(s) if necessary */
if (enablePullUp) {
pio->PIO_PUER = mask;
}
else {
pio->PIO_PUDR = mask;
}
abcdsr = pio->PIO_ABCDSR[0];
pio->PIO_ABCDSR[0] &= (~mask & abcdsr);
abcdsr = pio->PIO_ABCDSR[1];
pio->PIO_ABCDSR[1] &= (~mask & abcdsr);
pio->PIO_PDR = mask;
}
/**
* \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.
*
* \param pio Pointer to a PIO controller.
* \param mask Bitmask of one or more pin(s) to configure.
* \param enablePullUp Indicates if the pin(s) internal pull-up shall be
* configured.
*/
static void PIO_SetPeripheralB(
Pio *pio,
unsigned int mask,
unsigned char enablePullUp)
{
unsigned int abcdsr;
/* Disable interrupts on the pin(s) */
pio->PIO_IDR = mask;
/* Enable the pull-up(s) if necessary */
if (enablePullUp) {
pio->PIO_PUER = mask;
}
else {
pio->PIO_PUDR = mask;
}
abcdsr = pio->PIO_ABCDSR[0];
pio->PIO_ABCDSR[0] = (mask | abcdsr);
abcdsr = pio->PIO_ABCDSR[1];
pio->PIO_ABCDSR[1] &= (~mask & abcdsr);
pio->PIO_PDR = mask;
}
/**
* \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.
*
* \param pio Pointer to a PIO controller.
* \param mask Bitmask of one or more pin(s) to configure.
* \param enablePullUp Indicates if the pin(s) internal pull-up shall be
* configured.
*/
static void PIO_SetPeripheralC(
Pio *pio,
unsigned int mask,
unsigned char enablePullUp)
{
unsigned int abcdsr;
/* Disable interrupts on the pin(s) */
pio->PIO_IDR = mask;
/* Enable the pull-up(s) if necessary */
if (enablePullUp) {
pio->PIO_PUER = mask;
}
else {
pio->PIO_PUDR = mask;
}
abcdsr = pio->PIO_ABCDSR[0];
pio->PIO_ABCDSR[0] &= (~mask & abcdsr);
abcdsr = pio->PIO_ABCDSR[1];
pio->PIO_ABCDSR[1] = (mask | abcdsr);
pio->PIO_PDR = mask;
}
/**
* \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.
*
* \param pio Pointer to a PIO controller.
* \param mask Bitmask of one or more pin(s) to configure.
* \param enablePullUp Indicates if the pin(s) internal pull-up shall be
* configured.
*/
static void PIO_SetPeripheralD(
Pio *pio,
unsigned int mask,
unsigned char enablePullUp)
{
unsigned int abcdsr;
/* Disable interrupts on the pin(s) */
pio->PIO_IDR = mask;
/* Enable the pull-up(s) if necessary */
if (enablePullUp) {
pio->PIO_PUER = mask;
}
else {
pio->PIO_PUDR = mask;
}
abcdsr = pio->PIO_ABCDSR[0];
pio->PIO_ABCDSR[0] = (mask | abcdsr);
abcdsr = pio->PIO_ABCDSR[1];
pio->PIO_ABCDSR[1] = (mask | abcdsr);
pio->PIO_PDR = mask;
}
/**
* \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.
*
* \param pio Pointer to a PIO controller.
* \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 enableFilter Indicates if the glitch filter(s) must be enabled.
*/
static void PIO_SetInput(
Pio *pio,
unsigned int mask,
unsigned char attribute)
{
/* Disable interrupts */
pio->PIO_IDR = mask;
/* Enable pull-up(s) if necessary */
if (attribute & PIO_PULLUP)
pio->PIO_PUER = mask;
else
pio->PIO_PUDR = mask;
/* Enable Input Filter if necessary */
if (attribute & (PIO_DEGLITCH | PIO_DEBOUNCE))
pio->PIO_IFER = mask;
else
pio->PIO_IFDR = mask;
/* Enable de-glitch or de-bounce if necessary */
if (attribute & PIO_DEGLITCH)
{
pio->PIO_IFSCDR = mask;
}
else
{
if (attribute & PIO_DEBOUNCE)
{
pio->PIO_IFSCER = mask;
}
}
/* Configure pin as input */
pio->PIO_ODR = mask;
pio->PIO_PER = mask;
}
/**
* \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
* on the pin(s).
*
* \param pio Pointer to a PIO controller.
* \param mask Bitmask indicating which pin(s) to configure.
* \param defaultValue Default level on the pin(s).
* \param enableMultiDrive Indicates if the pin(s) shall be configured as
* open-drain.
* \param enablePullUp Indicates if the pin shall have its pull-up activated.
*/
static void PIO_SetOutput(
Pio *pio,
unsigned int mask,
unsigned char defaultValue,
unsigned char enableMultiDrive,
unsigned char enablePullUp)
{
/* Disable interrupts */
pio->PIO_IDR = mask;
/* Enable pull-up(s) if necessary */
if (enablePullUp) {
pio->PIO_PUER = mask;
}
else {
pio->PIO_PUDR = mask;
}
/* Enable multi-drive if necessary */
if (enableMultiDrive) {
pio->PIO_MDER = mask;
}
else {
pio->PIO_MDDR = mask;
}
/* Set default value */
if (defaultValue) {
pio->PIO_SODR = mask;
}
else {
pio->PIO_CODR = mask;
}
/* Configure pin(s) as output(s) */
pio->PIO_OER = mask;
pio->PIO_PER = mask;
}
/*----------------------------------------------------------------------------
* Global functions
*----------------------------------------------------------------------------*/
/**
* \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
* 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.
*
* \param list Pointer to a list of Pin instances.
* \param size Size of the Pin list (calculated using PIO_LISTSIZE).
*
* \return 1 if the pins have been configured properly; otherwise 0.
*/
uint8_t PIO_Configure( const Pin *list, uint32_t size )
{
/* Configure pins */
while ( size > 0 )
{
switch ( list->type )
{
case PIO_PERIPH_A:
PIO_SetPeripheralA(list->pio,
list->mask,
(list->attribute & PIO_PULLUP) ? 1 : 0);
break;
case PIO_PERIPH_B:
PIO_SetPeripheralB(list->pio,
list->mask,
(list->attribute & PIO_PULLUP) ? 1 : 0);
break;
case PIO_PERIPH_C:
PIO_SetPeripheralC(list->pio,
list->mask,
(list->attribute & PIO_PULLUP) ? 1 : 0);
break;
case PIO_PERIPH_D:
PIO_SetPeripheralD(list->pio,
list->mask,
(list->attribute & PIO_PULLUP) ? 1 : 0);
break;
case PIO_INPUT:
PMC_EnablePeripheral(list->id);
PIO_SetInput(list->pio,
list->mask,
list->attribute);
break;
case PIO_OUTPUT_0:
case PIO_OUTPUT_1:
PIO_SetOutput(list->pio,
list->mask,
(list->type == PIO_OUTPUT_1),
(list->attribute & PIO_OPENDRAIN) ? 1 : 0,
(list->attribute & PIO_PULLUP) ? 1 : 0);
break;
default: return 0;
}
list++;
size--;
}
return 1;
}
/**
* \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
* controller will memorize the value they are changed to outputs.
*
* \param pin Pointer to a Pin instance describing one or more pins.
*/
void PIO_Set(const Pin *pin)
{
pin->pio->PIO_SODR = pin->mask;
}
/**
* \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
* controller will memorize the value they are changed to outputs.
*
* \param pin Pointer to a Pin instance describing one or more pins.
*/
void PIO_Clear(const Pin *pin)
{
pin->pio->PIO_CODR = pin->mask;
}
/**
* \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
* is being read on the pin. To return the supposed output value of a pin, use
* PIO_GetOutputDataStatus() instead.
*
* \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
* a high level; otherwise 0.
*/
unsigned char PIO_Get( const Pin *pin )
{
unsigned int reg ;
if ( (pin->type == PIO_OUTPUT_0) || (pin->type == PIO_OUTPUT_1) )
{
reg = pin->pio->PIO_ODSR ;
}
else
{
reg = pin->pio->PIO_PDSR ;
}
if ( (reg & pin->mask) == 0 )
{
return 0 ;
}
else
{
return 1 ;
}
}
/**
* \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).
* To get the actual value of the pin, use PIO_Get() instead.
*
* \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
* to output a high level; otherwise 0.
*/
unsigned char PIO_GetOutputDataStatus(const Pin *pin)
{
if ((pin->pio->PIO_ODSR & pin->mask) == 0) {
return 0;
}
else {
return 1;
}
}
/*
* \brief Configures Glitch or Debouncing filter for input.
*
* \param pin Pointer to a Pin instance describing one or more pins.
* \param cuttoff Cutt off frequency for debounce filter.
*/
void PIO_SetDebounceFilter( const Pin *pin, uint32_t cuttoff )
{
Pio *pio = pin->pio;
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 */
}

View File

@@ -1,315 +1,315 @@
/* ----------------------------------------------------------------------------
* 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.
* ----------------------------------------------------------------------------
*/
/*
* \file
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include <assert.h>
/*----------------------------------------------------------------------------
* Local definitions
*----------------------------------------------------------------------------*/
/* Maximum number of interrupt sources that can be defined. This
* constant can be increased, but the current value is the smallest possible
* that will be compatible with all existing projects. */
#define MAX_INTERRUPT_SOURCES 7
/*----------------------------------------------------------------------------
* Local types
*----------------------------------------------------------------------------*/
/**
* Describes a PIO interrupt source, including the PIO instance triggering the
* interrupt and the associated interrupt handler.
*/
typedef struct _InterruptSource
{
/* Pointer to the source pin instance. */
const Pin *pPin;
/* Interrupt handler. */
void (*handler)( const Pin* ) ;
} InterruptSource ;
/*----------------------------------------------------------------------------
* Local variables
*----------------------------------------------------------------------------*/
/* List of interrupt sources. */
static InterruptSource _aIntSources[MAX_INTERRUPT_SOURCES] ;
/* Number of currently defined interrupt sources. */
static uint32_t _dwNumSources = 0;
/*----------------------------------------------------------------------------
* Local Functions
*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/**
* \brief Stub, to handling all PIO Capture interrupts, if not defined.
*/
/*----------------------------------------------------------------------------*/
extern WEAK void PIO_CaptureHandler( void )
{
}
/**
* \brief Handles all interrupts on the given PIO controller.
* \param id PIO controller ID.
* \param pPio PIO controller base address.
*/
extern void PioInterruptHandler( uint32_t id, Pio *pPio )
{
uint32_t status;
uint32_t i;
/* Read PIO controller status */
status = pPio->PIO_ISR;
status &= pPio->PIO_IMR;
/* Check pending events */
if ( status != 0 )
{
TRACE_DEBUG( "PIO interrupt on PIO controller #%" PRIu32 "\n\r", id ) ;
/* Find triggering source */
i = 0;
while ( status != 0 )
{
/* There cannot be an unconfigured source enabled. */
assert(i < _dwNumSources);
/* Source is configured on the same controller */
if (_aIntSources[i].pPin->id == id)
{
/* Source has PIOs whose statuses have changed */
if ( (status & _aIntSources[i].pPin->mask) != 0 )
{
TRACE_DEBUG( "Interrupt source #%" PRIu32 " triggered\n\r", i ) ;
_aIntSources[i].handler(_aIntSources[i].pPin);
status &= ~(_aIntSources[i].pPin->mask);
}
}
i++;
}
}
}
/*----------------------------------------------------------------------------
* Global Functions
*----------------------------------------------------------------------------*/
/**
* \brief Parallel IO Controller A interrupt handler
* \Redefined PIOA interrupt handler for NVIC interrupt table.
*/
extern void PIOA_IrqHandler( void )
{
if ( PIOA->PIO_PCISR != 0 )
{
PIO_CaptureHandler() ;
}
PioInterruptHandler( ID_PIOA, PIOA ) ;
}
/**
* \brief Parallel IO Controller B interrupt handler
* \Redefined PIOB interrupt handler for NVIC interrupt table.
*/
extern void PIOB_IrqHandler( void )
{
PioInterruptHandler( ID_PIOB, PIOB ) ;
}
/**
* \brief Parallel IO Controller C interrupt handler
* \Redefined PIOC interrupt handler for NVIC interrupt table.
*/
extern void PIOC_IrqHandler( void )
{
PioInterruptHandler( ID_PIOC, PIOC ) ;
}
/**
* \brief Initializes the PIO interrupt management logic
*
* The desired priority of PIO interrupts must be provided.
* Calling this function multiple times result in the reset of currently
* configured interrupts.
*
* \param priority PIO controller interrupts priority.
*/
extern void PIO_InitializeInterrupts( uint32_t dwPriority )
{
TRACE_DEBUG( "PIO_Initialize()\n\r" ) ;
/* Reset sources */
_dwNumSources = 0 ;
/* Configure PIO interrupt sources */
TRACE_DEBUG( "PIO_Initialize: Configuring PIOA\n\r" ) ;
PMC_EnablePeripheral( ID_PIOA ) ;
PIOA->PIO_ISR ;
PIOA->PIO_IDR = 0xFFFFFFFF ;
NVIC_DisableIRQ( PIOA_IRQn ) ;
NVIC_ClearPendingIRQ( PIOA_IRQn ) ;
NVIC_SetPriority( PIOA_IRQn, dwPriority ) ;
NVIC_EnableIRQ( PIOA_IRQn ) ;
TRACE_DEBUG( "PIO_Initialize: Configuring PIOB\n\r" ) ;
PMC_EnablePeripheral( ID_PIOB ) ;
PIOB->PIO_ISR ;
PIOB->PIO_IDR = 0xFFFFFFFF ;
NVIC_DisableIRQ( PIOB_IRQn ) ;
NVIC_ClearPendingIRQ( PIOB_IRQn ) ;
NVIC_SetPriority( PIOB_IRQn, dwPriority ) ;
NVIC_EnableIRQ( PIOB_IRQn ) ;
TRACE_DEBUG( "PIO_Initialize: Configuring PIOC\n\r" ) ;
PMC_EnablePeripheral( ID_PIOC ) ;
PIOC->PIO_ISR ;
PIOC->PIO_IDR = 0xFFFFFFFF ;
NVIC_DisableIRQ( PIOC_IRQn ) ;
NVIC_ClearPendingIRQ( PIOC_IRQn ) ;
NVIC_SetPriority( PIOC_IRQn, dwPriority ) ;
NVIC_EnableIRQ( PIOC_IRQn ) ;
}
/**
* 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
* pin as its parameter (enabling different pin instances to share the same
* handler).
* \param pPin Pointer to a Pin instance.
* \param handler Interrupt handler function pointer.
*/
extern void PIO_ConfigureIt( const Pin *pPin, void (*handler)( const Pin* ) )
{
Pio* pio ;
InterruptSource* pSource ;
TRACE_DEBUG( "PIO_ConfigureIt()\n\r" ) ;
assert( pPin ) ;
pio = pPin->pio ;
assert( _dwNumSources < MAX_INTERRUPT_SOURCES ) ;
/* Define new source */
TRACE_DEBUG( "PIO_ConfigureIt: Defining new source #%" PRIu32 ".\n\r", _dwNumSources ) ;
pSource = &(_aIntSources[_dwNumSources]) ;
pSource->pPin = pPin ;
pSource->handler = handler ;
_dwNumSources++ ;
/* PIO3 with additional interrupt support
* Configure additional interrupt mode registers */
if ( pPin->attribute & PIO_IT_AIME )
{
// enable additional interrupt mode
pio->PIO_AIMER = pPin->mask ;
// if bit field of selected pin is 1, set as Rising Edge/High level detection event
if ( pPin->attribute & PIO_IT_RE_OR_HL )
{
pio->PIO_REHLSR = pPin->mask ;
}
else
{
pio->PIO_FELLSR = pPin->mask;
}
/* if bit field of selected pin is 1, set as edge detection source */
if (pPin->attribute & PIO_IT_EDGE)
pio->PIO_ESR = pPin->mask;
else
pio->PIO_LSR = pPin->mask;
}
else
{
/* disable additional interrupt mode */
pio->PIO_AIMDR = pPin->mask;
}
}
/**
* Enables the given interrupt source if it has been configured. The status
* register of the corresponding PIO controller is cleared prior to enabling
* the interrupt.
* \param pPin Interrupt source to enable.
*/
extern void PIO_EnableIt( const Pin *pPin )
{
TRACE_DEBUG( "PIO_EnableIt()\n\r" ) ;
assert( pPin != NULL ) ;
#ifndef NOASSERT
uint32_t i = 0;
uint32_t dwFound = 0;
while ( (i < _dwNumSources) && !dwFound )
{
if ( _aIntSources[i].pPin == pPin )
{
dwFound = 1 ;
}
i++ ;
}
assert( dwFound != 0 ) ;
#endif
pPin->pio->PIO_ISR;
pPin->pio->PIO_IER = pPin->mask ;
}
/**
* Disables a given interrupt source, with no added side effects.
*
* \param pPin Interrupt source to disable.
*/
extern void PIO_DisableIt( const Pin *pPin )
{
assert( pPin != NULL ) ;
TRACE_DEBUG( "PIO_DisableIt()\n\r" ) ;
pPin->pio->PIO_IDR = pPin->mask;
}
/* ----------------------------------------------------------------------------
* 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.
* ----------------------------------------------------------------------------
*/
/*
* \file
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include <assert.h>
/*----------------------------------------------------------------------------
* Local definitions
*----------------------------------------------------------------------------*/
/* Maximum number of interrupt sources that can be defined. This
* constant can be increased, but the current value is the smallest possible
* that will be compatible with all existing projects. */
#define MAX_INTERRUPT_SOURCES 7
/*----------------------------------------------------------------------------
* Local types
*----------------------------------------------------------------------------*/
/**
* Describes a PIO interrupt source, including the PIO instance triggering the
* interrupt and the associated interrupt handler.
*/
typedef struct _InterruptSource
{
/* Pointer to the source pin instance. */
const Pin *pPin;
/* Interrupt handler. */
void (*handler)( const Pin* ) ;
} InterruptSource ;
/*----------------------------------------------------------------------------
* Local variables
*----------------------------------------------------------------------------*/
/* List of interrupt sources. */
static InterruptSource _aIntSources[MAX_INTERRUPT_SOURCES] ;
/* Number of currently defined interrupt sources. */
static uint32_t _dwNumSources = 0;
/*----------------------------------------------------------------------------
* Local Functions
*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/**
* \brief Stub, to handling all PIO Capture interrupts, if not defined.
*/
/*----------------------------------------------------------------------------*/
extern WEAK void PIO_CaptureHandler( void )
{
}
/**
* \brief Handles all interrupts on the given PIO controller.
* \param id PIO controller ID.
* \param pPio PIO controller base address.
*/
extern void PioInterruptHandler( uint32_t id, Pio *pPio )
{
uint32_t status;
uint32_t i;
/* Read PIO controller status */
status = pPio->PIO_ISR;
status &= pPio->PIO_IMR;
/* Check pending events */
if ( status != 0 )
{
TRACE_DEBUG( "PIO interrupt on PIO controller #%" PRIu32 "\n\r", id ) ;
/* Find triggering source */
i = 0;
while ( status != 0 )
{
/* There cannot be an unconfigured source enabled. */
assert(i < _dwNumSources);
/* Source is configured on the same controller */
if (_aIntSources[i].pPin->id == id)
{
/* Source has PIOs whose statuses have changed */
if ( (status & _aIntSources[i].pPin->mask) != 0 )
{
TRACE_DEBUG( "Interrupt source #%" PRIu32 " triggered\n\r", i ) ;
_aIntSources[i].handler(_aIntSources[i].pPin);
status &= ~(_aIntSources[i].pPin->mask);
}
}
i++;
}
}
}
/*----------------------------------------------------------------------------
* Global Functions
*----------------------------------------------------------------------------*/
/**
* \brief Parallel IO Controller A interrupt handler
* \Redefined PIOA interrupt handler for NVIC interrupt table.
*/
extern void PIOA_IrqHandler( void )
{
if ( PIOA->PIO_PCISR != 0 )
{
PIO_CaptureHandler() ;
}
PioInterruptHandler( ID_PIOA, PIOA ) ;
}
/**
* \brief Parallel IO Controller B interrupt handler
* \Redefined PIOB interrupt handler for NVIC interrupt table.
*/
extern void PIOB_IrqHandler( void )
{
PioInterruptHandler( ID_PIOB, PIOB ) ;
}
/**
* \brief Parallel IO Controller C interrupt handler
* \Redefined PIOC interrupt handler for NVIC interrupt table.
*/
extern void PIOC_IrqHandler( void )
{
PioInterruptHandler( ID_PIOC, PIOC ) ;
}
/**
* \brief Initializes the PIO interrupt management logic
*
* The desired priority of PIO interrupts must be provided.
* Calling this function multiple times result in the reset of currently
* configured interrupts.
*
* \param priority PIO controller interrupts priority.
*/
extern void PIO_InitializeInterrupts( uint32_t dwPriority )
{
TRACE_DEBUG( "PIO_Initialize()\n\r" ) ;
/* Reset sources */
_dwNumSources = 0 ;
/* Configure PIO interrupt sources */
TRACE_DEBUG( "PIO_Initialize: Configuring PIOA\n\r" ) ;
PMC_EnablePeripheral( ID_PIOA ) ;
PIOA->PIO_ISR ;
PIOA->PIO_IDR = 0xFFFFFFFF ;
NVIC_DisableIRQ( PIOA_IRQn ) ;
NVIC_ClearPendingIRQ( PIOA_IRQn ) ;
NVIC_SetPriority( PIOA_IRQn, dwPriority ) ;
NVIC_EnableIRQ( PIOA_IRQn ) ;
TRACE_DEBUG( "PIO_Initialize: Configuring PIOB\n\r" ) ;
PMC_EnablePeripheral( ID_PIOB ) ;
PIOB->PIO_ISR ;
PIOB->PIO_IDR = 0xFFFFFFFF ;
NVIC_DisableIRQ( PIOB_IRQn ) ;
NVIC_ClearPendingIRQ( PIOB_IRQn ) ;
NVIC_SetPriority( PIOB_IRQn, dwPriority ) ;
NVIC_EnableIRQ( PIOB_IRQn ) ;
TRACE_DEBUG( "PIO_Initialize: Configuring PIOC\n\r" ) ;
PMC_EnablePeripheral( ID_PIOC ) ;
PIOC->PIO_ISR ;
PIOC->PIO_IDR = 0xFFFFFFFF ;
NVIC_DisableIRQ( PIOC_IRQn ) ;
NVIC_ClearPendingIRQ( PIOC_IRQn ) ;
NVIC_SetPriority( PIOC_IRQn, dwPriority ) ;
NVIC_EnableIRQ( PIOC_IRQn ) ;
}
/**
* 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
* pin as its parameter (enabling different pin instances to share the same
* handler).
* \param pPin Pointer to a Pin instance.
* \param handler Interrupt handler function pointer.
*/
extern void PIO_ConfigureIt( const Pin *pPin, void (*handler)( const Pin* ) )
{
Pio* pio ;
InterruptSource* pSource ;
TRACE_DEBUG( "PIO_ConfigureIt()\n\r" ) ;
assert( pPin ) ;
pio = pPin->pio ;
assert( _dwNumSources < MAX_INTERRUPT_SOURCES ) ;
/* Define new source */
TRACE_DEBUG( "PIO_ConfigureIt: Defining new source #%" PRIu32 ".\n\r", _dwNumSources ) ;
pSource = &(_aIntSources[_dwNumSources]) ;
pSource->pPin = pPin ;
pSource->handler = handler ;
_dwNumSources++ ;
/* PIO3 with additional interrupt support
* Configure additional interrupt mode registers */
if ( pPin->attribute & PIO_IT_AIME )
{
// enable additional interrupt mode
pio->PIO_AIMER = pPin->mask ;
// if bit field of selected pin is 1, set as Rising Edge/High level detection event
if ( pPin->attribute & PIO_IT_RE_OR_HL )
{
pio->PIO_REHLSR = pPin->mask ;
}
else
{
pio->PIO_FELLSR = pPin->mask;
}
/* if bit field of selected pin is 1, set as edge detection source */
if (pPin->attribute & PIO_IT_EDGE)
pio->PIO_ESR = pPin->mask;
else
pio->PIO_LSR = pPin->mask;
}
else
{
/* disable additional interrupt mode */
pio->PIO_AIMDR = pPin->mask;
}
}
/**
* Enables the given interrupt source if it has been configured. The status
* register of the corresponding PIO controller is cleared prior to enabling
* the interrupt.
* \param pPin Interrupt source to enable.
*/
extern void PIO_EnableIt( const Pin *pPin )
{
TRACE_DEBUG( "PIO_EnableIt()\n\r" ) ;
assert( pPin != NULL ) ;
#ifndef NOASSERT
uint32_t i = 0;
uint32_t dwFound = 0;
while ( (i < _dwNumSources) && !dwFound )
{
if ( _aIntSources[i].pPin == pPin )
{
dwFound = 1 ;
}
i++ ;
}
assert( dwFound != 0 ) ;
#endif
pPin->pio->PIO_ISR;
pPin->pio->PIO_IER = pPin->mask ;
}
/**
* Disables a given interrupt source, with no added side effects.
*
* \param pPin Interrupt source to disable.
*/
extern void PIO_DisableIt( const Pin *pPin )
{
assert( pPin != NULL ) ;
TRACE_DEBUG( "PIO_DisableIt()\n\r" ) ;
pPin->pio->PIO_IDR = pPin->mask;
}

View File

@@ -1,168 +1,168 @@
/* ----------------------------------------------------------------------------
* 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 "chip.h"
#include "trace.h"
#include <assert.h>
/*----------------------------------------------------------------------------
* Local definitions
*----------------------------------------------------------------------------*/
#define MASK_STATUS0 0xFFFFFFFC
#define MASK_STATUS1 0xFFFFFFFF
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/**
* \brief Enables the clock of a peripheral. The peripheral ID is used
* to identify which peripheral is targetted.
*
* \note The ID must NOT be shifted (i.e. 1 << ID_xxx).
*
* \param id Peripheral ID (ID_xxx).
*/
extern void PMC_EnablePeripheral( uint32_t dwId )
{
assert( dwId < 35 ) ;
if ( dwId < 32 )
{
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 ) ;
}
else
{
PMC->PMC_PCER0 = 1 << dwId ;
}
}
else
{
dwId -= 32;
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 ) ;
}
else
{
PMC->PMC_PCER1 = 1 << dwId ;
}
}
}
/**
* \brief Disables the clock of a peripheral. The peripheral ID is used
* to identify which peripheral is targetted.
*
* \note The ID must NOT be shifted (i.e. 1 << ID_xxx).
*
* \param id Peripheral ID (ID_xxx).
*/
extern void PMC_DisablePeripheral( uint32_t dwId )
{
assert( dwId < 35 ) ;
if ( dwId < 32 )
{
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 ) ;
}
else
{
PMC->PMC_PCDR0 = 1 << dwId ;
}
}
else
{
dwId -= 32 ;
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 ) ;
}
else
{
PMC->PMC_PCDR1 = 1 << dwId ;
}
}
}
/**
* \brief Enable all the periph clock via PMC.
*/
extern void PMC_EnableAllPeripherals( void )
{
PMC->PMC_PCER0 = MASK_STATUS0 ;
while ( (PMC->PMC_PCSR0 & MASK_STATUS0) != MASK_STATUS0 ) ;
PMC->PMC_PCER1 = MASK_STATUS1 ;
while ( (PMC->PMC_PCSR1 & MASK_STATUS1) != MASK_STATUS1 ) ;
TRACE_DEBUG( "Enable all periph clocks\n\r" ) ;
}
/**
* \brief Disable all the periph clock via PMC.
*/
extern void PMC_DisableAllPeripherals( void )
{
PMC->PMC_PCDR0 = MASK_STATUS0 ;
while ( (PMC->PMC_PCSR0 & MASK_STATUS0) != 0 ) ;
PMC->PMC_PCDR1 = MASK_STATUS1 ;
while ( (PMC->PMC_PCSR1 & MASK_STATUS1) != 0 ) ;
TRACE_DEBUG( "Disable all periph clocks\n\r" ) ;
}
/**
* \brief Get Periph Status for the given peripheral ID.
*
* \param id Peripheral ID (ID_xxx).
*/
extern uint32_t PMC_IsPeriphEnabled( uint32_t dwId )
{
assert( dwId < 35 ) ;
if ( dwId < 32 )
{
return ( PMC->PMC_PCSR0 & (1 << dwId) ) ;
}
else {
return ( PMC->PMC_PCSR1 & (1 << (dwId - 32)) ) ;
}
}
/* ----------------------------------------------------------------------------
* 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 "chip.h"
#include "trace.h"
#include <assert.h>
/*----------------------------------------------------------------------------
* Local definitions
*----------------------------------------------------------------------------*/
#define MASK_STATUS0 0xFFFFFFFC
#define MASK_STATUS1 0xFFFFFFFF
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/**
* \brief Enables the clock of a peripheral. The peripheral ID is used
* to identify which peripheral is targetted.
*
* \note The ID must NOT be shifted (i.e. 1 << ID_xxx).
*
* \param id Peripheral ID (ID_xxx).
*/
extern void PMC_EnablePeripheral( uint32_t dwId )
{
assert( dwId < 35 ) ;
if ( dwId < 32 )
{
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 ) ;
}
else
{
PMC->PMC_PCER0 = 1 << dwId ;
}
}
else
{
dwId -= 32;
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 ) ;
}
else
{
PMC->PMC_PCER1 = 1 << dwId ;
}
}
}
/**
* \brief Disables the clock of a peripheral. The peripheral ID is used
* to identify which peripheral is targetted.
*
* \note The ID must NOT be shifted (i.e. 1 << ID_xxx).
*
* \param id Peripheral ID (ID_xxx).
*/
extern void PMC_DisablePeripheral( uint32_t dwId )
{
assert( dwId < 35 ) ;
if ( dwId < 32 )
{
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 ) ;
}
else
{
PMC->PMC_PCDR0 = 1 << dwId ;
}
}
else
{
dwId -= 32 ;
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 ) ;
}
else
{
PMC->PMC_PCDR1 = 1 << dwId ;
}
}
}
/**
* \brief Enable all the periph clock via PMC.
*/
extern void PMC_EnableAllPeripherals( void )
{
PMC->PMC_PCER0 = MASK_STATUS0 ;
while ( (PMC->PMC_PCSR0 & MASK_STATUS0) != MASK_STATUS0 ) ;
PMC->PMC_PCER1 = MASK_STATUS1 ;
while ( (PMC->PMC_PCSR1 & MASK_STATUS1) != MASK_STATUS1 ) ;
TRACE_DEBUG( "Enable all periph clocks\n\r" ) ;
}
/**
* \brief Disable all the periph clock via PMC.
*/
extern void PMC_DisableAllPeripherals( void )
{
PMC->PMC_PCDR0 = MASK_STATUS0 ;
while ( (PMC->PMC_PCSR0 & MASK_STATUS0) != 0 ) ;
PMC->PMC_PCDR1 = MASK_STATUS1 ;
while ( (PMC->PMC_PCSR1 & MASK_STATUS1) != 0 ) ;
TRACE_DEBUG( "Disable all periph clocks\n\r" ) ;
}
/**
* \brief Get Periph Status for the given peripheral ID.
*
* \param id Peripheral ID (ID_xxx).
*/
extern uint32_t PMC_IsPeriphEnabled( uint32_t dwId )
{
assert( dwId < 35 ) ;
if ( dwId < 32 )
{
return ( PMC->PMC_PCSR0 & (1 << dwId) ) ;
}
else {
return ( PMC->PMC_PCSR1 & (1 << (dwId - 32)) ) ;
}
}

View File

@@ -1,352 +1,352 @@
/* ----------------------------------------------------------------------------
* 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.
* ----------------------------------------------------------------------------
*/
/** \addtogroup spi_module Working with SPI
* The SPI driver provides the interface to configure and use the SPI
* peripheral.
*
* The Serial Peripheral Interface (SPI) circuit is a synchronous serial
* data link that provides communication with external devices in Master
* or Slave Mode.
*
* To use the SPI, the user has to follow these few steps:
* -# Enable the SPI pins required by the application (see pio.h).
* -# Configure the SPI using the \ref SPI_Configure(). This enables the
* peripheral clock. The mode register is loaded with the given value.
* -# Configure all the necessary chip selects with \ref SPI_ConfigureNPCS().
* -# Enable the SPI by calling \ref SPI_Enable().
* -# 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.
* -# Send/receive data using the PDC with the \ref SPI_WriteBuffer() and
* \ref SPI_ReadBuffer() functions.
* -# Disable the SPI by calling \ref SPI_Disable().
*
* For more accurate information, please look at the SPI section of the
* Datasheet.
*
* Related files :\n
* \ref spi.c\n
* \ref spi.h.\n
*/
/*@{*/
/*@}*/
/**
* \file
*
* Implementation of Serial Peripheral Interface (SPI) controller.
*
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include "pmc.h"
#include "spi.h"
#include <stdint.h>
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/**
* \brief Enables a SPI peripheral.
*
* \param spi Pointer to an Spi instance.
*/
extern void SPI_Enable( Spi* spi )
{
spi->SPI_CR = SPI_CR_SPIEN ;
}
/**
* \brief Disables a SPI peripheral.
*
* \param spi Pointer to an Spi instance.
*/
extern void SPI_Disable( Spi* spi )
{
spi->SPI_CR = SPI_CR_SPIDIS ;
}
/**
* \brief Enables one or more interrupt sources of a SPI peripheral.
*
* \param spi Pointer to an Spi instance.
* \param sources Bitwise OR of selected interrupt sources.
*/
extern void SPI_EnableIt( Spi* spi, uint32_t dwSources )
{
spi->SPI_IER = dwSources ;
}
/**
* \brief Disables one or more interrupt sources of a SPI peripheral.
*
* \param spi Pointer to an Spi instance.
* \param sources Bitwise OR of selected interrupt sources.
*/
extern void SPI_DisableIt( Spi* spi, uint32_t dwSources )
{
spi->SPI_IDR = dwSources ;
}
/**
* \brief Configures a SPI peripheral as specified. The configuration can be computed
* using several macros (see \ref spi_configuration_macros).
*
* \param spi Pointer to an Spi instance.
* \param id Peripheral ID of the SPI.
* \param configuration Value of the SPI configuration register.
*/
extern void SPI_Configure( Spi* spi, uint32_t dwId, uint32_t dwConfiguration )
{
PMC_EnablePeripheral( dwId ) ;
spi->SPI_CR = SPI_CR_SPIDIS ;
/* Execute a software reset of the SPI twice */
spi->SPI_CR = SPI_CR_SWRST ;
spi->SPI_CR = SPI_CR_SWRST ;
spi->SPI_MR = dwConfiguration ;
}
/**
* \brief Configures a chip select of a SPI peripheral. The chip select configuration
* is computed using several macros (see \ref spi_configuration_macros).
*
* \param spi Pointer to an Spi instance.
* \param npcs Chip select to configure (0, 1, 2 or 3).
* \param configuration Desired chip select configuration.
*/
void SPI_ConfigureNPCS( Spi* spi, uint32_t dwNpcs, uint32_t dwConfiguration )
{
spi->SPI_CSR[dwNpcs] = dwConfiguration ;
}
/**
* \brief Get the current status register of the given SPI peripheral.
* \note This resets the internal value of the status register, so further
* read may yield different values.
* \param spi Pointer to a Spi instance.
* \return SPI status register.
*/
extern uint32_t SPI_GetStatus( Spi* spi )
{
return spi->SPI_SR ;
}
/**
* \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.
*
* \param spi Pointer to an Spi instance.
*
* \return readed data.
*/
extern uint32_t SPI_Read( Spi* spi )
{
while ( (spi->SPI_SR & SPI_SR_RDRF) == 0 ) ;
return spi->SPI_RDR & 0xFFFF ;
}
/**
* \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
* the component which shall be addressed.
*
* \param spi Pointer to an Spi instance.
* \param npcs Chip select of the component to address (0, 1, 2 or 3).
* \param data Word of data to send.
*/
extern void SPI_Write( Spi* spi, uint32_t dwNpcs, uint16_t wData )
{
/* Send data */
while ( (spi->SPI_SR & SPI_SR_TXEMPTY) == 0 ) ;
spi->SPI_TDR = wData | SPI_PCS( dwNpcs ) ;
while ( (spi->SPI_SR & SPI_SR_TDRE) == 0 ) ;
}
/**
* \brief Check if SPI transfer finish.
*
* \param spi Pointer to an Spi instance.
*
* \return Returns 1 if there is no pending write operation on the SPI; otherwise
* returns 0.
*/
extern uint32_t SPI_IsFinished( Spi* spi )
{
return ((spi->SPI_SR & SPI_SR_TXEMPTY) != 0) ;
}
/**
* \brief Enable Spi PDC transmit
* \param spi Pointer to an Spi instance.
*/
extern void SPI_PdcEnableTx( Spi* spi )
{
spi->SPI_PTCR = SPI_PTCR_TXTEN ;
}
/**
* \brief Disable Spi PDC transmit
* \param spi Pointer to an Spi instance.
*/
extern void SPI_PdcDisableTx( Spi* spi )
{
spi->SPI_PTCR = SPI_PTCR_TXTDIS ;
}
/**
* \brief Enable Spi PDC receive
* \param spi Pointer to an Spi instance.
*/
extern void SPI_PdcEnableRx( Spi* spi )
{
spi->SPI_PTCR = SPI_PTCR_RXTEN ;
}
/**
* \brief Disable Spi PDC receive
* \param spi Pointer to an Spi instance.
*/
extern void SPI_PdcDisableRx( Spi* spi )
{
spi->SPI_PTCR = SPI_PTCR_RXTDIS ;
}
/**
* \brief Set PDC transmit and next transmit buffer address and size.
*
* \param spi Pointer to an Spi instance.
* \param txBuf PDC transmit buffer address.
* \param txCount Length in bytes of the transmit buffer.
* \param txNextBuf PDC next transmit buffer address.
* \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 )
{
spi->SPI_TPR = (uint32_t)pvTxBuf ;
spi->SPI_TCR = dwTxCount ;
spi->SPI_TNPR = (uint32_t)pvTxNextBuf ;
spi->SPI_TNCR = dwTxNextCount ;
}
/**
* \brief Set PDC receive and next receive buffer address and size.
*
* \param spi Pointer to an Spi instance.
* \param rxBuf PDC receive buffer address.
* \param rxCount Length in bytes of the receive buffer.
* \param rxNextBuf PDC next receive buffer address.
* \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 )
{
spi->SPI_RPR = (uint32_t)pvRxBuf ;
spi->SPI_RCR = dwRxCount ;
spi->SPI_RNPR = (uint32_t)pvRxNextBuf ;
spi->SPI_RNCR = dwRxNextCount ;
}
/**
* \brief Sends the contents of buffer through a SPI peripheral, using the PDC to
* take care of the transfer.
*
* \param spi Pointer to an Spi instance.
* \param buffer Data buffer to send.
* \param length Length of the data buffer.
*/
extern uint32_t SPI_WriteBuffer( Spi* spi, void* pvBuffer, uint32_t dwLength )
{
/* Check if first bank is free */
if ( spi->SPI_TCR == 0 )
{
spi->SPI_TPR = (uint32_t)pvBuffer ;
spi->SPI_TCR = dwLength ;
spi->SPI_PTCR = PERIPH_PTCR_TXTEN ;
return 1 ;
}
/* Check if second bank is free */
else
{
if ( spi->SPI_TNCR == 0 )
{
spi->SPI_TNPR = (uint32_t)pvBuffer ;
spi->SPI_TNCR = dwLength ;
return 1 ;
}
}
/* No free banks */
return 0 ;
}
/**
* \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.
*
* \param spi Pointer to an Spi instance.
* \param buffer Data buffer to store incoming bytes.
* \param length Length in bytes of the data buffer.
*/
extern uint32_t SPI_ReadBuffer( Spi* spi, void *pvBuffer, uint32_t dwLength )
{
/* Check if the first bank is free */
if ( spi->SPI_RCR == 0 )
{
spi->SPI_RPR = (uint32_t)pvBuffer ;
spi->SPI_RCR = dwLength ;
spi->SPI_PTCR = PERIPH_PTCR_RXTEN ;
return 1 ;
}
/* Check if second bank is free */
else
{
if ( spi->SPI_RNCR == 0 )
{
spi->SPI_RNPR = (uint32_t)pvBuffer ;
spi->SPI_RNCR = dwLength ;
return 1 ;
}
}
/* No free bank */
return 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.
* ----------------------------------------------------------------------------
*/
/** \addtogroup spi_module Working with SPI
* The SPI driver provides the interface to configure and use the SPI
* peripheral.
*
* The Serial Peripheral Interface (SPI) circuit is a synchronous serial
* data link that provides communication with external devices in Master
* or Slave Mode.
*
* To use the SPI, the user has to follow these few steps:
* -# Enable the SPI pins required by the application (see pio.h).
* -# Configure the SPI using the \ref SPI_Configure(). This enables the
* peripheral clock. The mode register is loaded with the given value.
* -# Configure all the necessary chip selects with \ref SPI_ConfigureNPCS().
* -# Enable the SPI by calling \ref SPI_Enable().
* -# 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.
* -# Send/receive data using the PDC with the \ref SPI_WriteBuffer() and
* \ref SPI_ReadBuffer() functions.
* -# Disable the SPI by calling \ref SPI_Disable().
*
* For more accurate information, please look at the SPI section of the
* Datasheet.
*
* Related files :\n
* \ref spi.c\n
* \ref spi.h.\n
*/
/*@{*/
/*@}*/
/**
* \file
*
* Implementation of Serial Peripheral Interface (SPI) controller.
*
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "chip.h"
#include "pmc.h"
#include "spi.h"
#include <stdint.h>
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/**
* \brief Enables a SPI peripheral.
*
* \param spi Pointer to an Spi instance.
*/
extern void SPI_Enable( Spi* spi )
{
spi->SPI_CR = SPI_CR_SPIEN ;
}
/**
* \brief Disables a SPI peripheral.
*
* \param spi Pointer to an Spi instance.
*/
extern void SPI_Disable( Spi* spi )
{
spi->SPI_CR = SPI_CR_SPIDIS ;
}
/**
* \brief Enables one or more interrupt sources of a SPI peripheral.
*
* \param spi Pointer to an Spi instance.
* \param sources Bitwise OR of selected interrupt sources.
*/
extern void SPI_EnableIt( Spi* spi, uint32_t dwSources )
{
spi->SPI_IER = dwSources ;
}
/**
* \brief Disables one or more interrupt sources of a SPI peripheral.
*
* \param spi Pointer to an Spi instance.
* \param sources Bitwise OR of selected interrupt sources.
*/
extern void SPI_DisableIt( Spi* spi, uint32_t dwSources )
{
spi->SPI_IDR = dwSources ;
}
/**
* \brief Configures a SPI peripheral as specified. The configuration can be computed
* using several macros (see \ref spi_configuration_macros).
*
* \param spi Pointer to an Spi instance.
* \param id Peripheral ID of the SPI.
* \param configuration Value of the SPI configuration register.
*/
extern void SPI_Configure( Spi* spi, uint32_t dwId, uint32_t dwConfiguration )
{
PMC_EnablePeripheral( dwId ) ;
spi->SPI_CR = SPI_CR_SPIDIS ;
/* Execute a software reset of the SPI twice */
spi->SPI_CR = SPI_CR_SWRST ;
spi->SPI_CR = SPI_CR_SWRST ;
spi->SPI_MR = dwConfiguration ;
}
/**
* \brief Configures a chip select of a SPI peripheral. The chip select configuration
* is computed using several macros (see \ref spi_configuration_macros).
*
* \param spi Pointer to an Spi instance.
* \param npcs Chip select to configure (0, 1, 2 or 3).
* \param configuration Desired chip select configuration.
*/
void SPI_ConfigureNPCS( Spi* spi, uint32_t dwNpcs, uint32_t dwConfiguration )
{
spi->SPI_CSR[dwNpcs] = dwConfiguration ;
}
/**
* \brief Get the current status register of the given SPI peripheral.
* \note This resets the internal value of the status register, so further
* read may yield different values.
* \param spi Pointer to a Spi instance.
* \return SPI status register.
*/
extern uint32_t SPI_GetStatus( Spi* spi )
{
return spi->SPI_SR ;
}
/**
* \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.
*
* \param spi Pointer to an Spi instance.
*
* \return readed data.
*/
extern uint32_t SPI_Read( Spi* spi )
{
while ( (spi->SPI_SR & SPI_SR_RDRF) == 0 ) ;
return spi->SPI_RDR & 0xFFFF ;
}
/**
* \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
* the component which shall be addressed.
*
* \param spi Pointer to an Spi instance.
* \param npcs Chip select of the component to address (0, 1, 2 or 3).
* \param data Word of data to send.
*/
extern void SPI_Write( Spi* spi, uint32_t dwNpcs, uint16_t wData )
{
/* Send data */
while ( (spi->SPI_SR & SPI_SR_TXEMPTY) == 0 ) ;
spi->SPI_TDR = wData | SPI_PCS( dwNpcs ) ;
while ( (spi->SPI_SR & SPI_SR_TDRE) == 0 ) ;
}
/**
* \brief Check if SPI transfer finish.
*
* \param spi Pointer to an Spi instance.
*
* \return Returns 1 if there is no pending write operation on the SPI; otherwise
* returns 0.
*/
extern uint32_t SPI_IsFinished( Spi* spi )
{
return ((spi->SPI_SR & SPI_SR_TXEMPTY) != 0) ;
}
/**
* \brief Enable Spi PDC transmit
* \param spi Pointer to an Spi instance.
*/
extern void SPI_PdcEnableTx( Spi* spi )
{
spi->SPI_PTCR = SPI_PTCR_TXTEN ;
}
/**
* \brief Disable Spi PDC transmit
* \param spi Pointer to an Spi instance.
*/
extern void SPI_PdcDisableTx( Spi* spi )
{
spi->SPI_PTCR = SPI_PTCR_TXTDIS ;
}
/**
* \brief Enable Spi PDC receive
* \param spi Pointer to an Spi instance.
*/
extern void SPI_PdcEnableRx( Spi* spi )
{
spi->SPI_PTCR = SPI_PTCR_RXTEN ;
}
/**
* \brief Disable Spi PDC receive
* \param spi Pointer to an Spi instance.
*/
extern void SPI_PdcDisableRx( Spi* spi )
{
spi->SPI_PTCR = SPI_PTCR_RXTDIS ;
}
/**
* \brief Set PDC transmit and next transmit buffer address and size.
*
* \param spi Pointer to an Spi instance.
* \param txBuf PDC transmit buffer address.
* \param txCount Length in bytes of the transmit buffer.
* \param txNextBuf PDC next transmit buffer address.
* \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 )
{
spi->SPI_TPR = (uint32_t)pvTxBuf ;
spi->SPI_TCR = dwTxCount ;
spi->SPI_TNPR = (uint32_t)pvTxNextBuf ;
spi->SPI_TNCR = dwTxNextCount ;
}
/**
* \brief Set PDC receive and next receive buffer address and size.
*
* \param spi Pointer to an Spi instance.
* \param rxBuf PDC receive buffer address.
* \param rxCount Length in bytes of the receive buffer.
* \param rxNextBuf PDC next receive buffer address.
* \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 )
{
spi->SPI_RPR = (uint32_t)pvRxBuf ;
spi->SPI_RCR = dwRxCount ;
spi->SPI_RNPR = (uint32_t)pvRxNextBuf ;
spi->SPI_RNCR = dwRxNextCount ;
}
/**
* \brief Sends the contents of buffer through a SPI peripheral, using the PDC to
* take care of the transfer.
*
* \param spi Pointer to an Spi instance.
* \param buffer Data buffer to send.
* \param length Length of the data buffer.
*/
extern uint32_t SPI_WriteBuffer( Spi* spi, void* pvBuffer, uint32_t dwLength )
{
/* Check if first bank is free */
if ( spi->SPI_TCR == 0 )
{
spi->SPI_TPR = (uint32_t)pvBuffer ;
spi->SPI_TCR = dwLength ;
spi->SPI_PTCR = PERIPH_PTCR_TXTEN ;
return 1 ;
}
/* Check if second bank is free */
else
{
if ( spi->SPI_TNCR == 0 )
{
spi->SPI_TNPR = (uint32_t)pvBuffer ;
spi->SPI_TNCR = dwLength ;
return 1 ;
}
}
/* No free banks */
return 0 ;
}
/**
* \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.
*
* \param spi Pointer to an Spi instance.
* \param buffer Data buffer to store incoming bytes.
* \param length Length in bytes of the data buffer.
*/
extern uint32_t SPI_ReadBuffer( Spi* spi, void *pvBuffer, uint32_t dwLength )
{
/* Check if the first bank is free */
if ( spi->SPI_RCR == 0 )
{
spi->SPI_RPR = (uint32_t)pvBuffer ;
spi->SPI_RCR = dwLength ;
spi->SPI_PTCR = PERIPH_PTCR_RXTEN ;
return 1 ;
}
/* Check if second bank is free */
else
{
if ( spi->SPI_RNCR == 0 )
{
spi->SPI_RNPR = (uint32_t)pvBuffer ;
spi->SPI_RNCR = dwLength ;
return 1 ;
}
}
/* No free bank */
return 0 ;
}

View File

@@ -1,175 +1,175 @@
/* ----------------------------------------------------------------------------
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* Implementation of Timer Counter (TC).
*
*/
/*------------------------------------------------------------------------------
* Headers
*------------------------------------------------------------------------------*/
#include "chip.h"
#include <assert.h>
/*------------------------------------------------------------------------------
* Global functions
*------------------------------------------------------------------------------*/
/**
* \brief Configures a Timer Counter Channel
*
* Configures a Timer Counter to operate in the given mode. Timer is stopped
* after configuration and must be restarted with TC_Start(). All the
* interrupts of the timer are also disabled.
*
* \param pTc Pointer to a Tc instance.
* \param channel Channel number.
* \param mode Operating mode (TC_CMR value).
*/
extern void TC_Configure( Tc *pTc, uint32_t dwChannel, uint32_t dwMode )
{
TcChannel* pTcCh ;
assert( dwChannel < (sizeof( pTc->TC_CHANNEL )/sizeof( pTc->TC_CHANNEL[0] )) ) ;
pTcCh = pTc->TC_CHANNEL+dwChannel ;
/* Disable TC clock */
pTcCh->TC_CCR = TC_CCR_CLKDIS ;
/* Disable interrupts */
pTcCh->TC_IDR = 0xFFFFFFFF ;
/* Clear status register */
pTcCh->TC_SR ;
/* Set mode */
pTcCh->TC_CMR = dwMode ;
}
/**
* \brief Reset and Start the TC Channel
*
* Enables the timer clock and performs a software reset to start the counting.
*
* \param pTc Pointer to a Tc instance.
* \param dwChannel Channel number.
*/
extern void TC_Start( Tc *pTc, uint32_t dwChannel )
{
TcChannel* pTcCh ;
assert( dwChannel < (sizeof( pTc->TC_CHANNEL )/sizeof( pTc->TC_CHANNEL[0] )) ) ;
pTcCh = pTc->TC_CHANNEL+dwChannel ;
pTcCh->TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG ;
}
/**
* \brief Stop TC Channel
*
* Disables the timer clock, stopping the counting.
*
* \param pTc Pointer to a Tc instance.
* \param dwChannel Channel number.
*/
extern void TC_Stop(Tc *pTc, uint32_t dwChannel )
{
TcChannel* pTcCh ;
assert( dwChannel < (sizeof( pTc->TC_CHANNEL )/sizeof( pTc->TC_CHANNEL[0] )) ) ;
pTcCh = pTc->TC_CHANNEL+dwChannel ;
pTcCh->TC_CCR = TC_CCR_CLKDIS ;
}
/**
* \brief Find best MCK divisor
*
* Finds the best MCK divisor given the timer frequency and MCK. The result
* is guaranteed to satisfy the following equation:
* \code
* (MCK / (DIV * 65536)) <= freq <= (MCK / DIV)
* \endcode
* with DIV being the highest possible value.
*
* \param dwFreq Desired timer frequency.
* \param dwMCk Master clock frequency.
* \param dwDiv Divisor value.
* \param dwTcClks TCCLKS field value for divisor.
* \param dwBoardMCK Board clock frequency.
*
* \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 )
{
const uint32_t adwDivisors[5] = { 2, 8, 32, 128, dwBoardMCK / 32768 } ;
uint32_t dwIndex = 0 ;
/* Satisfy lower bound */
while ( dwFreq < ((dwMCk / adwDivisors[dwIndex]) / 65536) )
{
dwIndex++ ;
/* If no divisor can be found, return 0 */
if ( dwIndex == (sizeof( adwDivisors )/sizeof( adwDivisors[0] )) )
{
return 0 ;
}
}
/* Try to maximize DIV while satisfying upper bound */
while ( dwIndex < 4 )
{
if ( dwFreq > (dwMCk / adwDivisors[dwIndex + 1]) )
{
break ;
}
dwIndex++ ;
}
/* Store results */
if ( dwDiv )
{
*dwDiv = adwDivisors[dwIndex] ;
}
if ( dwTcClks )
{
*dwTcClks = dwIndex ;
}
return 1 ;
}
/* ----------------------------------------------------------------------------
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* Implementation of Timer Counter (TC).
*
*/
/*------------------------------------------------------------------------------
* Headers
*------------------------------------------------------------------------------*/
#include "chip.h"
#include <assert.h>
/*------------------------------------------------------------------------------
* Global functions
*------------------------------------------------------------------------------*/
/**
* \brief Configures a Timer Counter Channel
*
* Configures a Timer Counter to operate in the given mode. Timer is stopped
* after configuration and must be restarted with TC_Start(). All the
* interrupts of the timer are also disabled.
*
* \param pTc Pointer to a Tc instance.
* \param channel Channel number.
* \param mode Operating mode (TC_CMR value).
*/
extern void TC_Configure( Tc *pTc, uint32_t dwChannel, uint32_t dwMode )
{
TcChannel* pTcCh ;
assert( dwChannel < (sizeof( pTc->TC_CHANNEL )/sizeof( pTc->TC_CHANNEL[0] )) ) ;
pTcCh = pTc->TC_CHANNEL+dwChannel ;
/* Disable TC clock */
pTcCh->TC_CCR = TC_CCR_CLKDIS ;
/* Disable interrupts */
pTcCh->TC_IDR = 0xFFFFFFFF ;
/* Clear status register */
pTcCh->TC_SR ;
/* Set mode */
pTcCh->TC_CMR = dwMode ;
}
/**
* \brief Reset and Start the TC Channel
*
* Enables the timer clock and performs a software reset to start the counting.
*
* \param pTc Pointer to a Tc instance.
* \param dwChannel Channel number.
*/
extern void TC_Start( Tc *pTc, uint32_t dwChannel )
{
TcChannel* pTcCh ;
assert( dwChannel < (sizeof( pTc->TC_CHANNEL )/sizeof( pTc->TC_CHANNEL[0] )) ) ;
pTcCh = pTc->TC_CHANNEL+dwChannel ;
pTcCh->TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG ;
}
/**
* \brief Stop TC Channel
*
* Disables the timer clock, stopping the counting.
*
* \param pTc Pointer to a Tc instance.
* \param dwChannel Channel number.
*/
extern void TC_Stop(Tc *pTc, uint32_t dwChannel )
{
TcChannel* pTcCh ;
assert( dwChannel < (sizeof( pTc->TC_CHANNEL )/sizeof( pTc->TC_CHANNEL[0] )) ) ;
pTcCh = pTc->TC_CHANNEL+dwChannel ;
pTcCh->TC_CCR = TC_CCR_CLKDIS ;
}
/**
* \brief Find best MCK divisor
*
* Finds the best MCK divisor given the timer frequency and MCK. The result
* is guaranteed to satisfy the following equation:
* \code
* (MCK / (DIV * 65536)) <= freq <= (MCK / DIV)
* \endcode
* with DIV being the highest possible value.
*
* \param dwFreq Desired timer frequency.
* \param dwMCk Master clock frequency.
* \param dwDiv Divisor value.
* \param dwTcClks TCCLKS field value for divisor.
* \param dwBoardMCK Board clock frequency.
*
* \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 )
{
const uint32_t adwDivisors[5] = { 2, 8, 32, 128, dwBoardMCK / 32768 } ;
uint32_t dwIndex = 0 ;
/* Satisfy lower bound */
while ( dwFreq < ((dwMCk / adwDivisors[dwIndex]) / 65536) )
{
dwIndex++ ;
/* If no divisor can be found, return 0 */
if ( dwIndex == (sizeof( adwDivisors )/sizeof( adwDivisors[0] )) )
{
return 0 ;
}
}
/* Try to maximize DIV while satisfying upper bound */
while ( dwIndex < 4 )
{
if ( dwFreq > (dwMCk / adwDivisors[dwIndex + 1]) )
{
break ;
}
dwIndex++ ;
}
/* Store results */
if ( dwDiv )
{
*dwDiv = adwDivisors[dwIndex] ;
}
if ( dwTcClks )
{
*dwTcClks = dwIndex ;
}
return 1 ;
}

View File

@@ -1,410 +1,410 @@
/* ----------------------------------------------------------------------------
* 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.
* ----------------------------------------------------------------------------
*/
/** \addtogroup usart_module Working with USART
* 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/
* 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:
* <ul>
* <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>
* -# 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.
</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.
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/
US_CSR_TXBUFE (WRITE). </li>
* <li> For interruption,"enable" the status bit through US_IER and
realize the hanler with USARTx_IrqHandler according to IRQ vector
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
NVIC .</li>
* </ul>
*
* For more accurate information, please look at the USART section of the
* Datasheet.
*
* Related files :\n
* \ref usart.c\n
* \ref usart.h\n
*/
/**
* \file
*
* Implementation of USART (Universal Synchronous Asynchronous Receiver Transmitter)
* controller.
*
*/
/*------------------------------------------------------------------------------
* Headers
*------------------------------------------------------------------------------*/
#include "chip.h"
#include "trace.h"
#include <assert.h>
#include <string.h>
/*----------------------------------------------------------------------------
* Local definitions
*----------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------
* Exported functions
*------------------------------------------------------------------------------*/
/**
* \brief Configures an USART peripheral with the specified parameters.
*
*
* \param usart Pointer to the USART peripheral to configure.
* \param mode Desired value for the USART mode register (see the datasheet).
* \param baudrate Baudrate at which the USART should operate (in Hz).
* \param masterClock Frequency of the system master clock (in Hz).
*/
void USART_Configure(Usart *usart,
uint32_t mode,
uint32_t baudrate,
uint32_t masterClock)
{
/* Reset and disable receiver & transmitter*/
usart->US_CR = US_CR_RSTRX | US_CR_RSTTX
| US_CR_RXDIS | US_CR_TXDIS;
/* Configure mode*/
usart->US_MR = mode;
/* Configure baudrate*/
/* Asynchronous, no oversampling*/
if ( ((mode & US_MR_SYNC) == 0) && ((mode & US_MR_OVER) == 0) )
{
usart->US_BRGR = (masterClock / baudrate) / 16;
}
if( ((mode & US_MR_USART_MODE_SPI_MASTER) == US_MR_USART_MODE_SPI_MASTER)
|| ((mode & US_MR_SYNC) == US_MR_SYNC))
{
if( (mode & US_MR_USCLKS_Msk) == US_MR_USCLKS_MCK)
{
usart->US_BRGR = masterClock / baudrate;
}
else
{
if ( (mode & US_MR_USCLKS_DIV) == US_MR_USCLKS_DIV)
{
usart->US_BRGR = masterClock / baudrate / 8;
}
}
}
/* TODO other modes*/
}
/**
* \brief Enables or disables the transmitter of an USART peripheral.
*
*
* \param usart Pointer to an USART peripheral
* \param enabled If true, the transmitter is enabled; otherwise it is
* disabled.
*/
void USART_SetTransmitterEnabled(Usart *usart, uint8_t enabled)
{
if (enabled) {
usart->US_CR = US_CR_TXEN;
}
else {
usart->US_CR = US_CR_TXDIS;
}
}
/**
* \brief Enables or disables the receiver of an USART peripheral
*
*
* \param usart Pointer to an USART peripheral
* \param enabled If true, the receiver is enabled; otherwise it is disabled.
*/
void USART_SetReceiverEnabled(Usart *usart,
uint8_t enabled)
{
if (enabled) {
usart->US_CR = US_CR_RXEN;
}
else {
usart->US_CR = US_CR_RXDIS;
}
}
/**
* \brief Sends one packet of data through the specified USART peripheral. This
* function operates synchronously, so it only returns when the data has been
* actually sent.
*
*
* \param usart Pointer to an USART peripheral.
* \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).
* \param timeOut Time out value (0 = no timeout).
*/
void USART_Write(
Usart *usart,
uint16_t data,
volatile uint32_t timeOut)
{
if (timeOut == 0) {
while ((usart->US_CSR & US_CSR_TXEMPTY) == 0);
}
else {
while ((usart->US_CSR & US_CSR_TXEMPTY) == 0) {
if (timeOut == 0) {
TRACE_ERROR("USART_Write: Timed out.\n\r");
return;
}
timeOut--;
}
}
usart->US_THR = data;
}
/**
* \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
* otherwise); poll the ENDTX and TXBUFE bits of the USART status register
* to check for the transfer completion.
*
* \param usart Pointer to an USART peripheral.
* \param buffer Pointer to the data buffer to send.
* \param size Size of the data buffer (in bytes).
*/
uint8_t USART_WriteBuffer(
Usart *usart,
void *buffer,
uint32_t size)
{
/* Check if the first PDC bank is free*/
if ((usart->US_TCR == 0) && (usart->US_TNCR == 0)) {
usart->US_TPR = (uint32_t) buffer;
usart->US_TCR = size;
usart->US_PTCR = US_PTCR_TXTEN;
return 1;
}
/* Check if the second PDC bank is free*/
else if (usart->US_TNCR == 0) {
usart->US_TNPR = (uint32_t) buffer;
usart->US_TNCR = size;
return 1;
}
else {
return 0;
}
}
/**
* \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
* received.
*
* \param usart Pointer to an USART peripheral.
* \param timeOut Time out value (0 -> no timeout).
*/
uint16_t USART_Read(
Usart *usart,
volatile uint32_t timeOut)
{
if (timeOut == 0) {
while ((usart->US_CSR & US_CSR_RXRDY) == 0);
}
else {
while ((usart->US_CSR & US_CSR_RXRDY) == 0) {
if (timeOut == 0) {
TRACE_ERROR( "USART_Read: Timed out.\n\r" ) ;
return 0;
}
timeOut--;
}
}
return usart->US_RHR;
}
/**
* \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
* been queued for transmission; otherwise 0.
*
* \param usart Pointer to an USART peripheral.
* \param buffer Pointer to the buffer where the received data will be stored.
* \param size Size of the data buffer (in bytes).
*/
uint8_t USART_ReadBuffer(Usart *usart,
void *buffer,
uint32_t size)
{
/* Check if the first PDC bank is free*/
if ((usart->US_RCR == 0) && (usart->US_RNCR == 0)) {
usart->US_RPR = (uint32_t) buffer;
usart->US_RCR = size;
usart->US_PTCR = US_PTCR_RXTEN;
return 1;
}
/* Check if the second PDC bank is free*/
else if (usart->US_RNCR == 0) {
usart->US_RNPR = (uint32_t) buffer;
usart->US_RNCR = size;
return 1;
}
else {
return 0;
}
}
/**
* \brief Returns 1 if some data has been received and can be read from an USART;
* otherwise returns 0.
*
* \param usart Pointer to an Usart instance.
*/
uint8_t USART_IsDataAvailable(Usart *usart)
{
if ((usart->US_CSR & US_CSR_RXRDY) != 0) {
return 1;
}
else {
return 0;
}
}
/**
* \brief Sets the filter value for the IRDA demodulator.
*
* \param pUsart Pointer to an Usart instance.
* \param filter Filter value.
*/
void USART_SetIrdaFilter(Usart *pUsart, uint8_t filter)
{
assert( pUsart != NULL ) ;
pUsart->US_IF = filter;
}
/**
* \brief Sends one packet of data through the specified USART peripheral. This
* function operates synchronously, so it only returns when the data has been
* actually sent.
*
* \param usart Pointer to an USART peripheral.
* \param c Character to send
*/
void USART_PutChar(
Usart *usart,
uint8_t c)
{
/* Wait for the transmitter to be ready*/
while ((usart->US_CSR & US_CSR_TXEMPTY) == 0);
/* Send character*/
usart->US_THR = c;
/* Wait for the transfer to complete*/
while ((usart->US_CSR & US_CSR_TXEMPTY) == 0);
}
/**
* \brief Return 1 if a character can be read in USART
*/
uint32_t USART_IsRxReady(Usart *usart)
{
return (usart->US_CSR & US_CSR_RXRDY);
}
/**
* \brief Get present status
*/
uint32_t USART_GetStatus(Usart *usart)
{
return usart->US_CSR;
}
/**
* \brief Enable interrupt
*/
void USART_EnableIt(Usart *usart,uint32_t mode)
{
usart->US_IER = mode;
}
/**
* \brief Disable interrupt
*/
void USART_DisableIt(Usart *usart,uint32_t mode)
{
usart->US_IDR = mode;
}
/**
* \brief Reads and returns a character from the USART.
*
* \note This function is synchronous (i.e. uses polling).
* \param usart Pointer to an USART peripheral.
* \return Character received.
*/
uint8_t USART_GetChar(Usart *usart)
{
while ((usart->US_CSR & US_CSR_RXRDY) == 0);
return usart->US_RHR;
}
/* ----------------------------------------------------------------------------
* 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.
* ----------------------------------------------------------------------------
*/
/** \addtogroup usart_module Working with USART
* 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/
* 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:
* <ul>
* <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>
* -# 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.
</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.
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/
US_CSR_TXBUFE (WRITE). </li>
* <li> For interruption,"enable" the status bit through US_IER and
realize the hanler with USARTx_IrqHandler according to IRQ vector
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
NVIC .</li>
* </ul>
*
* For more accurate information, please look at the USART section of the
* Datasheet.
*
* Related files :\n
* \ref usart.c\n
* \ref usart.h\n
*/
/**
* \file
*
* Implementation of USART (Universal Synchronous Asynchronous Receiver Transmitter)
* controller.
*
*/
/*------------------------------------------------------------------------------
* Headers
*------------------------------------------------------------------------------*/
#include "chip.h"
#include "trace.h"
#include <assert.h>
#include <string.h>
/*----------------------------------------------------------------------------
* Local definitions
*----------------------------------------------------------------------------*/
/*------------------------------------------------------------------------------
* Exported functions
*------------------------------------------------------------------------------*/
/**
* \brief Configures an USART peripheral with the specified parameters.
*
*
* \param usart Pointer to the USART peripheral to configure.
* \param mode Desired value for the USART mode register (see the datasheet).
* \param baudrate Baudrate at which the USART should operate (in Hz).
* \param masterClock Frequency of the system master clock (in Hz).
*/
void USART_Configure(Usart *usart,
uint32_t mode,
uint32_t baudrate,
uint32_t masterClock)
{
/* Reset and disable receiver & transmitter*/
usart->US_CR = US_CR_RSTRX | US_CR_RSTTX
| US_CR_RXDIS | US_CR_TXDIS;
/* Configure mode*/
usart->US_MR = mode;
/* Configure baudrate*/
/* Asynchronous, no oversampling*/
if ( ((mode & US_MR_SYNC) == 0) && ((mode & US_MR_OVER) == 0) )
{
usart->US_BRGR = (masterClock / baudrate) / 16;
}
if( ((mode & US_MR_USART_MODE_SPI_MASTER) == US_MR_USART_MODE_SPI_MASTER)
|| ((mode & US_MR_SYNC) == US_MR_SYNC))
{
if( (mode & US_MR_USCLKS_Msk) == US_MR_USCLKS_MCK)
{
usart->US_BRGR = masterClock / baudrate;
}
else
{
if ( (mode & US_MR_USCLKS_DIV) == US_MR_USCLKS_DIV)
{
usart->US_BRGR = masterClock / baudrate / 8;
}
}
}
/* TODO other modes*/
}
/**
* \brief Enables or disables the transmitter of an USART peripheral.
*
*
* \param usart Pointer to an USART peripheral
* \param enabled If true, the transmitter is enabled; otherwise it is
* disabled.
*/
void USART_SetTransmitterEnabled(Usart *usart, uint8_t enabled)
{
if (enabled) {
usart->US_CR = US_CR_TXEN;
}
else {
usart->US_CR = US_CR_TXDIS;
}
}
/**
* \brief Enables or disables the receiver of an USART peripheral
*
*
* \param usart Pointer to an USART peripheral
* \param enabled If true, the receiver is enabled; otherwise it is disabled.
*/
void USART_SetReceiverEnabled(Usart *usart,
uint8_t enabled)
{
if (enabled) {
usart->US_CR = US_CR_RXEN;
}
else {
usart->US_CR = US_CR_RXDIS;
}
}
/**
* \brief Sends one packet of data through the specified USART peripheral. This
* function operates synchronously, so it only returns when the data has been
* actually sent.
*
*
* \param usart Pointer to an USART peripheral.
* \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).
* \param timeOut Time out value (0 = no timeout).
*/
void USART_Write(
Usart *usart,
uint16_t data,
volatile uint32_t timeOut)
{
if (timeOut == 0) {
while ((usart->US_CSR & US_CSR_TXEMPTY) == 0);
}
else {
while ((usart->US_CSR & US_CSR_TXEMPTY) == 0) {
if (timeOut == 0) {
TRACE_ERROR("USART_Write: Timed out.\n\r");
return;
}
timeOut--;
}
}
usart->US_THR = data;
}
/**
* \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
* otherwise); poll the ENDTX and TXBUFE bits of the USART status register
* to check for the transfer completion.
*
* \param usart Pointer to an USART peripheral.
* \param buffer Pointer to the data buffer to send.
* \param size Size of the data buffer (in bytes).
*/
uint8_t USART_WriteBuffer(
Usart *usart,
void *buffer,
uint32_t size)
{
/* Check if the first PDC bank is free*/
if ((usart->US_TCR == 0) && (usart->US_TNCR == 0)) {
usart->US_TPR = (uint32_t) buffer;
usart->US_TCR = size;
usart->US_PTCR = US_PTCR_TXTEN;
return 1;
}
/* Check if the second PDC bank is free*/
else if (usart->US_TNCR == 0) {
usart->US_TNPR = (uint32_t) buffer;
usart->US_TNCR = size;
return 1;
}
else {
return 0;
}
}
/**
* \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
* received.
*
* \param usart Pointer to an USART peripheral.
* \param timeOut Time out value (0 -> no timeout).
*/
uint16_t USART_Read(
Usart *usart,
volatile uint32_t timeOut)
{
if (timeOut == 0) {
while ((usart->US_CSR & US_CSR_RXRDY) == 0);
}
else {
while ((usart->US_CSR & US_CSR_RXRDY) == 0) {
if (timeOut == 0) {
TRACE_ERROR( "USART_Read: Timed out.\n\r" ) ;
return 0;
}
timeOut--;
}
}
return usart->US_RHR;
}
/**
* \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
* been queued for transmission; otherwise 0.
*
* \param usart Pointer to an USART peripheral.
* \param buffer Pointer to the buffer where the received data will be stored.
* \param size Size of the data buffer (in bytes).
*/
uint8_t USART_ReadBuffer(Usart *usart,
void *buffer,
uint32_t size)
{
/* Check if the first PDC bank is free*/
if ((usart->US_RCR == 0) && (usart->US_RNCR == 0)) {
usart->US_RPR = (uint32_t) buffer;
usart->US_RCR = size;
usart->US_PTCR = US_PTCR_RXTEN;
return 1;
}
/* Check if the second PDC bank is free*/
else if (usart->US_RNCR == 0) {
usart->US_RNPR = (uint32_t) buffer;
usart->US_RNCR = size;
return 1;
}
else {
return 0;
}
}
/**
* \brief Returns 1 if some data has been received and can be read from an USART;
* otherwise returns 0.
*
* \param usart Pointer to an Usart instance.
*/
uint8_t USART_IsDataAvailable(Usart *usart)
{
if ((usart->US_CSR & US_CSR_RXRDY) != 0) {
return 1;
}
else {
return 0;
}
}
/**
* \brief Sets the filter value for the IRDA demodulator.
*
* \param pUsart Pointer to an Usart instance.
* \param filter Filter value.
*/
void USART_SetIrdaFilter(Usart *pUsart, uint8_t filter)
{
assert( pUsart != NULL ) ;
pUsart->US_IF = filter;
}
/**
* \brief Sends one packet of data through the specified USART peripheral. This
* function operates synchronously, so it only returns when the data has been
* actually sent.
*
* \param usart Pointer to an USART peripheral.
* \param c Character to send
*/
void USART_PutChar(
Usart *usart,
uint8_t c)
{
/* Wait for the transmitter to be ready*/
while ((usart->US_CSR & US_CSR_TXEMPTY) == 0);
/* Send character*/
usart->US_THR = c;
/* Wait for the transfer to complete*/
while ((usart->US_CSR & US_CSR_TXEMPTY) == 0);
}
/**
* \brief Return 1 if a character can be read in USART
*/
uint32_t USART_IsRxReady(Usart *usart)
{
return (usart->US_CSR & US_CSR_RXRDY);
}
/**
* \brief Get present status
*/
uint32_t USART_GetStatus(Usart *usart)
{
return usart->US_CSR;
}
/**
* \brief Enable interrupt
*/
void USART_EnableIt(Usart *usart,uint32_t mode)
{
usart->US_IER = mode;
}
/**
* \brief Disable interrupt
*/
void USART_DisableIt(Usart *usart,uint32_t mode)
{
usart->US_IDR = mode;
}
/**
* \brief Reads and returns a character from the USART.
*
* \note This function is synchronous (i.e. uses polling).
* \param usart Pointer to an USART peripheral.
* \return Character received.
*/
uint8_t USART_GetChar(Usart *usart)
{
while ((usart->US_CSR & US_CSR_RXRDY) == 0);
return usart->US_RHR;
}

View File

@@ -1,132 +1,132 @@
/* ----------------------------------------------------------------------------
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* Implementation of Watchdog Timer (WDT) controller.
*
*/
/** \addtogroup wdt_module Working with WDT
* The WDT driver provides the interface to configure and use the WDT
* peripheral.
*
* 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
* 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)
* and external reset generation enabled. The user must either disable it or
* reprogram it to meet the application requires.
*
* To use the WDT, the user could follow these few steps:
* <ul>
* <li>Enable watchdog with given mode using \ref WDT_Enable().
* <li>Restart the watchdog using \ref WDT_Restart() within the watchdog period.
* </ul>
*
* For more accurate information, please look at the WDT section of the
* Datasheet.
*
* \note
* The Watchdog Mode Register (WDT_MR) can be written only once.\n
*
* Related files :\n
* \ref wdt.c\n
* \ref wdt.h.\n
*/
/*@{*/
/*@}*/
/*---------------------------------------------------------------------------
* Headers
*---------------------------------------------------------------------------*/
#include "chip.h"
#include <stdint.h>
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/**
* \brief Enable watchdog with given mode.
*
* \note The Watchdog Mode Register (WDT_MR) can be written only once.
* Only a processor reset resets it.
*
* \param dwMode WDT mode to be set
*/
extern void WDT_Enable( Wdt* pWDT, uint32_t dwMode )
{
pWDT->WDT_MR = dwMode ;
}
/**
* \brief Disable watchdog.
*
* \note The Watchdog Mode Register (WDT_MR) can be written only once.
* Only a processor reset resets it.
*/
extern void WDT_Disable( Wdt* pWDT )
{
pWDT->WDT_MR = WDT_MR_WDDIS;
}
/**
* \brief Watchdog restart.
*/
extern void WDT_Restart( Wdt* pWDT )
{
pWDT->WDT_CR = 0xA5000001;
}
/**
* \brief Watchdog get status.
*/
extern uint32_t WDT_GetStatus( Wdt* pWDT )
{
return (pWDT->WDT_SR & 0x3) ;
}
/**
* \brief Watchdog get period.
*
* \param dwMs desired watchdog period in millisecond.
*/
extern uint32_t WDT_GetPeriod( uint32_t dwMs )
{
if ( (dwMs < 4) || (dwMs > 16000) )
{
return 0 ;
}
return ((dwMs << 8) / 1000) ;
}
/* ----------------------------------------------------------------------------
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* Implementation of Watchdog Timer (WDT) controller.
*
*/
/** \addtogroup wdt_module Working with WDT
* The WDT driver provides the interface to configure and use the WDT
* peripheral.
*
* 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
* 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)
* and external reset generation enabled. The user must either disable it or
* reprogram it to meet the application requires.
*
* To use the WDT, the user could follow these few steps:
* <ul>
* <li>Enable watchdog with given mode using \ref WDT_Enable().
* <li>Restart the watchdog using \ref WDT_Restart() within the watchdog period.
* </ul>
*
* For more accurate information, please look at the WDT section of the
* Datasheet.
*
* \note
* The Watchdog Mode Register (WDT_MR) can be written only once.\n
*
* Related files :\n
* \ref wdt.c\n
* \ref wdt.h.\n
*/
/*@{*/
/*@}*/
/*---------------------------------------------------------------------------
* Headers
*---------------------------------------------------------------------------*/
#include "chip.h"
#include <stdint.h>
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/**
* \brief Enable watchdog with given mode.
*
* \note The Watchdog Mode Register (WDT_MR) can be written only once.
* Only a processor reset resets it.
*
* \param dwMode WDT mode to be set
*/
extern void WDT_Enable( Wdt* pWDT, uint32_t dwMode )
{
pWDT->WDT_MR = dwMode ;
}
/**
* \brief Disable watchdog.
*
* \note The Watchdog Mode Register (WDT_MR) can be written only once.
* Only a processor reset resets it.
*/
extern void WDT_Disable( Wdt* pWDT )
{
pWDT->WDT_MR = WDT_MR_WDDIS;
}
/**
* \brief Watchdog restart.
*/
extern void WDT_Restart( Wdt* pWDT )
{
pWDT->WDT_CR = 0xA5000001;
}
/**
* \brief Watchdog get status.
*/
extern uint32_t WDT_GetStatus( Wdt* pWDT )
{
return (pWDT->WDT_SR & 0x3) ;
}
/**
* \brief Watchdog get period.
*
* \param dwMs desired watchdog period in millisecond.
*/
extern uint32_t WDT_GetPeriod( uint32_t dwMs )
{
if ( (dwMs < 4) || (dwMs > 16000) )
{
return 0 ;
}
return ((dwMs << 8) / 1000) ;
}

View File

@@ -1,3 +1,19 @@
/* SIMtrace 2 common board pin definitions
*
* 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_
#define _BOARD_
@@ -98,15 +114,8 @@
#define SIM_PWEN PIO_PA5
#define VCC_FWD PIO_PA26
/** Pin configuration to control USB pull-up on D+
* @details the USB pull-up on D+ is enable by default on the board but can be disabled by setting PA16 high
*/
#define PIN_USB_PULLUP {PIO_PA16, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
// Board has UDP controller
#define BOARD_USB_UDP
// D+ has external pull-up
#define BOARD_USB_PULLUP_EXTERNAL
#define BOARD_USB_DFU
#define BOARD_DFU_BOOT_SIZE (16 * 1024)

View File

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

View File

@@ -1,4 +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
uint32_t adc2uv(uint16_t adc);
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
enum led {
@@ -17,6 +31,7 @@ enum led_pattern {
BLINK_200O_F = 7,
BLINK_600O_F = 8,
BLINK_CUSTOM = 9,
BLINK_2F_O,
_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
#define _MANIFEST_H

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
int sim_switch_use_physical(unsigned int nr, int physical);

View File

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

View File

@@ -1,215 +1,208 @@
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2010, Atmel Corporation
* Copyright (C) 2017, Harald Welte <laforge@gnumonks.org>
*
* 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 "board_lowlevel.h"
/*----------------------------------------------------------------------------
* Exported variables
*----------------------------------------------------------------------------*/
/* Stack Configuration */
#define STACK_SIZE 0x900 /** Stack size (in DWords) */
__attribute__ ((aligned(8),section(".stack")))
uint32_t pdwStack[STACK_SIZE] ;
/* Initialize segments */
extern uint32_t _sfixed;
extern uint32_t _efixed;
extern uint32_t _etext;
extern uint32_t _srelocate;
extern uint32_t _erelocate;
extern uint32_t _szero;
extern uint32_t _ezero;
/*----------------------------------------------------------------------------
* ProtoTypes
*----------------------------------------------------------------------------*/
/** \cond DOXYGEN_SHOULD_SKIP_THIS */
extern int main( void ) ;
/** \endcond */
void ResetException( void ) ;
/*------------------------------------------------------------------------------
* Exception Table
*------------------------------------------------------------------------------*/
__attribute__((section(".vectors")))
IntFunc exception_table[] = {
/* Configure Initial Stack Pointer, using linker-generated symbols */
(IntFunc)(&pdwStack[STACK_SIZE-1]),
ResetException,
NMI_Handler,
HardFault_Handler,
MemManage_Handler,
BusFault_Handler,
UsageFault_Handler,
0, 0, 0, 0, /* Reserved */
SVC_Handler,
DebugMon_Handler,
0, /* Reserved */
PendSV_Handler,
SysTick_Handler,
/* Configurable interrupts */
SUPC_IrqHandler, /* 0 Supply Controller */
RSTC_IrqHandler, /* 1 Reset Controller */
RTC_IrqHandler, /* 2 Real Time Clock */
RTT_IrqHandler, /* 3 Real Time Timer */
WDT_IrqHandler, /* 4 Watchdog Timer */
PMC_IrqHandler, /* 5 PMC */
EEFC_IrqHandler, /* 6 EEFC */
IrqHandlerNotUsed, /* 7 Reserved */
UART0_IrqHandler, /* 8 UART0 */
UART1_IrqHandler, /* 9 UART1 */
SMC_IrqHandler, /* 10 SMC */
PIOA_IrqHandler, /* 11 Parallel IO Controller A */
PIOB_IrqHandler, /* 12 Parallel IO Controller B */
PIOC_IrqHandler, /* 13 Parallel IO Controller C */
USART0_IrqHandler, /* 14 USART 0 */
USART1_IrqHandler, /* 15 USART 1 */
IrqHandlerNotUsed, /* 16 Reserved */
IrqHandlerNotUsed, /* 17 Reserved */
MCI_IrqHandler, /* 18 MCI */
TWI0_IrqHandler, /* 19 TWI 0 */
TWI1_IrqHandler, /* 20 TWI 1 */
SPI_IrqHandler, /* 21 SPI */
SSC_IrqHandler, /* 22 SSC */
TC0_IrqHandler, /* 23 Timer Counter 0 */
TC1_IrqHandler, /* 24 Timer Counter 1 */
TC2_IrqHandler, /* 25 Timer Counter 2 */
TC3_IrqHandler, /* 26 Timer Counter 3 */
TC4_IrqHandler, /* 27 Timer Counter 4 */
TC5_IrqHandler, /* 28 Timer Counter 5 */
ADC_IrqHandler, /* 29 ADC controller */
DAC_IrqHandler, /* 30 DAC controller */
PWM_IrqHandler, /* 31 PWM */
CRCCU_IrqHandler, /* 32 CRC Calculation Unit */
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)
{
unsigned int *pSrc;
void (*appReset)(void);
pSrc = (unsigned int *) ((unsigned char *)IFLASH_ADDR + BOARD_DFU_BOOT_SIZE);
SCB->VTOR = ((unsigned int)(pSrc)) | (0x0 << 7);
appReset = (void(*)(void))pSrc[1];
g_dfu->state = DFU_STATE_appIDLE;
appReset();
}
#endif
/**
* \brief This is the code that gets called on processor reset.
* To initialize the device, and call the main() routine.
*/
void ResetException( void )
{
uint32_t *pSrc, *pDest ;
/* Low level Initialize */
LowLevelInit() ;
#if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu)
/* we are before the text segment has been relocated, so g_dfu is
* not initialized yet */
g_dfu = &_g_dfu;
if ((g_dfu->magic != USB_DFU_MAGIC) && !USBDFU_OverrideEnterDFU()) {
/* start application if valid
* the application starts with the vector table
* the first entry in the vector table is the initial stack pointer (SP) address
* the stack will be placed in RAM, which begins at 0x2000 0000
* there is up to 48 KB of RAM (0xc000)
* since the stack grown "downwards" it should start at the end of the RAM: max 0x2000 c000
* if the SP is not in this range (e.g. flash has been erased) there is no valid application
* the second entry in the vector table is the reset address, corresponding to the application start
*/
if (((*((uint32_t*)(IFLASH_ADDR+BOARD_DFU_BOOT_SIZE)))&0xFFFF0000)==0x20000000) {
BootIntoApp();
/* Infinite loop */
while ( 1 ) ;
}
}
#endif
/* Initialize the relocate segment */
pSrc = &_etext ;
pDest = &_srelocate ;
if ( pSrc != pDest )
{
for ( ; pDest < &_erelocate ; )
{
*pDest++ = *pSrc++ ;
}
}
/* Clear the zero segment */
for ( pDest = &_szero ; pDest < &_ezero ; )
{
*pDest++ = 0;
}
/* Set the vector table base address */
pSrc = (uint32_t *)&_sfixed;
SCB->VTOR = ( (uint32_t)pSrc & SCB_VTOR_TBLOFF_Msk ) ;
if ( ((uint32_t)pSrc >= IRAM_ADDR) && ((uint32_t)pSrc < IRAM_ADDR+IRAM_SIZE) )
{
SCB->VTOR |= 1 << SCB_VTOR_TBLBASE_Pos ;
}
/* App should have disabled interrupts during the transition */
__enable_irq();
/* Branch to main function */
main() ;
/* Infinite loop */
while ( 1 ) ;
}
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2010, Atmel Corporation
* Copyright (c) 2017, Harald Welte <laforge@gnumonks.org>
* Copyright (c) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* 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 "board_lowlevel.h"
/*----------------------------------------------------------------------------
* Exported variables
*----------------------------------------------------------------------------*/
/* Stack Configuration */
#define STACK_SIZE 0x900 /** Stack size (in DWords) */
__attribute__ ((aligned(8),section(".stack")))
uint32_t pdwStack[STACK_SIZE] ;
/* Initialize segments */
extern uint32_t _sfixed;
extern uint32_t _efixed;
extern uint32_t _etext;
extern uint32_t _srelocate;
extern uint32_t _erelocate;
extern uint32_t _szero;
extern uint32_t _ezero;
/*----------------------------------------------------------------------------
* ProtoTypes
*----------------------------------------------------------------------------*/
/** \cond DOXYGEN_SHOULD_SKIP_THIS */
extern int main( void ) ;
/** \endcond */
void ResetException( void ) ;
/*------------------------------------------------------------------------------
* Exception Table
*------------------------------------------------------------------------------*/
__attribute__((section(".vectors")))
IntFunc exception_table[] = {
/* Configure Initial Stack Pointer, using linker-generated symbols */
(IntFunc)(&pdwStack[STACK_SIZE-1]),
ResetException,
NMI_Handler,
HardFault_Handler,
MemManage_Handler,
BusFault_Handler,
UsageFault_Handler,
0, 0, 0, 0, /* Reserved */
SVC_Handler,
DebugMon_Handler,
0, /* Reserved */
PendSV_Handler,
SysTick_Handler,
/* Configurable interrupts */
SUPC_IrqHandler, /* 0 Supply Controller */
RSTC_IrqHandler, /* 1 Reset Controller */
RTC_IrqHandler, /* 2 Real Time Clock */
RTT_IrqHandler, /* 3 Real Time Timer */
WDT_IrqHandler, /* 4 Watchdog Timer */
PMC_IrqHandler, /* 5 PMC */
EEFC_IrqHandler, /* 6 EEFC */
IrqHandlerNotUsed, /* 7 Reserved */
UART0_IrqHandler, /* 8 UART0 */
UART1_IrqHandler, /* 9 UART1 */
SMC_IrqHandler, /* 10 SMC */
PIOA_IrqHandler, /* 11 Parallel IO Controller A */
PIOB_IrqHandler, /* 12 Parallel IO Controller B */
PIOC_IrqHandler, /* 13 Parallel IO Controller C */
USART0_IrqHandler, /* 14 USART 0 */
USART1_IrqHandler, /* 15 USART 1 */
IrqHandlerNotUsed, /* 16 Reserved */
IrqHandlerNotUsed, /* 17 Reserved */
MCI_IrqHandler, /* 18 MCI */
TWI0_IrqHandler, /* 19 TWI 0 */
TWI1_IrqHandler, /* 20 TWI 1 */
SPI_IrqHandler, /* 21 SPI */
SSC_IrqHandler, /* 22 SSC */
TC0_IrqHandler, /* 23 Timer Counter 0 */
TC1_IrqHandler, /* 24 Timer Counter 1 */
TC2_IrqHandler, /* 25 Timer Counter 2 */
TC3_IrqHandler, /* 26 Timer Counter 3 */
TC4_IrqHandler, /* 27 Timer Counter 4 */
TC5_IrqHandler, /* 28 Timer Counter 5 */
ADC_IrqHandler, /* 29 ADC controller */
DAC_IrqHandler, /* 30 DAC controller */
PWM_IrqHandler, /* 31 PWM */
CRCCU_IrqHandler, /* 32 CRC Calculation Unit */
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)
{
unsigned int *pSrc;
void (*appReset)(void);
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) */
SCB->VTOR = (unsigned int)(pSrc);
/* set stack pointer to address provided in the beginning of the application (loaded into a register first) */
__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) */
appReset = (void(*)(void))pSrc[1];
g_dfu->state = DFU_STATE_appIDLE;
appReset();
}
#endif
/**
* \brief This is the code that gets called on processor reset.
* To initialize the device, and call the main() routine.
*/
void ResetException( void )
{
uint32_t *pSrc, *pDest ;
/* Low level Initialize */
LowLevelInit() ;
#if defined(BOARD_USB_DFU) && defined(APPLICATION_dfu)
if (!USBDFU_OverrideEnterDFU()) {
UART_Exit();
__disable_irq();
BootIntoApp();
/* Infinite loop */
while ( 1 ) ;
}
#endif
/* Initialize the relocate segment */
pSrc = &_etext ;
pDest = &_srelocate ;
if ( pSrc != pDest )
{
for ( ; pDest < &_erelocate ; )
{
*pDest++ = *pSrc++ ;
}
}
/* Clear the zero segment */
for ( pDest = &_szero ; pDest < &_ezero ; )
{
*pDest++ = 0;
}
/* Set the vector table base address */
pSrc = (uint32_t *)&_sfixed;
SCB->VTOR = ( (uint32_t)pSrc & SCB_VTOR_TBLOFF_Msk ) ;
if ( ((uint32_t)pSrc >= IRAM_ADDR) && ((uint32_t)pSrc < IRAM_ADDR+IRAM_SIZE) )
{
SCB->VTOR |= 1 << SCB_VTOR_TBLBASE_Pos ;
}
/* App should have disabled interrupts during the transition */
__enable_irq();
/* Branch to main function */
main() ;
/* Infinite loop */
while ( 1 ) ;
}

View File

@@ -1,216 +1,216 @@
/* ----------------------------------------------------------------------------
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* Provides the low-level initialization function that called on chip startup.
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "board.h"
/*----------------------------------------------------------------------------
* Local definitions
*----------------------------------------------------------------------------*/
#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)
/* Clock settings at 48MHz for 18 MHz crystal */
#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \
| CKGR_PLLAR_MULA(13-1) \
| CKGR_PLLAR_PLLACOUNT(0x1) \
| CKGR_PLLAR_DIVA(5))
#elif (BOARD_MAINOSC == 12000000)
/* QMod has 12 MHz clock, so multply by 8 (96 MHz) and divide by 2 */
#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \
| CKGR_PLLAR_MULA(8-1) \
| CKGR_PLLAR_PLLACOUNT(0x1) \
| CKGR_PLLAR_DIVA(2))
#else
#error "Please define PLLA config for your MAINOSC frequency"
#endif /* MAINOSC */
#elif (BOARD_MCK == 64000000)
#if (BOARD_MAINOSC == 18432000)
/* Clock settings at 64MHz for 18 MHz crystal: 64.512 MHz */
#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \
| CKGR_PLLAR_MULA(7-1) \
| CKGR_PLLAR_PLLACOUNT(0x1) \
| CKGR_PLLAR_DIVA(2))
#elif (BOARD_MAINOSC == 12000000)
/* QMod has 12 MHz clock, so multply by 10 / div by 2: 60 MHz */
#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \
| CKGR_PLLAR_MULA(10-1) \
| CKGR_PLLAR_PLLACOUNT(0x1) \
| CKGR_PLLAR_DIVA(2))
#error "Please define PLLA config for your MAINOSC frequency"
#endif /* MAINOSC */
#else
#error "No PLL settings for current BOARD_MCK."
#endif
#if (BOARD_MAINOSC == 12000000)
#define PLLB_CFG (CKGR_PLLBR_DIVB(2)|CKGR_PLLBR_MULB(8-1)|CKGR_PLLBR_PLLBCOUNT_Msk)
#elif (BOARD_MAINOSC == 18432000)
#define PLLB_CFG (CKGR_PLLBR_DIVB(5)|CKGR_PLLBR_MULB(13-1)|CKGR_PLLBR_PLLBCOUNT_Msk)
#else
#error "Please configure PLLB for your MAINOSC freq"
#endif
/* Define clock timeout */
#define CLOCK_TIMEOUT 0xFFFFFFFF
/**
* \brief Configure 48MHz Clock for USB
*/
static void _ConfigureUsbClock(void)
{
/* Enable PLLB for USB */
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) */
| PMC_USB_USBS; /* PLLB */
}
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/**
* \brief Performs the low-level initialization of the chip.
* 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 )
{
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
* might be some kind of leakage that creeps in some way, but is not
* the "official" power supply */
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;
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);
/* 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;
while (!(SUPC->SUPC_SR & SUPC_SR_OSCSEL_CRYST) );
}
*/
#ifndef qmod
/* 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;
while (!(PMC->PMC_SR & PMC_SR_MOSCXTS) && (timeout++ < CLOCK_TIMEOUT));
}
/* Switch to 3-20MHz Xtal oscillator */
PIOB->PIO_PDR = (1 << 8) | (1 << 9);
PIOB->PIO_PUDR = (1 << 8) | (1 << 9);
PIOB->PIO_PPDDR = (1 << 8) | (1 << 9);
PMC->CKGR_MOR = CKGR_MOR_KEY(0x37) | BOARD_OSCOUNT | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN | CKGR_MOR_MOSCSEL;
/* wait for Main XTAL oscillator stabilization */
timeout = 0;
while (!(PMC->PMC_SR & PMC_SR_MOSCSELS) && (timeout++ < CLOCK_TIMEOUT));
#else
/* QMOD has external 12MHz clock source */
PIOB->PIO_PDR = (1 << 9);
PIOB->PIO_PUDR = (1 << 9);
PIOB->PIO_PPDDR = (1 << 9);
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;
/* "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;
/* 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;
/* Wait for PLLA to lock */
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;
/* 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 ;
/* 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);
_ConfigureUsbClock();
}
/* SysTick based delay function */
volatile uint32_t jiffies;
/* Interrupt handler for SysTick interrupt */
void SysTick_Handler(void)
{
jiffies++;
}
void mdelay(unsigned int msecs)
{
uint32_t jiffies_start = jiffies;
do {
} while ((jiffies - jiffies_start) < msecs);
}
/* ----------------------------------------------------------------------------
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* Provides the low-level initialization function that called on chip startup.
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "board.h"
/*----------------------------------------------------------------------------
* Local definitions
*----------------------------------------------------------------------------*/
#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)
/* Clock settings at 48MHz for 18 MHz crystal */
#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \
| CKGR_PLLAR_MULA(13-1) \
| CKGR_PLLAR_PLLACOUNT(0x1) \
| CKGR_PLLAR_DIVA(5))
#elif (BOARD_MAINOSC == 12000000)
/* QMod has 12 MHz clock, so multply by 8 (96 MHz) and divide by 2 */
#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \
| CKGR_PLLAR_MULA(8-1) \
| CKGR_PLLAR_PLLACOUNT(0x1) \
| CKGR_PLLAR_DIVA(2))
#else
#error "Please define PLLA config for your MAINOSC frequency"
#endif /* MAINOSC */
#elif (BOARD_MCK == 64000000)
#if (BOARD_MAINOSC == 18432000)
/* Clock settings at 64MHz for 18 MHz crystal: 64.512 MHz */
#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \
| CKGR_PLLAR_MULA(7-1) \
| CKGR_PLLAR_PLLACOUNT(0x1) \
| CKGR_PLLAR_DIVA(2))
#elif (BOARD_MAINOSC == 12000000)
/* QMod has 12 MHz clock, so multply by 10 / div by 2: 60 MHz */
#define BOARD_PLLAR (CKGR_PLLAR_STUCKTO1 \
| CKGR_PLLAR_MULA(10-1) \
| CKGR_PLLAR_PLLACOUNT(0x1) \
| CKGR_PLLAR_DIVA(2))
#error "Please define PLLA config for your MAINOSC frequency"
#endif /* MAINOSC */
#else
#error "No PLL settings for current BOARD_MCK."
#endif
#if (BOARD_MAINOSC == 12000000)
#define PLLB_CFG (CKGR_PLLBR_DIVB(2)|CKGR_PLLBR_MULB(8-1)|CKGR_PLLBR_PLLBCOUNT_Msk)
#elif (BOARD_MAINOSC == 18432000)
#define PLLB_CFG (CKGR_PLLBR_DIVB(5)|CKGR_PLLBR_MULB(13-1)|CKGR_PLLBR_PLLBCOUNT_Msk)
#else
#error "Please configure PLLB for your MAINOSC freq"
#endif
/* Define clock timeout */
#define CLOCK_TIMEOUT 0xFFFFFFFF
/**
* \brief Configure 48MHz Clock for USB
*/
static void _ConfigureUsbClock(void)
{
/* Enable PLLB for USB */
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) */
| PMC_USB_USBS; /* PLLB */
}
/*----------------------------------------------------------------------------
* Exported functions
*----------------------------------------------------------------------------*/
/**
* \brief Performs the low-level initialization of the chip.
* 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 )
{
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
* might be some kind of leakage that creeps in some way, but is not
* the "official" power supply */
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;
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);
/* 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;
while (!(SUPC->SUPC_SR & SUPC_SR_OSCSEL_CRYST) );
}
*/
#ifndef qmod
/* 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;
while (!(PMC->PMC_SR & PMC_SR_MOSCXTS) && (timeout++ < CLOCK_TIMEOUT));
}
/* Switch to 3-20MHz Xtal oscillator */
PIOB->PIO_PDR = (1 << 8) | (1 << 9);
PIOB->PIO_PUDR = (1 << 8) | (1 << 9);
PIOB->PIO_PPDDR = (1 << 8) | (1 << 9);
PMC->CKGR_MOR = CKGR_MOR_KEY(0x37) | BOARD_OSCOUNT | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN | CKGR_MOR_MOSCSEL;
/* wait for Main XTAL oscillator stabilization */
timeout = 0;
while (!(PMC->PMC_SR & PMC_SR_MOSCSELS) && (timeout++ < CLOCK_TIMEOUT));
#else
/* QMOD has external 12MHz clock source */
PIOB->PIO_PDR = (1 << 9);
PIOB->PIO_PUDR = (1 << 9);
PIOB->PIO_PPDDR = (1 << 9);
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;
/* "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;
/* 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;
/* Wait for PLLA to lock */
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;
/* 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 ;
/* 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);
_ConfigureUsbClock();
}
/* SysTick based delay function */
volatile uint32_t jiffies;
/* Interrupt handler for SysTick interrupt */
void SysTick_Handler(void)
{
jiffies++;
}
void mdelay(unsigned int msecs)
{
uint32_t jiffies_start = jiffies;
do {
} while ((jiffies - jiffies_start) < msecs);
}

View File

@@ -1,7 +1,21 @@
/* 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 "boardver_adc.h"
#define UV_PER_LSB ((3300 * 1000) / 4096)
#define UV_PER_LSB ((3300 * 1000) / 4096)
uint32_t adc2uv(uint16_t adc)
{
uint32_t uv = (uint32_t) adc * UV_PER_LSB;
@@ -72,7 +86,7 @@ int get_board_version_adc(void)
/* convert to voltage */
sample = ADC->ADC_CDR[2];
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 */

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 <string.h>
#include <assert.h>
@@ -16,9 +35,9 @@ static void led_set(enum led led, int on)
ASSERT(led < PIO_LISTSIZE(pinsLeds));
if (on)
PIO_Clear(&pinsLeds[led]);
PIO_Clear(&pinsLeds[led]);
else
PIO_Set(&pinsLeds[led]);
PIO_Set(&pinsLeds[led]);
}
/* LED blinking code */
@@ -54,16 +73,23 @@ static const struct blink_state bs_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 }
};
static const struct blink_state bs_2on_off[] = {
{ 200, 1 }, { 0, 0 },
};
static const struct blink_state bs_200on_off[] = {
{ 20000, 1 }, { 0, 0 },
};
static const struct blink_state bs_600on_off[] = {
{ 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 */
struct blink_pattern {
@@ -109,6 +135,11 @@ static const struct blink_pattern patterns[] = {
.states = 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 {

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"
const char *manifest_application = APPLICATION;

View File

@@ -1,5 +1,21 @@
/* 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 "trace.h"
#include "led.h"

View File

@@ -1,415 +1,448 @@
/* ----------------------------------------------------------------------------
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* Implements UART console.
*
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "board.h"
#include <stdio.h>
#include <stdint.h>
#include "ringbuffer.h"
/*----------------------------------------------------------------------------
* Definitions
*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
* Variables
*----------------------------------------------------------------------------*/
/** Is Console Initialized. */
static uint8_t _ucIsConsoleInitialized=0;
/** Ring buffer to queue data to be sent */
static ringbuf uart_tx_buffer;
/**
* \brief Configures an USART peripheral with the specified parameters.
*
* \param baudrate Baudrate at which the USART should operate (in Hz).
* \param masterClock Frequency of the system master clock (in Hz).
*/
extern void UART_Configure( uint32_t baudrate, uint32_t masterClock)
{
const Pin pPins[] = CONSOLE_PINS;
Uart *pUart = CONSOLE_UART;
/* Configure PIO */
PIO_Configure(pPins, PIO_LISTSIZE(pPins));
/* Configure PMC */
PMC->PMC_PCER0 = 1 << CONSOLE_ID;
/* Reset and disable receiver & transmitter */
pUart->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX
| UART_CR_RXDIS | UART_CR_TXDIS;
/* Configure mode */
pUart->UART_MR = UART_MR_PAR_NO;
/* Configure baudrate */
/* Asynchronous, no oversampling */
pUart->UART_BRGR = (masterClock / baudrate) / 16;
/* Disable PDC channel */
pUart->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS;
/* Reset transmit ring buffer */
rbuf_reset(&uart_tx_buffer);
/* Enable TX interrupts */
pUart->UART_IER = UART_IER_TXRDY;
NVIC_EnableIRQ(CONSOLE_IRQ);
/* Enable receiver and transmitter */
pUart->UART_CR = UART_CR_RXEN | UART_CR_TXEN;
/* Remember the configuration is complete */
_ucIsConsoleInitialized=1 ;
}
/** Interrupt Service routine to transmit queued data */
void CONSOLE_ISR(void)
{
Uart *uart = CONSOLE_UART;
if (uart->UART_SR & UART_SR_TXRDY) {
if (!rbuf_is_empty(&uart_tx_buffer)) {
//uart->UART_IER = UART_IER_TXRDY;
uart->UART_THR = rbuf_read(&uart_tx_buffer);
} else {
uart->UART_IDR = UART_IER_TXRDY;
}
}
}
/**
* \brief Outputs a character on the UART line.
*
* \note This function is synchronous (i.e. uses polling).
* \param c Character to send.
*/
extern void UART_PutChar( uint8_t c )
{
Uart *pUart = CONSOLE_UART ;
/* Initialize console is not already done */
if ( !_ucIsConsoleInitialized )
{
UART_Configure(CONSOLE_BAUDRATE, BOARD_MCK);
}
/* Only store input if buffer is not full, else drop it */
bool trigger_isr = false;
if (rbuf_is_empty(&uart_tx_buffer)) {
trigger_isr = true;
}
if (!rbuf_is_full(&uart_tx_buffer)) {
rbuf_write(&uart_tx_buffer, c);
}
if (trigger_isr) {
pUart->UART_IER = UART_IER_TXRDY;
CONSOLE_ISR();
}
}
/**
* \brief Input a character from the UART line.
*
* \note This function is synchronous
* \return character received.
*/
extern uint32_t UART_GetChar( void )
{
Uart *pUart = CONSOLE_UART ;
if ( !_ucIsConsoleInitialized )
{
UART_Configure(CONSOLE_BAUDRATE, BOARD_MCK);
}
while ( (pUart->UART_SR & UART_SR_RXRDY) == 0 )
WDT_Restart(WDT);
return pUart->UART_RHR ;
}
/**
* \brief Check if there is Input from UART line.
*
* \return true if there is Input.
*/
extern uint32_t UART_IsRxReady( void )
{
Uart *pUart = CONSOLE_UART;
if ( !_ucIsConsoleInitialized )
{
UART_Configure( CONSOLE_BAUDRATE, BOARD_MCK ) ;
}
return (pUart->UART_SR & UART_SR_RXRDY) > 0 ;
}
/**
* Displays the content of the given frame on the UART0.
*
* \param pucFrame Pointer to the frame to dump.
* \param dwSize Buffer size in bytes.
*/
extern void UART_DumpFrame( uint8_t* pucFrame, uint32_t dwSize )
{
uint32_t dw ;
for ( dw=0 ; dw < dwSize ; dw++ )
{
printf( "%02X ", pucFrame[dw] ) ;
}
printf( "\n\r" ) ;
}
/**
* Displays the content of the given buffer on the UART0.
*
* \param pucBuffer Pointer to the buffer to dump.
* \param dwSize Buffer size in bytes.
* \param dwAddress Start address to display
*/
extern void UART_DumpMemory( uint8_t* pucBuffer, uint32_t dwSize, uint32_t dwAddress )
{
uint32_t i ;
uint32_t j ;
uint32_t dwLastLineStart ;
uint8_t* pucTmp ;
for ( i=0 ; i < (dwSize / 16) ; i++ )
{
printf( "0x%08X: ", (unsigned int)(dwAddress + (i*16)) ) ;
pucTmp = (uint8_t*)&pucBuffer[i*16] ;
for ( j=0 ; j < 4 ; j++ )
{
printf( "%02X%02X%02X%02X ", pucTmp[0], pucTmp[1], pucTmp[2], pucTmp[3] ) ;
pucTmp += 4 ;
}
pucTmp=(uint8_t*)&pucBuffer[i*16] ;
for ( j=0 ; j < 16 ; j++ )
{
UART_PutChar( *pucTmp++ ) ;
}
printf( "\n\r" ) ;
}
if ( (dwSize%16) != 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) )
{
printf( " " ) ;
}
if ( j < dwSize )
{
printf( "%02X", pucBuffer[j] ) ;
}
else
{
printf(" ") ;
}
}
printf( " " ) ;
for ( j=dwLastLineStart ; j < dwSize ; j++ )
{
UART_PutChar( pucBuffer[j] ) ;
}
printf( "\n\r" ) ;
}
}
/**
* Reads an integer
*
* \param pdwValue Pointer to the uint32_t variable to contain the input value.
*/
extern uint32_t UART_GetInteger( uint32_t* pdwValue )
{
uint8_t ucKey ;
uint8_t ucNbNb=0 ;
uint32_t dwValue=0 ;
while ( 1 )
{
ucKey=UART_GetChar() ;
UART_PutChar( ucKey ) ;
if ( ucKey >= '0' && ucKey <= '9' )
{
dwValue = (dwValue * 10) + (ucKey - '0');
ucNbNb++ ;
}
else
{
if ( ucKey == 0x0D || ucKey == ' ' )
{
if ( ucNbNb == 0 )
{
printf( "\n\rWrite a number and press ENTER or SPACE!\n\r" ) ;
return 0 ;
}
else
{
printf( "\n\r" ) ;
*pdwValue=dwValue ;
return 1 ;
}
}
else
{
printf( "\n\r'%c' not a number!\n\r", ucKey ) ;
return 0 ;
}
}
WDT_Restart(WDT);
}
}
/**
* Reads an integer and check the value
*
* \param pdwValue Pointer to the uint32_t variable to contain the input value.
* \param dwMin Minimum value
* \param dwMax Maximum value
*/
extern uint32_t UART_GetIntegerMinMax( uint32_t* pdwValue, uint32_t dwMin, uint32_t dwMax )
{
uint32_t dwValue=0 ;
if ( UART_GetInteger( &dwValue ) == 0 )
{
return 0 ;
}
if ( dwValue < dwMin || dwValue > dwMax )
{
printf( "\n\rThe number have to be between %d and %d\n\r", (int)dwMin, (int)dwMax ) ;
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__
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2009, Atmel Corporation
* Copyright (c) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* 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.
* ----------------------------------------------------------------------------
*/
/**
* \file
*
* Implements UART console.
*
*/
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "board.h"
#include <stdio.h>
#include <stdint.h>
#include "ringbuffer.h"
/*----------------------------------------------------------------------------
* Definitions
*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
* Variables
*----------------------------------------------------------------------------*/
/** Is Console Initialized. */
static uint8_t _ucIsConsoleInitialized=0;
/** Ring buffer to queue data to be sent */
static ringbuf uart_tx_buffer;
/**
* \brief Configures an USART peripheral with the specified parameters.
*
* \param baudrate Baudrate at which the USART should operate (in Hz).
* \param masterClock Frequency of the system master clock (in Hz).
*/
extern void UART_Configure( uint32_t baudrate, uint32_t masterClock)
{
const Pin pPins[] = CONSOLE_PINS;
Uart *pUart = CONSOLE_UART;
/* Configure PIO */
PIO_Configure(pPins, PIO_LISTSIZE(pPins));
/* Configure PMC */
PMC->PMC_PCER0 = 1 << CONSOLE_ID;
/* Reset and disable receiver & transmitter */
pUart->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX
| UART_CR_RXDIS | UART_CR_TXDIS;
/* Configure mode */
pUart->UART_MR = UART_MR_PAR_NO;
/* Configure baudrate */
/* Asynchronous, no oversampling */
pUart->UART_BRGR = (masterClock / baudrate) / 16;
/* Disable PDC channel */
pUart->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS;
/* Reset transmit ring buffer */
rbuf_reset(&uart_tx_buffer);
/* Enable TX interrupts */
pUart->UART_IER = UART_IER_TXRDY;
NVIC_EnableIRQ(CONSOLE_IRQ);
/* Enable receiver and transmitter */
pUart->UART_CR = UART_CR_RXEN | UART_CR_TXEN;
/* Remember the configuration is complete */
_ucIsConsoleInitialized=1 ;
}
/**
* \brief Disables the USART peripheral and related IRQ
*/
void UART_Exit(void)
{
if (!_ucIsConsoleInitialized) {
return;
}
Uart *pUart = CONSOLE_UART;
pUart->UART_IDR = UART_IDR_TXRDY;
pUart->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS | UART_CR_TXDIS | UART_CR_RSTSTA;
PMC->PMC_PCDR0 = 1 << CONSOLE_ID;
NVIC_DisableIRQ(CONSOLE_IRQ);
}
/** Interrupt Service routine to transmit queued data */
void CONSOLE_ISR(void)
{
Uart *uart = CONSOLE_UART;
if (uart->UART_SR & UART_SR_TXRDY) {
if (!rbuf_is_empty(&uart_tx_buffer)) {
uart->UART_THR = rbuf_read(&uart_tx_buffer);
} else {
uart->UART_IDR = UART_IER_TXRDY;
}
}
}
/**
* \brief Outputs a character on the UART line.
*
* \note This function is asynchronous (i.e. uses a buffer and interrupt to complete the transfer).
* \param c Character to send.
*/
void UART_PutChar( uint8_t uc )
{
Uart *pUart = CONSOLE_UART ;
/* Initialize console is not already done */
if ( !_ucIsConsoleInitialized )
{
UART_Configure(CONSOLE_BAUDRATE, BOARD_MCK);
}
if (!rbuf_is_full(&uart_tx_buffer)) {
rbuf_write(&uart_tx_buffer, uc);
if (!(pUart->UART_IMR & UART_IMR_TXRDY)) {
pUart->UART_IER = UART_IER_TXRDY;
CONSOLE_ISR();
}
}
}
/**
* \brief Outputs a character on the UART line.
*
* \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 )
{
Uart *pUart = CONSOLE_UART ;
/* Initialize console is not already done */
if ( !_ucIsConsoleInitialized )
{
UART_Configure(CONSOLE_BAUDRATE, BOARD_MCK);
}
while (!(pUart->UART_SR & UART_SR_TXRDY)); /* Wait for transfer buffer to be empty */
pUart->UART_THR = uc; /* Send data to UART peripheral */
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) */
}
/**
* \brief Input a character from the UART line.
*
* \note This function is synchronous
* \return character received.
*/
extern uint32_t UART_GetChar( void )
{
Uart *pUart = CONSOLE_UART ;
if ( !_ucIsConsoleInitialized )
{
UART_Configure(CONSOLE_BAUDRATE, BOARD_MCK);
}
while ( (pUart->UART_SR & UART_SR_RXRDY) == 0 )
WDT_Restart(WDT);
return pUart->UART_RHR ;
}
/**
* \brief Check if there is Input from UART line.
*
* \return true if there is Input.
*/
extern uint32_t UART_IsRxReady( void )
{
Uart *pUart = CONSOLE_UART;
if ( !_ucIsConsoleInitialized )
{
UART_Configure( CONSOLE_BAUDRATE, BOARD_MCK ) ;
}
return (pUart->UART_SR & UART_SR_RXRDY) > 0 ;
}
/**
* Displays the content of the given frame on the UART0.
*
* \param pucFrame Pointer to the frame to dump.
* \param dwSize Buffer size in bytes.
*/
extern void UART_DumpFrame( uint8_t* pucFrame, uint32_t dwSize )
{
uint32_t dw ;
for ( dw=0 ; dw < dwSize ; dw++ )
{
printf( "%02X ", pucFrame[dw] ) ;
}
printf( "\n\r" ) ;
}
/**
* Displays the content of the given buffer on the UART0.
*
* \param pucBuffer Pointer to the buffer to dump.
* \param dwSize Buffer size in bytes.
* \param dwAddress Start address to display
*/
extern void UART_DumpMemory( uint8_t* pucBuffer, uint32_t dwSize, uint32_t dwAddress )
{
uint32_t i ;
uint32_t j ;
uint32_t dwLastLineStart ;
uint8_t* pucTmp ;
for ( i=0 ; i < (dwSize / 16) ; i++ )
{
printf( "0x%08X: ", (unsigned int)(dwAddress + (i*16)) ) ;
pucTmp = (uint8_t*)&pucBuffer[i*16] ;
for ( j=0 ; j < 4 ; j++ )
{
printf( "%02X%02X%02X%02X ", pucTmp[0], pucTmp[1], pucTmp[2], pucTmp[3] ) ;
pucTmp += 4 ;
}
pucTmp=(uint8_t*)&pucBuffer[i*16] ;
for ( j=0 ; j < 16 ; j++ )
{
UART_PutChar( *pucTmp++ ) ;
}
printf( "\n\r" ) ;
}
if ( (dwSize%16) != 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) )
{
printf( " " ) ;
}
if ( j < dwSize )
{
printf( "%02X", pucBuffer[j] ) ;
}
else
{
printf(" ") ;
}
}
printf( " " ) ;
for ( j=dwLastLineStart ; j < dwSize ; j++ )
{
UART_PutChar( pucBuffer[j] ) ;
}
printf( "\n\r" ) ;
}
}
/**
* Reads an integer
*
* \param pdwValue Pointer to the uint32_t variable to contain the input value.
*/
extern uint32_t UART_GetInteger( uint32_t* pdwValue )
{
uint8_t ucKey ;
uint8_t ucNbNb=0 ;
uint32_t dwValue=0 ;
while ( 1 )
{
ucKey=UART_GetChar() ;
UART_PutChar( ucKey ) ;
if ( ucKey >= '0' && ucKey <= '9' )
{
dwValue = (dwValue * 10) + (ucKey - '0');
ucNbNb++ ;
}
else
{
if ( ucKey == 0x0D || ucKey == ' ' )
{
if ( ucNbNb == 0 )
{
printf( "\n\rWrite a number and press ENTER or SPACE!\n\r" ) ;
return 0 ;
}
else
{
printf( "\n\r" ) ;
*pdwValue=dwValue ;
return 1 ;
}
}
else
{
printf( "\n\r'%c' not a number!\n\r", ucKey ) ;
return 0 ;
}
}
WDT_Restart(WDT);
}
}
/**
* Reads an integer and check the value
*
* \param pdwValue Pointer to the uint32_t variable to contain the input value.
* \param dwMin Minimum value
* \param dwMax Maximum value
*/
extern uint32_t UART_GetIntegerMinMax( uint32_t* pdwValue, uint32_t dwMin, uint32_t dwMax )
{
uint32_t dwValue=0 ;
if ( UART_GetInteger( &dwValue ) == 0 )
{
return 0 ;
}
if ( dwValue < dwMin || dwValue > dwMax )
{
printf( "\n\rThe number have to be between %d and %d\n\r", (int)dwMin, (int)dwMax ) ;
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,3 +1,21 @@
/* OWHW board definition
*
* (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
*/
#pragma once
#include "board_common.h"
#include "simtrace_usb.h"

View File

@@ -1,20 +1,20 @@
/* Card simulator specific functions */
/* (C) 2015 by Harald Welte <hwelte@hmw-consulting.de>
/* Card simulator specific functions
*
* 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.
* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
*
* 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.
* 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.
*
* 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
* 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 "chip.h"
@@ -36,5 +36,5 @@ void cardsim_set_simpres(uint8_t slot, int present)
void cardsim_gpio_init(void)
{
PIO_Configure(&pins_cardsim, ARRAY_SIZE(pins_cardsim));
PIO_Configure(pins_cardsim, ARRAY_SIZE(pins_cardsim));
}

View File

@@ -1,3 +1,21 @@
/* 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
#include "board_common.h"
#include "simtrace_usb.h"

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
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
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
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
int wwan_perst_set(int modem_nr, int active);

View File

@@ -1,6 +1,21 @@
/* Quad-modem speciic application code */
/* (C) 2016-2016 by Harald Welte <laforge@gnumonks.org> */
/* sysmocom quad-modem sysmoQMOD application code
*
* (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 "board.h"
#include "simtrace.h"
#include "utils.h"
@@ -55,8 +70,6 @@ const unsigned char __eeprom_bin[256] = {
#include "i2c.h"
static int write_hub_eeprom(void)
{
const unsigned int __eeprom_bin_len = 256;
int i;
/* wait */
@@ -64,16 +77,18 @@ static int write_hub_eeprom(void)
TRACE_INFO("Writing EEPROM...\n\r");
/* 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]);
/* if the result was negative, repeat that write */
if (rc < 0)
i--;
if (rc < 0) {
TRACE_ERROR("Writing EEPROM failed at byte %u: 0x%02x\n\r",
i, __eeprom_bin[i]);
return 1;
}
}
/* then pursue re-reading it again and again */
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);
TRACE_INFO("0x%02x: %02x\n\r", i, byte);
if (byte != __eeprom_bin[i])
@@ -87,6 +102,28 @@ static int write_hub_eeprom(void)
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;
}
}
return 0;
}
static void board_exec_dbg_cmd_st12only(int ch)
{
uint32_t addr, val;
@@ -99,6 +136,9 @@ static void board_exec_dbg_cmd_st12only(int ch)
case 'E':
write_hub_eeprom();
break;
case 'e':
erase_hub_eeprom();
break;
case 'O':
printf("Setting PRTPWR_OVERRIDE\n\r");
PIO_Set(&pin_hubpwr_override);
@@ -123,13 +163,13 @@ static void board_exec_dbg_cmd_st12only(int ch)
UART_GetIntegerMinMax(&addr, 0, 255);
printf("Please enter EEPROM value:\n\r");
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);
break;
case 'r':
printf("Please enter EEPROM offset:\n\r");
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;
default:
printf("Unknown command '%c'\n\r", ch);
@@ -146,6 +186,7 @@ void board_exec_dbg_cmd(int ch)
printf("\tR\treset SAM3\n\r");
if (qmod_sam3_is_12()) {
printf("\tE\tprogram EEPROM\n\r");
printf("\te\tErase EEPROM\n\r");
printf("\tO\tEnable PRTPWR_OVERRIDE\n\r");
printf("\to\tDisable PRTPWR_OVERRIDE\n\r");
printf("\tH\tRelease HUB RESET (high)\n\r");
@@ -261,20 +302,32 @@ static int uart_has_loopback_jumper(void)
/* 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]))
return 0;
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]))
return 0;
if (PIO_Get(&uart_loopback_pins[0])) {
has_loopback_jumper = 0;
break;
}
}
/* 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;
/* 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)

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 "board.h"
#include "utils.h"

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 <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);
if (nack)
goto out_stop;
/* Wait tWR time to ensure EEPROM is writing correctly (tWR = 5 ms for AT24C02) */
mdelay(5);
out_stop:
i2c_stop_cond();

View File

@@ -1,11 +1,24 @@
/* 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
* the cellular modem. If the board supports this, it sets the
* PIN_WWAN1 and/or PIN_WWAN2 defines in its board.h file.
*/
#include "board.h"
#include "wwan_led.h"

View File

@@ -1,11 +1,24 @@
/* 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
* the cellular modem. If the board supports this, it sets the
* PIN_PERST1 and/or PIN_PERST2 defines in its board.h file.
*/
#include "board.h"
#include "trace.h"
#include "wwan_perst.h"

View File

@@ -1,3 +1,22 @@
/* 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
#include "board_common.h"
#include "simtrace_usb.h"
@@ -98,6 +117,11 @@
/* SPI flash write protect pin (active low, pulled low) */
#define PIN_SPI_WP {PA15, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
/** Pin configuration to control USB pull-up on D+
* @details the USB pull-up on D+ is enable by default on the board but can be disabled by setting PA16 high
*/
#define PIN_USB_PULLUP {PIO_PA16, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT}
/** USB definitions */
/* OpenMoko SIMtrace 2 USB vendor ID */
#define BOARD_USB_VENDOR_ID USB_VENDOR_OPENMOKO

View File

@@ -1,6 +1,22 @@
/* SIMtrace specific application code */
/* (C) 2017 by Harald Welte <laforge@gnumonks.org> */
/* 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"

View File

@@ -65,41 +65,41 @@
// Definitions
//------------------------------------------------------------------------------
#if defined(NOASSERT)
#define ASSERT(...)
#define SANITY_CHECK(...)
#define ASSERT(...)
#define SANITY_CHECK(...)
#else
#if (TRACE_LEVEL == 0)
/// Checks that the given condition is true,
/// otherwise stops the program execution.
/// \param condition Condition to verify.
#define ASSERT(condition) { \
if (!(condition)) { \
while (1); \
} \
}
#if (TRACE_LEVEL == 0)
/// Checks that the given condition is true,
/// otherwise stops the program execution.
/// \param condition Condition to verify.
#define ASSERT(condition) { \
if (!(condition)) { \
while (1); \
} \
}
/// Performs the same duty as the ASSERT() macro
/// \param condition Condition to verify.
#define SANITY_CHECK(condition) ASSERT(condition, ...)
/// Performs the same duty as the ASSERT() macro
/// \param condition Condition to verify.
#define SANITY_CHECK(condition) ASSERT(condition, ...)
#else
/// Checks that the given condition is true, otherwise displays an error
/// message and stops the program execution.
/// \param condition Condition to verify.
#define ASSERT(condition) { \
if (!(condition)) { \
printf("-F- ASSERT: %s %s:%d\n\r", #condition, __BASE_FILE__, __LINE__); \
while (1); \
} \
}
#define SANITY_ERROR "Sanity check failed at %s:%d\n\r"
/// Performs the same duty as the ASSERT() macro, except a default error
/// message is output if the condition is false.
/// \param condition Condition to verify.
#define SANITY_CHECK(condition) ASSERT(condition, SANITY_ERROR, __FILE__, __LINE__)
#endif
#else
/// Checks that the given condition is true, otherwise displays an error
/// message and stops the program execution.
/// \param condition Condition to verify.
#define ASSERT(condition) { \
if (!(condition)) { \
printf("-F- ASSERT: %s %s:%d\n\r", #condition, __BASE_FILE__, __LINE__); \
while (1); \
} \
}
#define SANITY_ERROR "Sanity check failed at %s:%d\n\r"
/// Performs the same duty as the ASSERT() macro, except a default error
/// message is output if the condition is false.
/// \param condition Condition to verify.
#define SANITY_CHECK(condition) ASSERT(condition, SANITY_ERROR, __FILE__, __LINE__)
#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
#include <stdint.h>
@@ -36,3 +55,4 @@ int card_emu_uart_update_fidi(uint8_t uart_chan, unsigned int fidi);
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_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
typedef struct
{
/// Number of seconds.
unsigned char bTimerOut;
/// Several parameters for the PIN format options
unsigned char bmFormatString;
/// Define the length of the PIN to present in the APDU command
unsigned char bmPINBlockString;
/// Allows the length PIN insertion in the APDU command
unsigned char bmPINLengthFormat;
/// Minimum PIN size in digit and Maximum PIN size in digit
unsigned char wPINMaxExtraDigit;
/// The value is a bit wise OR operation.
unsigned char bEntryValidationCondition;
/// Number of messages to display for the PIN modify command
unsigned char bNumberMessage;
/// Language used to display the messages.
unsigned char wLangId;
/// Message index in the Reader message table
unsigned char bMsgIndex;
/// T=1 I-block prologue field to use
unsigned char bTeoPrologue[3];
/// APDU to send to the ICC
unsigned char abPINApdu[255];
/// Number of seconds.
unsigned char bTimerOut;
/// Several parameters for the PIN format options
unsigned char bmFormatString;
/// Define the length of the PIN to present in the APDU command
unsigned char bmPINBlockString;
/// Allows the length PIN insertion in the APDU command
unsigned char bmPINLengthFormat;
/// Minimum PIN size in digit and Maximum PIN size in digit
unsigned char wPINMaxExtraDigit;
/// The value is a bit wise OR operation.
unsigned char bEntryValidationCondition;
/// Number of messages to display for the PIN modify command
unsigned char bNumberMessage;
/// Language used to display the messages.
unsigned char wLangId;
/// Message index in the Reader message table
unsigned char bMsgIndex;
/// T=1 I-block prologue field to use
unsigned char bTeoPrologue[3];
/// APDU to send to the ICC
unsigned char abPINApdu[255];
}__attribute__ ((packed)) S_ccid_PIN_Verification;
/// 6.1.11.7 PIN Modification Data Structure
typedef struct
{
/// Number of seconds. If 00h then CCID default value is used.
unsigned char bTimeOut;
/// Several parameters for the PIN format options (defined in § 6.1.11.4)
unsigned char bmFormatString4;
/// Define the length of the PIN to present in the APDU command
unsigned char bmPINBlockString;
/// Allows the length PIN insertion in the APDU command (defined in § 6.1.11.6)
unsigned char bmPinLengthFormat;
/// Insertion position offset in byte for the current PIN
unsigned char bInsertionOffsetOld;
/// Insertion position offset in byte for the new PIN
unsigned char bInsertionOffsetNew;
/// XXYYh
/// XX: Minimum PIN size in digit
/// YY: Maximum PIN size in digit
unsigned char wPINMaxExtraDigit;
/// 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 the current PIN must be entered and set in the same APDU field of not.
unsigned char bConfirmPIN;
/// The value is a bit wise OR operation.
/// 01h Max size reached
/// 02h Validation key pressed
/// 04h Timeout occurred
unsigned char bEntryValidationCondition;
/// 00h,01h,02h,03h,or FFh
/// Number of messages to display for the PIN modify command.
unsigned char bNumberMessage;
/// Language used to display the messages. The 16 bit
unsigned char wLangId;
/// Message index in the Reader message table (should be 00h or 01h).
unsigned char bMsgIndex1;
/// Message index in the Reader message table (should be 01h or 02h).
unsigned char bMsgIndex2;
/// Message index in the Reader message table (should be 02h).
unsigned char bMsgIndex3;
/// T=1 I-block prologue field to use. Significant only if protocol in use is T=1.
unsigned char bTeoPrologue[3];
/// Byte array APDU to send to the ICC
unsigned char abPINApdu[255];
/// Number of seconds. If 00h then CCID default value is used.
unsigned char bTimeOut;
/// Several parameters for the PIN format options (defined in § 6.1.11.4)
unsigned char bmFormatString4;
/// Define the length of the PIN to present in the APDU command
unsigned char bmPINBlockString;
/// Allows the length PIN insertion in the APDU command (defined in § 6.1.11.6)
unsigned char bmPinLengthFormat;
/// Insertion position offset in byte for the current PIN
unsigned char bInsertionOffsetOld;
/// Insertion position offset in byte for the new PIN
unsigned char bInsertionOffsetNew;
/// XXYYh
/// XX: Minimum PIN size in digit
/// YY: Maximum PIN size in digit
unsigned char wPINMaxExtraDigit;
/// 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 the current PIN must be entered and set in the same APDU field of not.
unsigned char bConfirmPIN;
/// The value is a bit wise OR operation.
/// 01h Max size reached
/// 02h Validation key pressed
/// 04h Timeout occurred
unsigned char bEntryValidationCondition;
/// 00h,01h,02h,03h,or FFh
/// Number of messages to display for the PIN modify command.
unsigned char bNumberMessage;
/// Language used to display the messages. The 16 bit
unsigned char wLangId;
/// Message index in the Reader message table (should be 00h or 01h).
unsigned char bMsgIndex1;
/// Message index in the Reader message table (should be 01h or 02h).
unsigned char bMsgIndex2;
/// Message index in the Reader message table (should be 02h).
unsigned char bMsgIndex3;
/// T=1 I-block prologue field to use. Significant only if protocol in use is T=1.
unsigned char bTeoPrologue[3];
/// Byte array APDU to send to the ICC
unsigned char abPINApdu[255];
}__attribute__ ((packed)) S_ccid_PIN_Modification;
/// Protocol Data Structure for Protocol T=0 (bProtocolNum=0, dwLength=00000005h)
typedef struct
{
/// B7-4 FI Index into the table 7 in ISO/IEC 7816-3:1997 selecting a
/// clock rate conversion factor
/// B3-0 DI - Index into the table 8 in ISO/IEC 7816-3:1997 selecting a
/// baud rate conversion factor
unsigned char bmFindexDindex;
/// For T=0 ,B0 0b, B7-2 000000b
/// B1 Convention used (b1=0 for direct, b1=1 for inverse)
unsigned char bmTCCKST0; // 0 to 2
/// Extra Guardtime between two characters. Add 0 to 254 etu to the normal
/// guardtime of 12etu. FFh is the same as 00h.
unsigned char bGuardTimeT0; // 0 to FF
/// WI for T=0 used to define WWT
unsigned char bWaitingIntegerT0; // 0 to FF
/// ICC Clock Stop Support
/// 00 = Stopping the Clock is not allowed
/// 01 = Stop with Clock signal Low
/// 02 = Stop with Clock signal High
/// 03 = Stop with Clock either High or Low
unsigned char bClockStop; // 0 to 3
/// B7-4 FI Index into the table 7 in ISO/IEC 7816-3:1997 selecting a
/// clock rate conversion factor
/// B3-0 DI - Index into the table 8 in ISO/IEC 7816-3:1997 selecting a
/// baud rate conversion factor
unsigned char bmFindexDindex;
/// For T=0 ,B0 0b, B7-2 000000b
/// B1 Convention used (b1=0 for direct, b1=1 for inverse)
unsigned char bmTCCKST0; // 0 to 2
/// Extra Guardtime between two characters. Add 0 to 254 etu to the normal
/// guardtime of 12etu. FFh is the same as 00h.
unsigned char bGuardTimeT0; // 0 to FF
/// WI for T=0 used to define WWT
unsigned char bWaitingIntegerT0; // 0 to FF
/// ICC Clock Stop Support
/// 00 = Stopping the Clock is not allowed
/// 01 = Stop with Clock signal Low
/// 02 = Stop with Clock signal High
/// 03 = Stop with Clock either High or Low
unsigned char bClockStop; // 0 to 3
} __attribute__ ((packed)) S_ccid_protocol_t0;
/// Protocol Data Structure for Protocol T=1 (bProtocolNum=1, dwLength=00000007h)
typedef struct
{
/// B7-4 FI Index into the table 7 in ISO/IEC 7816-3:1997 selecting a
/// clock rate conversion factor
/// B3-0 DI - Index into the table 8 in ISO/IEC 7816-3:1997 selecting a
/// baud rate conversion factor
unsigned char bmFindexDindex;
/// For T=1, B7-2 000100b
/// B0 Checksum type (b0=0 for LRC, b0=1 for CRC
/// B1 Convention used (b1=0 for direct, b1=1 for inverse)
unsigned char bmTCCKST1; // 10h, 11h, 12h, 13h
/// Extra Guardtime (0 to 254 etu between two characters).
/// If value is FFh, then guardtime is reduced by 1.
unsigned char bGuardTimeT1; // 0 to FF
/// B7-4 = BWI
/// B3-0 = CWI
unsigned char bmWaitingIntegersT1; // 0 to 9
/// ICC Clock Stop Support
/// 00 = Stopping the Clock is not allowed
/// 01 = Stop with Clock signal Low
/// 02 = Stop with Clock signal High
/// 03 = Stop with Clock either High or Low
unsigned char bClockStop; // 0 to 3
/// Size of negotiated IFSC
unsigned char bIFSC; // 0 to FE
/// Nad value used by CCID
unsigned char bNadValue; // 0 to FF
/// B7-4 FI Index into the table 7 in ISO/IEC 7816-3:1997 selecting a
/// clock rate conversion factor
/// B3-0 DI - Index into the table 8 in ISO/IEC 7816-3:1997 selecting a
/// baud rate conversion factor
unsigned char bmFindexDindex;
/// For T=1, B7-2 000100b
/// B0 Checksum type (b0=0 for LRC, b0=1 for CRC
/// B1 Convention used (b1=0 for direct, b1=1 for inverse)
unsigned char bmTCCKST1; // 10h, 11h, 12h, 13h
/// Extra Guardtime (0 to 254 etu between two characters).
/// If value is FFh, then guardtime is reduced by 1.
unsigned char bGuardTimeT1; // 0 to FF
/// B7-4 = BWI
/// B3-0 = CWI
unsigned char bmWaitingIntegersT1; // 0 to 9
/// ICC Clock Stop Support
/// 00 = Stopping the Clock is not allowed
/// 01 = Stop with Clock signal Low
/// 02 = Stop with Clock signal High
/// 03 = Stop with Clock either High or Low
unsigned char bClockStop; // 0 to 3
/// Size of negotiated IFSC
unsigned char bIFSC; // 0 to FE
/// Nad value used by CCID
unsigned char bNadValue; // 0 to FF
} __attribute__ ((packed)) S_ccid_protocol_t1;
@@ -357,8 +357,8 @@ typedef struct
//------------------------------------------------------------------------------
extern unsigned char RDRtoPCHardwareError( unsigned char bSlot,
unsigned char bSeq,
unsigned char bHardwareErrorCode );
unsigned char bSeq,
unsigned char bHardwareErrorCode );
/*
#if !defined(NOAUTOCALLBACK)
@@ -368,13 +368,13 @@ extern void USBDCallbacks_RequestReceived(const USBGenericRequest *request);
extern void CCID_SmartCardRequest( void );
extern void CCIDDriver_Initialize( void );
extern unsigned char CCID_Read(void *pBuffer,
unsigned int dLength,
TransferCallback fCallback,
void *pArgument);
unsigned int dLength,
TransferCallback fCallback,
void *pArgument);
extern unsigned char CCID_Write(void *pBuffer,
unsigned int dLength,
TransferCallback fCallback,
void *pArgument);
unsigned int dLength,
TransferCallback fCallback,
void *pArgument);
extern unsigned char CCID_Insertion( void );
extern unsigned char CCID_Removal( void );

View File

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

View File

@@ -1,3 +1,21 @@
/* 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
#include <stdint.h>

View File

@@ -1,3 +1,21 @@
/* 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
#include <osmocom/core/linuxlist.h>

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
#define SIMTRACE_RINGBUF_H
@@ -16,7 +32,7 @@ typedef struct ringbuf {
void rbuf_reset(volatile ringbuf * rb);
uint8_t rbuf_read(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_full(volatile ringbuf * rb);

View File

@@ -1,3 +1,21 @@
/* 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
#define SIMTRACE_H
@@ -47,19 +65,19 @@ enum confNum {
/// device using the CCID driver.
typedef struct {
/// Configuration descriptor
USBConfigurationDescriptor configuration;
/// Interface descriptor
USBInterfaceDescriptor interface;
/// CCID descriptor
CCIDDescriptor ccid;
/// Bulk OUT endpoint descriptor
USBEndpointDescriptor bulkOut;
/// Bulk IN endpoint descriptor
USBEndpointDescriptor bulkIn;
/// Interrupt OUT endpoint descriptor
USBEndpointDescriptor interruptIn;
DFURT_IF_DESCRIPTOR_STRUCT
/// Configuration descriptor
USBConfigurationDescriptor configuration;
/// Interface descriptor
USBInterfaceDescriptor interface;
/// CCID descriptor
CCIDDescriptor ccid;
/// Bulk OUT endpoint descriptor
USBEndpointDescriptor bulkOut;
/// Bulk IN endpoint descriptor
USBEndpointDescriptor bulkIn;
/// Interrupt OUT endpoint descriptor
USBEndpointDescriptor interruptIn;
DFURT_IF_DESCRIPTOR_STRUCT
} __attribute__ ((packed)) CCIDDriverConfigurationDescriptors;
extern const USBConfigurationDescriptor *configurationDescriptorsArr[];
@@ -68,7 +86,7 @@ extern const USBConfigurationDescriptor *configurationDescriptorsArr[];
* @param[io] usart USART peripheral base address
* @param[in] fidi FiDi value as provided in TA interface byte
*/
void update_fidi(Usart *usart, uint8_t fidi);
void update_fidi(Usart_info *usart, uint8_t fidi);
void ISR_PhoneRST( const Pin *pPin);

View File

@@ -1,21 +1,21 @@
/* SIMtrace2 USB protocol */
/* (C) 2015-2017 by Harald Welte <hwelte@hmw-consulting.de>
/* SIMtrace2 USB protocol
*
* 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.
* (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 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.
* 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.
*
* 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
* 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
@@ -291,9 +291,13 @@ struct st_modem_status {
/* 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_HOLD (1<<2)
#define SNIFF_CHANGE_FLAG_RESET_RELEASE (1<<3)
#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 {
@@ -309,8 +313,8 @@ struct sniff_fidi {
/* SIMTRACE_MSGT_SNIFF_ATR, SIMTRACE_MSGT_SNIFF_PPS, SIMTRACE_MSGT_SNIFF_TPDU */
struct sniff_data {
/* if the data is complete (an error might have occurred during transmission */
bool complete;
/* data flags */
uint32_t flags;
/* data length */
uint16_t length;
/* data */

View File

@@ -1,20 +1,21 @@
/* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
/* 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 Affero General Public License for more details.
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* (C) 2018 by Kevin Redon <kredon@sysmocom.de>
* All Rights Reserved
* 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 */

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
#include <stddef.h>
#include <stdarg.h>
@@ -24,9 +52,14 @@ signed int printf(const char *pFormat, ...);
signed int sprintf(char *pStr, const char *pFormat, ...);
signed int puts(const char *pStr);
int fputc(int c, FILE *stream);
int fputs(const char *s, FILE *stream);
#define putc(c, stream) fputc(c, stream)
#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
#include <stdlib.h>

View File

@@ -1,3 +1,19 @@
/* 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
#include <osmocom/core/linuxlist.h>

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
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

View File

@@ -1,24 +1,22 @@
/* ISO7816-3 state machine for the card side */
/* (C) 2010-2017 by Harald Welte <hwelte@hmw-consulting.de>
/* ISO7816-3 state machine for the card side
*
* 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.
* (C) 2010-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 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.
* 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.
*
* 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
* 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
*/
//#define TRACE_LEVEL 6
#include <stdio.h>
#include <assert.h>
#include <errno.h>
@@ -56,6 +54,22 @@ enum iso7816_3_card_state {
ISO_S_IN_TPDU, /* inside a TPDU */
};
const struct value_string iso7816_3_card_state_names[] = {
OSMO_VALUE_STRING(ISO_S_WAIT_POWER),
OSMO_VALUE_STRING(ISO_S_WAIT_CLK),
OSMO_VALUE_STRING(ISO_S_WAIT_RST),
OSMO_VALUE_STRING(ISO_S_WAIT_ATR),
OSMO_VALUE_STRING(ISO_S_IN_ATR),
OSMO_VALUE_STRING(ISO_S_IN_PTS),
OSMO_VALUE_STRING(ISO_S_WAIT_TPDU),
OSMO_VALUE_STRING(ISO_S_IN_TPDU),
{
.value = 0,
.str = NULL,
},
};
/* detailed sub-states of ISO_S_IN_PTS */
enum pts_state {
PTS_S_WAIT_REQ_PTSS,
@@ -87,7 +101,7 @@ enum tpdu_state {
TPDU_S_WAIT_P2, /* waiting for P2 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_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 */
};
@@ -98,7 +112,7 @@ enum tpdu_state {
#define _P3 4
struct card_handle {
uint32_t num;
unsigned int num;
enum iso7816_3_card_state state;
@@ -192,7 +206,7 @@ struct msgb *usb_buf_alloc_st(uint8_t ep, uint8_t msg_class, uint8_t msg_type)
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)
{
struct msgb *msg;
@@ -205,14 +219,17 @@ static void flush_rx_buffer(struct card_handle *ch)
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->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);
}
/* 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 */
static int serialize_pts(uint8_t *out, const uint8_t *in)
{
@@ -287,8 +304,9 @@ static void card_set_state(struct card_handle *ch,
if (ch->state == new_state)
return;
TRACE_DEBUG("%u: 7816 card state %u -> %u\r\n", ch->num,
ch->state, new_state);
TRACE_DEBUG("%u: 7816 card state %u (%s) -> %u (%s)\r\n", ch->num,
ch->state, get_value_string(iso7816_3_card_state_names, ch->state),
new_state, get_value_string(iso7816_3_card_state_names, new_state));
ch->state = new_state;
switch (new_state) {
@@ -299,32 +317,39 @@ static void card_set_state(struct card_handle *ch,
card_emu_uart_enable(ch->uart_chan, 0);
break;
case ISO_S_WAIT_ATR:
set_pts_state(ch, PTS_S_WAIT_REQ_PTSS);
/* Reset to initial Fi / Di ratio */
ch->fi = 1;
ch->di = 1;
emu_update_fidi(ch);
/* initialize todefault WI, this will be overwritten if we
* receive TC2, and it will be programmed into hardware after
/* 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.
*/
tc_etu_set_wtime(ch->tc_chan, 2);
/* ensure the TC_ETU timer is enabled */
tc_etu_enable(ch->tc_chan);
break;
case ISO_S_IN_ATR:
/* initialize to default WI, this will be overwritten if we
* send TC2, and it will be programmed into hardware after
* ATR is finished */
ch->wi = ISO7816_3_DEFAULT_WI;
/* update waiting time to initial waiting time */
ch->waiting_time = ISO7816_3_INIT_WTIME;
/* set initial waiting time */
tc_etu_set_wtime(ch->tc_chan, ch->waiting_time);
/* Set ATR sub-state to initial state */
ch->atr.idx = 0;
//set_atr_state(ch, ATR_S_WAIT_TS);
/* Notice that we are just coming out of reset */
//ch->sh.flags |= SIMTRACE_FLAG_ATR;
/* enable USART transmission to reader */
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;
case ISO_S_WAIT_TPDU:
/* enable the receiver, disable transmitter */
set_tpdu_state(ch, TPDU_S_WAIT_CLA);
card_emu_uart_enable(ch->uart_chan, ENABLE_RX);
break;
case ISO_S_IN_ATR:
case ISO_S_IN_PTS:
case ISO_S_IN_TPDU:
/* do nothing */
@@ -332,12 +357,80 @@ 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 */
ch->wi = ISO7816_3_DEFAULT_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 */
}
}
}
}
}
/* update waiting time (see ISO 7816-3 10.2) */
ch->waiting_time = ch->wi * 960 * ch->fi;
tc_etu_set_wtime(ch->tc_chan, ch->waiting_time);
/* 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
**********************************************************************/
/* Update the ATR sub-state */
/* Update the PTS sub-state */
static void set_pts_state(struct card_handle *ch, enum pts_state new_ptss)
{
TRACE_DEBUG("%u: 7816 PTS state %u -> %u\r\n",
@@ -718,7 +811,7 @@ static int tx_byte_tpdu(struct card_handle *ch)
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) {
case TPDU_S_WAIT_PB:
/* if we just transmitted the procedure byte, we need to decide
@@ -765,14 +858,6 @@ void card_emu_process_rx_byte(struct card_handle *ch, uint8_t byte)
ch->stats.rx_bytes++;
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:
if (byte == 0xff) {
new_state = process_byte_pts(ch, byte);
@@ -786,6 +871,10 @@ void card_emu_process_rx_byte(struct card_handle *ch, uint8_t byte)
case ISO_S_IN_PTS:
new_state = process_byte_pts(ch, byte);
goto out_silent;
default:
TRACE_ERROR("%u: Received UART char in invalid 7816 state "
"%u\r\n", ch->num, ch->state);
break;
}
out_silent:
@@ -800,17 +889,7 @@ int card_emu_tx_byte(struct card_handle *ch)
switch (ch->state) {
case ISO_S_IN_ATR:
if (ch->atr.idx < ch->atr.len) {
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);
}
rc = tx_byte_atr(ch);
break;
case ISO_S_IN_PTS:
rc = tx_byte_pts(ch);
@@ -905,9 +984,8 @@ void card_emu_io_statechg(struct card_handle *ch, enum card_io io, int active)
if (ch->vcc_active && ch->clocked) {
/* enable the TC/ETU counter once reset has been released */
tc_etu_enable(ch->tc_chan);
/* prepare to send the 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) {
TRACE_INFO("%u: RST asserted\r\n", ch->num);
@@ -928,7 +1006,15 @@ int card_emu_set_atr(struct card_handle *ch, const uint8_t *atr, uint8_t len)
ch->atr.len = len;
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 < ch->atr.len; i++) {
TRACE_INFO_WP("%02x ", atr[i]);
}
TRACE_INFO_WP("\n\r");
#endif
/* FIXME: race condition with transmitting ATR to reader? */
return 0;
}
@@ -959,7 +1045,15 @@ void tc_etu_wtime_half_expired(void *handle)
void tc_etu_wtime_expired(void *handle)
{
struct card_handle *ch = handle;
TRACE_ERROR("%u: wtime_exp\r\n", ch->num);
switch (ch->state) {
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:
TRACE_ERROR("%u: wtime_exp\r\n", ch->num);
break;
}
}
/* shortest ATR found in smartcard_list.txt */
@@ -981,7 +1075,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);
/* initialize the card_handle with reasonabe defaults */
/* initialize the card_handle with reasonable defaults */
ch->num = slot_num;
ch->irq_ep = irq_ep;
ch->in_ep = in_ep;

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 "uart_console.h"
@@ -10,6 +26,19 @@ int fputc(int c, FILE *stream)
int fputs(const char *s, FILE *stream)
{
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;
}

View File

@@ -1,3 +1,19 @@
/* 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 "llist_irqsafe.h"
#include "usb_buf.h"
@@ -134,7 +150,7 @@ int usb_refill_from_host(uint8_t ep)
rc = USBD_Read(ep, msg->head, msgb_tailroom(msg),
(TransferCallback) &usb_read_cb, msg);
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);
bep->in_progress = 0;
}

View File

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

View File

@@ -1,22 +1,21 @@
/* ISO7816-3 Fi/Di tables + computation */
/* (C) 2010-2015 by Harald Welte <hwelte@hmw-consulting.de>
/* ISO7816-3 Fi/Di tables + computation
*
* 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.
* (C) 2010-2015 by Harald Welte <laforge@gnumonks.org>
*
* 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.
* 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.
*
* 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
* 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 <errno.h>

View File

@@ -1,5 +1,22 @@
//#define TRACE_LEVEL 6
/* card emulation mode
*
* (C) 2015-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 "boardver_adc.h"
#include "simtrace.h"
@@ -33,7 +50,7 @@ static const Pin pin_usim2_vcc = PIN_USIM2_VCC;
#endif
struct cardem_inst {
uint32_t num;
unsigned int num;
struct card_handle *ch;
struct llist_head usb_out_queue;
struct ringbuf rb;
@@ -82,15 +99,11 @@ struct cardem_inst cardem_inst[] = {
static Usart *get_usart_by_chan(uint8_t uart_chan)
{
switch (uart_chan) {
case 0:
return USART1;
#ifdef CARDEMU_SECOND_UART
case 1:
return USART0;
#endif
if (uart_chan < ARRAY_SIZE(cardem_inst)) {
return cardem_inst[uart_chan].usart_info.base;
} else {
return NULL;
}
return NULL;
}
/***********************************************************************
@@ -104,7 +117,7 @@ static void wait_tx_idle(Usart *usart)
/* wait until last char has been fully transmitted */
while ((usart->US_CSR & (US_CSR_TXEMPTY)) == 0) {
if (!(i%1000000)) {
TRACE_ERROR("s: %x \r\n", usart->US_CSR);
TRACE_ERROR("s: %lx \r\n", usart->US_CSR);
}
i++;
}
@@ -161,7 +174,7 @@ int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte)
int i = 1;
while ((usart->US_CSR & (US_CSR_TXRDY)) == 0) {
if (!(i%1000000)) {
TRACE_ERROR("%u: s: %x %02X\r\n",
TRACE_ERROR("%u: s: %lx %02lX\r\n",
uart_chan, usart->US_CSR,
usart->US_RHR & 0xFF);
usart->US_CR = US_CR_RSTTX;
@@ -187,8 +200,9 @@ static void usart_irq_rx(uint8_t inst_num)
csr = usart->US_CSR & usart->US_IMR;
if (csr & US_CSR_RXRDY) {
byte = (usart->US_RHR) & 0xFF;
rbuf_write(&ci->rb, byte);
byte = (usart->US_RHR) & 0xFF;
if (rbuf_write(&ci->rb, byte) < 0)
TRACE_ERROR("rbuf overrun\r\n");
}
if (csr & US_CSR_TXRDY) {
@@ -199,7 +213,7 @@ static void usart_irq_rx(uint8_t inst_num)
if (csr & (US_CSR_OVRE|US_CSR_FRAME|US_CSR_PARE|
US_CSR_TIMEOUT|US_CSR_NACK|(1<<10))) {
usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
TRACE_ERROR("%u e 0x%x st: 0x%x\n", ci->num, byte, csr);
TRACE_ERROR("%u e 0x%x st: 0x%lx\n", ci->num, byte, csr);
}
}
@@ -227,6 +241,20 @@ int card_emu_uart_update_fidi(uint8_t uart_chan, unsigned int fidi)
return 0;
}
/* 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);
}
}
/***********************************************************************
* ADC for VCC voltage detection
***********************************************************************/
@@ -324,7 +352,7 @@ void ADC_IrqHandler(void)
#endif /* DETECT_VCC_BY_ADC */
/***********************************************************************
* Core USB / mainloop integration
* Core USB / main loop integration
***********************************************************************/
static void usim1_rst_irqhandler(const Pin *pPin)
@@ -576,6 +604,7 @@ static void dispatch_usb_command(struct msgb *msg, struct cardem_inst *ci)
usb_buf_free(msg);
return;
}
msg->l2h = msg->l1h + sizeof(*sh);
switch (sh->msg_class) {
case SIMTRACE_MSGC_GENERIC:
@@ -587,7 +616,6 @@ static void dispatch_usb_command(struct msgb *msg, struct cardem_inst *ci)
case SIMTRACE_MSGC_MODEM:
/* FIXME: Find out why this fails if used for !=
* MSGC_MODEM ?!? */
msg->l2h = msg->l1h + sizeof(*sh);
dispatch_usb_command_modem(msg, ci);
break;
default:

View File

@@ -84,11 +84,11 @@ static const Pin pinSmartCard = SMARTCARD_CONNECT_PIN;
static void ISR_PioSmartCard(const Pin * pPin)
{
/* 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("+++++ Mask: 0x%X\n\r", pinSmartCard.mask);
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);
Output:
+++++ Trying to check for pending interrupts (PIO ISR: 0x400)) = 1<<10
+++++ Mask: 0x100 = 1<<8
+++++ Trying to check for pending interrupts (PIO ISR: 0x400)) = 1<<10
+++++ Mask: 0x100 = 1<<8
*/
// PA10 is DTXD, which is the debug uart transmit pin

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
*/
#include <stdint.h>
#include "talloc.h"
@@ -46,7 +62,7 @@ int _talloc_free(void *ptr, const char *location)
for (i = 0; i < ARRAY_SIZE(msgb_inuse); i++) {
if (ptr == msgb_data[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 {
msgb_inuse[i] = 0;
}

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 "trace.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)
{
unsigned long state;
@@ -52,7 +72,7 @@ bool rbuf_is_full(volatile ringbuf * rb)
return rc;
}
void rbuf_write(volatile ringbuf * rb, uint8_t item)
int rbuf_write(volatile ringbuf * rb, uint8_t item)
{
unsigned long state;
@@ -61,9 +81,10 @@ void rbuf_write(volatile ringbuf * rb, uint8_t item)
rb->buf[rb->iwr] = item;
rb->iwr = (rb->iwr + 1) % RING_BUFLEN;
local_irq_restore(state);
return 0;
} else {
local_irq_restore(state);
TRACE_ERROR("Ringbuffer full, losing bytes!");
return -1;
}
}

View File

@@ -58,7 +58,7 @@ void ISR_PhoneRST(const Pin * pPin)
{
int ret;
// 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 (PIO_Get(&pinPhoneRST) == 0) {
printf(" 0 ");
@@ -117,7 +117,7 @@ void mode_trace_usart1_irq(void)
}
/* FIDI update functions */
void update_fidi(Usart *usart, uint8_t fidi)
void update_fidi(Usart_info *usart, uint8_t fidi)
{
if (NULL==usart) {
return;
@@ -129,14 +129,14 @@ void update_fidi(Usart *usart, uint8_t fidi)
if (ratio > 0 && ratio < 0x8000) {
/* make sure USART uses new F/D ratio */
usart->US_CR |= US_CR_RXDIS | US_CR_RSTRX;
usart->base->US_CR |= US_CR_RXDIS | US_CR_RSTRX;
/* disable write protection */
if (usart->US_WPMR) {
usart->US_WPMR = US_WPMR_WPKEY(0x555341);
if (usart->base->US_WPMR) {
usart->base->US_WPMR = US_WPMR_WPKEY(0x555341);
}
usart->US_FIDI = (ratio & 0x7ff);
usart->US_CR |= US_CR_RXEN | US_CR_STTTO;
//TRACE_INFO("updated USART Fi(%u)/Di(%u) ratio(%d): %u\n\r", fi, di, ratio, usart->US_FIDI); /* don't print since this is function is also called by ISRs */
usart->base->US_FIDI = (ratio & 0x7ff);
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 */
}

View File

@@ -1,25 +1,29 @@
/*
* (C) 2010-2017 by Harald Welte <hwelte@sysmocom.de>
* (C) 2018 by Kevin Redon <kredon@sysmocom.de>
* All Rights Reserved
/* SIMtrace 2 sniffer mode
*
* (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 Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* 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
*/
/* This code implement the Sniffer mode to sniff the communication between a SIM card (or any ISO 7816 smart card) and a phone (or any ISO 7816 card reader).
* For historical reasons (i.e. SIMtrace hardware) the USART peripheral connected to the SIM card is used.
* TODO put common ISO7816-3 code is separate library (and combine clean with iso7816_4)
/* This code implement the Sniffer mode to sniff the communication between a
* SIM card (or any ISO 7816 smart card) and a phone (or any ISO 7816 card
* reader).
* For historical reasons (i.e. SIMtrace hardware) the USART peripheral
* connected to the SIM card is used.
* TODO put common ISO7816-3 code is separate library (and combine clean with
* iso7816_4)
*/
#include "board.h"
#include "simtrace.h"
@@ -178,6 +182,11 @@ uint8_t tpdu_packet[5+256+2];
/*! Current index in TPDU packet */
uint16_t tpdu_packet_i = 0;
/*! Waiting Time (WT)
* @note defined in ISO/IEC 7816-3:2006(E) section 8.1 and 10.2
*/
uint32_t wt = 9600;
/*------------------------------------------------------------------------------
* Internal functions
*------------------------------------------------------------------------------*/
@@ -188,13 +197,75 @@ uint16_t tpdu_packet_i = 0;
*/
static const uint8_t convention_convert_lut[256] = { 0xff, 0x7f, 0xbf, 0x3f, 0xdf, 0x5f, 0x9f, 0x1f, 0xef, 0x6f, 0xaf, 0x2f, 0xcf, 0x4f, 0x8f, 0x0f, 0xf7, 0x77, 0xb7, 0x37, 0xd7, 0x57, 0x97, 0x17, 0xe7, 0x67, 0xa7, 0x27, 0xc7, 0x47, 0x87, 0x07, 0xfb, 0x7b, 0xbb, 0x3b, 0xdb, 0x5b, 0x9b, 0x1b, 0xeb, 0x6b, 0xab, 0x2b, 0xcb, 0x4b, 0x8b, 0x0b, 0xf3, 0x73, 0xb3, 0x33, 0xd3, 0x53, 0x93, 0x13, 0xe3, 0x63, 0xa3, 0x23, 0xc3, 0x43, 0x83, 0x03, 0xfd, 0x7d, 0xbd, 0x3d, 0xdd, 0x5d, 0x9d, 0x1d, 0xed, 0x6d, 0xad, 0x2d, 0xcd, 0x4d, 0x8d, 0x0d, 0xf5, 0x75, 0xb5, 0x35, 0xd5, 0x55, 0x95, 0x15, 0xe5, 0x65, 0xa5, 0x25, 0xc5, 0x45, 0x85, 0x05, 0xf9, 0x79, 0xb9, 0x39, 0xd9, 0x59, 0x99, 0x19, 0xe9, 0x69, 0xa9, 0x29, 0xc9, 0x49, 0x89, 0x09, 0xf1, 0x71, 0xb1, 0x31, 0xd1, 0x51, 0x91, 0x11, 0xe1, 0x61, 0xa1, 0x21, 0xc1, 0x41, 0x81, 0x01, 0xfe, 0x7e, 0xbe, 0x3e, 0xde, 0x5e, 0x9e, 0x1e, 0xee, 0x6e, 0xae, 0x2e, 0xce, 0x4e, 0x8e, 0x0e, 0xf6, 0x76, 0xb6, 0x36, 0xd6, 0x56, 0x96, 0x16, 0xe6, 0x66, 0xa6, 0x26, 0xc6, 0x46, 0x86, 0x06, 0xfa, 0x7a, 0xba, 0x3a, 0xda, 0x5a, 0x9a, 0x1a, 0xea, 0x6a, 0xaa, 0x2a, 0xca, 0x4a, 0x8a, 0x0a, 0xf2, 0x72, 0xb2, 0x32, 0xd2, 0x52, 0x92, 0x12, 0xe2, 0x62, 0xa2, 0x22, 0xc2, 0x42, 0x82, 0x02, 0xfc, 0x7c, 0xbc, 0x3c, 0xdc, 0x5c, 0x9c, 0x1c, 0xec, 0x6c, 0xac, 0x2c, 0xcc, 0x4c, 0x8c, 0x0c, 0xf4, 0x74, 0xb4, 0x34, 0xd4, 0x54, 0x94, 0x14, 0xe4, 0x64, 0xa4, 0x24, 0xc4, 0x44, 0x84, 0x04, 0xf8, 0x78, 0xb8, 0x38, 0xd8, 0x58, 0x98, 0x18, 0xe8, 0x68, 0xa8, 0x28, 0xc8, 0x48, 0x88, 0x08, 0xf0, 0x70, 0xb0, 0x30, 0xd0, 0x50, 0x90, 0x10, 0xe0, 0x60, 0xa0, 0x20, 0xc0, 0x40, 0x80, 0x00, };
/*! Update Waiting Time (WT)
* @param[in] wi Waiting Integer (0 if unchanged)
* @param[in] d Baud Rate divider (0 if unchanged)
* @note set wt to be used by the receiver timeout
* @note defined in ISO/IEC 7816-3:2006(E) section 8.1 and 10.2
*/
static void update_wt(uint8_t wi, uint8_t d)
{
static uint8_t wt_wi = 10; /* Waiting time Integer (WI), used to calculate the Waiting Time (WT) */
static uint8_t wt_d = 1; /* baud rate adjustment integer (the actual value, not the table index) */
if (0 != wi) {
wt_wi = wi;
}
if (0 != d) {
wt_d = d;
}
wt = wt_wi*960UL*wt_d;
TRACE_INFO("WT updated to %lu\n\r", wt);
}
/*! Allocate USB buffer and push + initialize simtrace_msg_hdr
* @param[in] ep USB IN endpoint where the message will be sent to
* @param[in] msg_class SIMtrace USB message class
* @param[in] msg_type SIMtrace USB message type
* @return USB message with allocated ans initialized header, or NULL if allocation failed
*/
static struct msgb *usb_msg_alloc_hdr(uint8_t ep, uint8_t msg_class, uint8_t msg_type)
{
/* Only allocate message if not too many are already in the queue */
struct llist_head *head = usb_get_queue(SIMTRACE_USB_EP_CARD_DATAIN);
if (!head) {
return NULL;
}
if (llist_count(head) > 5) {
return NULL;
}
struct msgb *usb_msg = usb_buf_alloc(SIMTRACE_USB_EP_CARD_DATAIN);
if (!usb_msg) {
return NULL;
}
struct simtrace_msg_hdr *usb_msg_header;
usb_msg->l1h = msgb_put(usb_msg, sizeof(*usb_msg_header));
usb_msg_header = (struct simtrace_msg_hdr *) usb_msg->l1h;
memset(usb_msg_header, 0, sizeof(*usb_msg_header));
usb_msg_header->msg_class = msg_class;
usb_msg_header->msg_type = msg_type;
usb_msg->l2h = usb_msg->l1h + sizeof(*usb_msg_header);
return usb_msg;
}
/* update SIMtrace header msg_len and submit USB buffer
* param[in] usb_msg USB message to update and send
*/
void usb_msg_upd_len_and_submit(struct msgb *usb_msg)
{
struct simtrace_msg_hdr *usb_msg_header = (struct simtrace_msg_hdr *) usb_msg->l1h;
usb_msg_header->msg_len = msgb_length(usb_msg);
usb_buf_submit(usb_msg);
}
/*! Update the ISO 7816-3 state
* @param[in] iso_state_new new ISO 7816-3 state to update to
*/
static void change_state(enum iso7816_3_sniff_state iso_state_new)
{
/* sanity check */
if (iso_state_new==iso_state) {
if (iso_state_new == iso_state) {
TRACE_WARNING("Already in ISO 7816 state %u\n\r", iso_state);
return;
}
@@ -202,12 +273,11 @@ static void change_state(enum iso7816_3_sniff_state iso_state_new)
/* handle actions to perform when switching state */
switch (iso_state_new) {
case ISO7816_S_RESET:
update_fidi(sniff_usart.base, 0x11); /* reset baud rate to default Di/Fi values */
change_flags |= SNIFF_CHANGE_FLAG_RESET_HOLD; /* set flag and let main loop send it */
update_fidi(&sniff_usart, 0x11); /* reset baud rate to default Di/Fi values */
update_wt(10, 1); /* reset WT time-out */
break;
case ISO7816_S_WAIT_ATR:
rbuf_reset(&sniff_buffer); /* reset buffer for new communication */
change_flags |= SNIFF_CHANGE_FLAG_RESET_RELEASE; /* set flag and let main loop send it */
break;
case ISO7816_S_IN_ATR:
atr_i = 0;
@@ -229,55 +299,110 @@ static void change_state(enum iso7816_3_sniff_state iso_state_new)
/* save new state */
iso_state = iso_state_new;
//TRACE_INFO("Changed to ISO 7816-3 state %u\n\r", iso_state); /* don't print since this is function is also called by ISRs */
TRACE_INFO("Changed to ISO 7816-3 state %u\n\r", iso_state);
}
/*! Send current ATR over USB
* @param[in] complete if the ATR is complete
* @note Also print the ATR to debug console
*/
static void usb_send_atr(bool complete)
{
/* Check state */
if (ISO7816_S_IN_ATR!=iso_state) {
TRACE_WARNING("Can't print ATR in ISO 7816-3 state %u\n\r", iso_state);
return;
const struct value_string data_flags[] = {
{
.value = SNIFF_DATA_FLAG_ERROR_INCOMPLETE,
.str = "incomplete",
},
{
.value = SNIFF_DATA_FLAG_ERROR_MALFORMED,
.str = "malformed",
},
{
.value = SNIFF_DATA_FLAG_ERROR_CHECKSUM,
.str = "checksum error",
},
{
.value = 0,
.str = NULL,
},
};
static void print_flags(const struct value_string* flag_meanings, uint32_t nb_flags, uint32_t flags) {
uint32_t i;
for (i = 0; i < nb_flags; i++) {
if (flags & flag_meanings[i].value) {
printf("%s", flag_meanings[i].str);
flags &= ~flag_meanings[i].value;
if (flags) {
printf(", ");
}
}
}
if (atr_i>=ARRAY_SIZE(atr)) {
TRACE_ERROR("ATR buffer overflow\n\r");
}
static void usb_send_data(enum simtrace_msg_type_sniff type, const uint8_t* data, uint16_t length, uint32_t flags)
{
/* Sanity check */
if (type != SIMTRACE_MSGT_SNIFF_ATR && type != SIMTRACE_MSGT_SNIFF_PPS && type != SIMTRACE_MSGT_SNIFF_TPDU) {
return;
}
/* Show activity on LED */
led_blink(LED_GREEN, BLINK_2O_F);
led_blink(LED_GREEN, BLINK_2F_O);
/* Print ATR */
printf("ATR%s: ", complete ? "" : " (incomplete)");
for (uint8_t i=0; i<atr_i; i++) {
printf("%02x ", atr[i]);
/* Print message */
switch (type) {
case SIMTRACE_MSGT_SNIFF_ATR:
printf("ATR");
break;
case SIMTRACE_MSGT_SNIFF_PPS:
printf("PPS");
break;
case SIMTRACE_MSGT_SNIFF_TPDU:
printf("TPDU");
break;
default:
printf("???");
break;
}
if (flags) {
printf(" (");
print_flags(data_flags, ARRAY_SIZE(data_flags), flags);
putchar(')');
}
printf(": ");
uint16_t i;
for (i = 0; i < length; i++) {
printf("%02x ", data[i]);
}
printf("\n\r");
/* Send ATR over USB */
struct msgb *usb_msg = usb_buf_alloc(SIMTRACE_USB_EP_CARD_DATAIN);
/* Send data over USB */
struct msgb *usb_msg = usb_msg_alloc_hdr(SIMTRACE_USB_EP_CARD_DATAIN, SIMTRACE_MSGC_SNIFF, type);
if (!usb_msg) {
return;
}
struct simtrace_msg_hdr *usb_msg_header;
usb_msg->l1h = msgb_put(usb_msg, sizeof(*usb_msg_header));
usb_msg_header = (struct simtrace_msg_hdr *) usb_msg->l1h;
memset(usb_msg_header, 0, sizeof(*usb_msg_header));
usb_msg_header->msg_class = SIMTRACE_MSGC_SNIFF;
usb_msg_header->msg_type = SIMTRACE_MSGT_SNIFF_ATR;
usb_msg->l2h = usb_msg->l1h + sizeof(*usb_msg_header);
struct sniff_data *usb_sniff_data_atr;
usb_sniff_data_atr = (struct sniff_data *) msgb_put(usb_msg, sizeof(*usb_sniff_data_atr));
usb_sniff_data_atr->complete = complete;
usb_sniff_data_atr->length = atr_i;
uint8_t *data = msgb_put(usb_msg, usb_sniff_data_atr->length);
memcpy(data, atr, atr_i);
usb_msg_header->msg_len = msgb_length(usb_msg);
usb_buf_submit(usb_msg);
struct sniff_data *usb_sniff_data = (struct sniff_data *) msgb_put(usb_msg, sizeof(*usb_sniff_data));
usb_sniff_data->flags = flags;
usb_sniff_data->length = length;
uint8_t *sniff_data = msgb_put(usb_msg, usb_sniff_data->length);
memcpy(sniff_data, data, length);
usb_msg_upd_len_and_submit(usb_msg);
}
/*! Send current ATR over USB
* @param[in] flags SNIFF_DATA_FLAG_ data flags
* @note Also print the ATR to debug console
*/
static void usb_send_atr(uint32_t flags)
{
/* Check state */
if (ISO7816_S_IN_ATR != iso_state) {
TRACE_WARNING("Can't print ATR in ISO 7816-3 state %u\n\r", iso_state);
return;
}
if (atr_i >= ARRAY_SIZE(atr)) {
TRACE_ERROR("ATR buffer overflow\n\r");
return;
}
/* Send ATR over USB */
usb_send_data(SIMTRACE_MSGT_SNIFF_ATR, atr, atr_i, flags);
}
/*! Process ATR byte
@@ -287,13 +412,15 @@ static void process_byte_atr(uint8_t byte)
{
static uint8_t atr_hist_len = 0; /* store the number of expected historical bytes */
static uint8_t y = 0; /* last mask of the upcoming TA, TB, TC, TD interface bytes */
static uint8_t i = 0; /* interface byte subgroup number */
static uint32_t flags = 0; /* error flag */
/* sanity check */
if (ISO7816_S_IN_ATR!=iso_state) {
if (ISO7816_S_IN_ATR != iso_state) {
TRACE_ERROR("Processing ATR data in wrong ISO 7816-3 state %u\n\r", iso_state);
return;
}
if (atr_i>=ARRAY_SIZE(atr)) {
if (atr_i >= ARRAY_SIZE(atr)) {
TRACE_ERROR("ATR data overflow\n\r");
return;
}
@@ -304,6 +431,7 @@ static void process_byte_atr(uint8_t byte)
/* handle ATR byte depending on current state */
switch (atr_state) {
case ATR_S_WAIT_TS: /* see ISO/IEC 7816-3:2006 section 8.1 */
flags = 0;
switch (byte) {
case 0x23: /* direct convention used, but decoded using inverse convention (a parity error should also have occurred) */
case 0x30: /* inverse convention used, but decoded using direct convention (a parity error should also have occurred) */
@@ -313,34 +441,47 @@ static void process_byte_atr(uint8_t byte)
atr_state = ATR_S_WAIT_T0; /* wait for format byte */
break;
default:
atr_i--; /* revert last byte */
TRACE_WARNING("Invalid TS received\n\r");
led_blink(LED_RED, BLINK_2F_O); /* indicate error to user */
usb_send_atr(SNIFF_DATA_FLAG_ERROR_MALFORMED); /* send ATR to host software using USB */
change_state(ISO7816_S_WAIT_ATR); /* reset state */
break;
}
i = 0; /* first interface byte sub-group is coming (T0 is kind of TD0) */
break;
case ATR_S_WAIT_T0: /* see ISO/IEC 7816-3:2006 section 8.2.2 */
case ATR_S_WAIT_TD: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
if (ATR_S_WAIT_T0==atr_state) {
atr_hist_len = (byte&0x0f); /* save the number of historical bytes */
} else if (ATR_S_WAIT_TD==atr_state) {
t_protocol_support |= (1<<(byte&0x0f)); /* remember supported protocol to know if TCK will be present */
if (ATR_S_WAIT_T0 == atr_state) {
atr_hist_len = (byte & 0x0f); /* save the number of historical bytes */
} else if (ATR_S_WAIT_TD == atr_state) {
t_protocol_support |= (1<<(byte & 0x0f)); /* remember supported protocol to know if TCK will be present */
}
y = (byte&0xf0); /* remember upcoming interface bytes */
if (y&0x10) {
y = (byte & 0xf0); /* remember upcoming interface bytes */
i++; /* next interface byte sub-group is coming */
if (y & 0x10) {
atr_state = ATR_S_WAIT_TA; /* wait for interface byte TA */
break;
}
case ATR_S_WAIT_TA: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
if (y&0x20) {
if (y & 0x20) {
atr_state = ATR_S_WAIT_TB; /* wait for interface byte TB */
break;
}
case ATR_S_WAIT_TB: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
if (y&0x40) {
if (y & 0x40) {
atr_state = ATR_S_WAIT_TC; /* wait for interface byte TC */
break;
}
case ATR_S_WAIT_TC: /* see ISO/IEC 7816-3:2006 section 8.2.3 */
if (y&0x80) {
/* retrieve WI encoded in TC2*/
if (ATR_S_WAIT_TC==atr_state && 2==i) {
if (0 == byte) {
update_wt(10, 0);
} else {
update_wt(byte, 0);
}
}
if (y & 0x80) {
atr_state = ATR_S_WAIT_TD; /* wait for interface byte TD */
break;
} else if (atr_hist_len) {
@@ -351,8 +492,8 @@ static void process_byte_atr(uint8_t byte)
if (atr_hist_len) {
atr_hist_len--;
}
if (0==atr_hist_len) {
if (t_protocol_support>1) {
if (0 == atr_hist_len) {
if (t_protocol_support > 1) {
atr_state = ATR_S_WAIT_TCK; /* wait for check bytes */
break;
}
@@ -360,8 +501,21 @@ static void process_byte_atr(uint8_t byte)
break;
}
case ATR_S_WAIT_TCK: /* see ISO/IEC 7816-3:2006 section 8.2.5 */
/* we could verify the checksum, but we are just here to sniff */
usb_send_atr(true); /* send ATR to host software using USB */
/* verify checksum if present */
if (ATR_S_WAIT_TCK == atr_state) {
uint8_t ui;
uint8_t checksum = 0;
for (ui = 1; ui < atr_i; ui++) {
checksum ^= atr[ui];
}
if (checksum) {
flags |= SNIFF_DATA_FLAG_ERROR_CHECKSUM;
/* We still consider the data as valid (e.g. for WT) even is the checksum is wrong.
* It is up to the reader to handle this error (e.g. by resetting)
*/
}
}
usb_send_atr(flags); /* send ATR to host software using USB */
change_state(ISO7816_S_WAIT_TPDU); /* go to next state */
break;
default:
@@ -370,17 +524,17 @@ static void process_byte_atr(uint8_t byte)
}
/*! Send current PPS over USB
* @param[in] complete if the PPS is complete
* @param[in] flags SNIFF_DATA_FLAG_ data flags
* @note Also print the PPS over the debug console
*/
static void usb_send_pps(bool complete)
static void usb_send_pps(uint32_t flags)
{
uint8_t *pps_cur; /* current PPS (request or response) */
/* Sanity check */
if (ISO7816_S_IN_PPS_REQ==iso_state) {
if (ISO7816_S_IN_PPS_REQ == iso_state) {
pps_cur = pps_req;
} else if (ISO7816_S_IN_PPS_RSP==iso_state) {
} else if (ISO7816_S_IN_PPS_RSP == iso_state) {
pps_cur = pps_rsp;
} else {
TRACE_ERROR("Can't print PPS in ISO 7816-3 state %u\n\r", iso_state);
@@ -390,55 +544,27 @@ static void usb_send_pps(bool complete)
/* Get only relevant data */
uint8_t pps[6];
uint8_t pps_i = 0;
if (pps_state>PPS_S_WAIT_PPSS) {
if (pps_state > PPS_S_WAIT_PPSS) {
pps[pps_i++] = pps_cur[0];
}
if (pps_state>PPS_S_WAIT_PPS0) {
if (pps_state > PPS_S_WAIT_PPS0) {
pps[pps_i++] = pps_cur[1];
}
if (pps_state>PPS_S_WAIT_PPS1 && pps_cur[1]&0x10) {
if (pps_state > PPS_S_WAIT_PPS1 && pps_cur[1] & 0x10) {
pps[pps_i++] = pps_cur[2];
}
if (pps_state>PPS_S_WAIT_PPS2 && pps_cur[1]&0x20) {
if (pps_state > PPS_S_WAIT_PPS2 && pps_cur[1] & 0x20) {
pps[pps_i++] = pps_cur[3];
}
if (pps_state>PPS_S_WAIT_PPS3 && pps_cur[1]&0x40) {
if (pps_state > PPS_S_WAIT_PPS3 && pps_cur[1] & 0x40) {
pps[pps_i++] = pps_cur[4];
}
if (pps_state>PPS_S_WAIT_PCK) {
if (pps_state > PPS_S_WAIT_PCK) {
pps[pps_i++] = pps_cur[5];
}
/* Show activity on LED */
led_blink(LED_GREEN, BLINK_2O_F);
/* Print PPS */
printf("PPS%s: ", complete ? "" : " (incomplete)");
for (uint8_t i=0; i<pps_i; i++) {
printf("%02x ", pps[i]);
}
printf("\n\r");
/* Send message over USB */
struct msgb *usb_msg = usb_buf_alloc(SIMTRACE_USB_EP_CARD_DATAIN);
if (!usb_msg) {
return;
}
struct simtrace_msg_hdr *usb_msg_header;
usb_msg->l1h = msgb_put(usb_msg, sizeof(*usb_msg_header));
usb_msg_header = (struct simtrace_msg_hdr *) usb_msg->l1h;
memset(usb_msg_header, 0, sizeof(*usb_msg_header));
usb_msg_header->msg_class = SIMTRACE_MSGC_SNIFF;
usb_msg_header->msg_type = SIMTRACE_MSGT_SNIFF_PPS;
usb_msg->l2h = usb_msg->l1h + sizeof(*usb_msg_header);
struct sniff_data *usb_sniff_data_pps;
usb_sniff_data_pps = (struct sniff_data *) msgb_put(usb_msg, sizeof(*usb_sniff_data_pps));
usb_sniff_data_pps->complete = complete;
usb_sniff_data_pps->length = pps_i;
uint8_t *data = msgb_put(usb_msg, usb_sniff_data_pps->length);
memcpy(data, pps, pps_i);
usb_msg_header->msg_len = msgb_length(usb_msg);
usb_buf_submit(usb_msg);
usb_send_data(SIMTRACE_MSGT_SNIFF_PPS, pps, pps_i, flags);
}
/*! Send Fi/Di change over USB
@@ -447,32 +573,24 @@ static void usb_send_pps(bool complete)
static void usb_send_fidi(uint8_t fidi)
{
/* Send message over USB */
struct msgb *usb_msg = usb_buf_alloc(SIMTRACE_USB_EP_CARD_DATAIN);
struct msgb *usb_msg = usb_msg_alloc_hdr(SIMTRACE_USB_EP_CARD_DATAIN, SIMTRACE_MSGC_SNIFF, SIMTRACE_MSGT_SNIFF_FIDI);
if (!usb_msg) {
return;
}
struct simtrace_msg_hdr *usb_msg_header;
usb_msg->l1h = msgb_put(usb_msg, sizeof(*usb_msg_header));
usb_msg_header = (struct simtrace_msg_hdr *) usb_msg->l1h;
memset(usb_msg_header, 0, sizeof(*usb_msg_header));
usb_msg_header->msg_class = SIMTRACE_MSGC_SNIFF;
usb_msg_header->msg_type = SIMTRACE_MSGT_SNIFF_FIDI;
usb_msg->l2h = usb_msg->l1h + sizeof(*usb_msg_header);
struct sniff_fidi *usb_sniff_fidi;
usb_sniff_fidi = (struct sniff_fidi *) msgb_put(usb_msg, sizeof(*usb_sniff_fidi));
struct sniff_fidi *usb_sniff_fidi = (struct sniff_fidi *) msgb_put(usb_msg, sizeof(*usb_sniff_fidi));
usb_sniff_fidi->fidi = fidi;
usb_msg_header->msg_len = msgb_length(usb_msg);
usb_buf_submit(usb_msg);
usb_msg_upd_len_and_submit(usb_msg);
}
static void process_byte_pps(uint8_t byte)
{
uint8_t *pps_cur; /* current PPS (request or response) */
static uint32_t flags = 0; /* error flag */
/* sanity check */
if (ISO7816_S_IN_PPS_REQ==iso_state) {
if (ISO7816_S_IN_PPS_REQ == iso_state) {
pps_cur = pps_req;
} else if (ISO7816_S_IN_PPS_RSP==iso_state) {
} else if (ISO7816_S_IN_PPS_RSP == iso_state) {
pps_cur = pps_rsp;
} else {
TRACE_ERROR("Processing PPS data in wrong ISO 7816-3 state %u\n\r", iso_state);
@@ -482,29 +600,32 @@ static void process_byte_pps(uint8_t byte)
/* handle PPS byte depending on current state */
switch (pps_state) { /* see ISO/IEC 7816-3:2006 section 9.2 */
case PPS_S_WAIT_PPSS: /*!< initial byte */
flags = 0;
if (0xff) {
pps_cur[0] = byte;
pps_state = PPS_S_WAIT_PPS0; /* go to next state */
} else {
TRACE_INFO("Invalid PPSS received\n\r");
led_blink(LED_RED, BLINK_2F_O); /* indicate error to user */
usb_send_pps(SNIFF_DATA_FLAG_ERROR_MALFORMED); /* send ATR to host software using USB */
change_state(ISO7816_S_WAIT_TPDU); /* go back to TPDU state */
}
break;
case PPS_S_WAIT_PPS0: /*!< format byte */
pps_cur[1] = byte;
if (pps_cur[1]&0x10) {
if (pps_cur[1] & 0x10) {
pps_state = PPS_S_WAIT_PPS1; /* go to next state */
break;
}
case PPS_S_WAIT_PPS1: /*!< first parameter byte */
pps_cur[2] = byte; /* not always right but doesn't affect the process */
if (pps_cur[1]&0x20) {
if (pps_cur[1] & 0x20) {
pps_state = PPS_S_WAIT_PPS2; /* go to next state */
break;
}
case PPS_S_WAIT_PPS2: /*!< second parameter byte */
pps_cur[3] = byte; /* not always right but doesn't affect the process */
if (pps_cur[1]&0x40) {
if (pps_cur[1] & 0x40) {
pps_state = PPS_S_WAIT_PPS3; /* go to next state */
break;
}
@@ -518,36 +639,40 @@ static void process_byte_pps(uint8_t byte)
uint8_t check = 0;
check ^= pps_cur[0];
check ^= pps_cur[1];
if (pps_cur[1]&0x10) {
if (pps_cur[1] & 0x10) {
check ^= pps_cur[2];
}
if (pps_cur[1]&0x20) {
if (pps_cur[1] & 0x20) {
check ^= pps_cur[3];
}
if (pps_cur[1]&0x40) {
if (pps_cur[1] & 0x40) {
check ^= pps_cur[4];
}
check ^= pps_cur[5];
if (check) {
flags |= SNIFF_DATA_FLAG_ERROR_CHECKSUM;
}
pps_state = PPS_S_WAIT_END;
usb_send_pps(true); /* send PPS to host software using USB */
if (ISO7816_S_IN_PPS_REQ==iso_state) {
if (0==check) { /* checksum is valid */
usb_send_pps(flags); /* send PPS to host software using USB */
if (ISO7816_S_IN_PPS_REQ == iso_state) {
if (0 == check) { /* checksum is valid */
change_state(ISO7816_S_WAIT_PPS_RSP); /* go to next state */
} else { /* checksum is invalid */
change_state(ISO7816_S_WAIT_TPDU); /* go to next state */
}
} else if (ISO7816_S_IN_PPS_RSP==iso_state) {
if (0==check) { /* checksum is valid */
} else if (ISO7816_S_IN_PPS_RSP == iso_state) {
if (0 == check) { /* checksum is valid */
uint8_t fn, dn;
if (pps_cur[1]&0x10) {
fn = (pps_cur[2]>>4);
dn = (pps_cur[2]&0x0f);
if (pps_cur[1] & 0x10) {
fn = (pps_cur[2] >> 4);
dn = (pps_cur[2] & 0x0f);
} else {
fn = 1;
dn = 1;
}
TRACE_INFO("PPS negotiation successful: Fn=%u Dn=%u\n\r", fi_table[fn], di_table[dn]);
update_fidi(sniff_usart.base, pps_cur[2]);
update_fidi(&sniff_usart, pps_cur[2]);
update_wt(0, di_table[dn]);
usb_send_fidi(pps_cur[2]); /* send Fi/Di change notification to host software over USB */
} else { /* checksum is invalid */
TRACE_INFO("PPS negotiation failed\n\r");
@@ -565,57 +690,29 @@ static void process_byte_pps(uint8_t byte)
}
/*! Send current TPDU over USB
* @param[in] complete if the TPDU is complete
* @param[in] flags SNIFF_DATA_FLAG_ data flags
* @note Also print the TPDU over the debug console
*/
static void usb_send_tpdu(bool complete)
static void usb_send_tpdu(uint32_t flags)
{
/* Check state */
if (ISO7816_S_IN_TPDU!=iso_state) {
if (ISO7816_S_IN_TPDU != iso_state) {
TRACE_WARNING("Can't print TPDU in ISO 7816-3 state %u\n\r", iso_state);
return;
}
/* Show activity on LED */
led_blink(LED_GREEN, BLINK_2O_F);
/* Print TPDU */
printf("TPDU%s: ", complete ? "" : " (incomplete)");
for (uint16_t i=0; i<tpdu_packet_i && i<ARRAY_SIZE(tpdu_packet); i++) {
printf("%02x ", tpdu_packet[i]);
}
printf("\n\r");
/* Send ATR over USB */
struct msgb *usb_msg = usb_buf_alloc(SIMTRACE_USB_EP_CARD_DATAIN);
if (!usb_msg) {
return;
}
struct simtrace_msg_hdr *usb_msg_header;
usb_msg->l1h = msgb_put(usb_msg, sizeof(*usb_msg_header));
usb_msg_header = (struct simtrace_msg_hdr *) usb_msg->l1h;
memset(usb_msg_header, 0, sizeof(*usb_msg_header));
usb_msg_header->msg_class = SIMTRACE_MSGC_SNIFF;
usb_msg_header->msg_type = SIMTRACE_MSGT_SNIFF_TPDU;
usb_msg->l2h = usb_msg->l1h + sizeof(*usb_msg_header);
struct sniff_data *usb_sniff_data_tpdu;
usb_sniff_data_tpdu = (struct sniff_data *) msgb_put(usb_msg, sizeof(*usb_sniff_data_tpdu));
usb_sniff_data_tpdu->complete = complete;
usb_sniff_data_tpdu->length = tpdu_packet_i;
uint8_t *data = msgb_put(usb_msg, usb_sniff_data_tpdu->length);
memcpy(data, tpdu_packet, tpdu_packet_i);
usb_msg_header->msg_len = msgb_length(usb_msg);
usb_buf_submit(usb_msg);
usb_send_data(SIMTRACE_MSGT_SNIFF_TPDU, tpdu_packet, tpdu_packet_i, flags);
}
static void process_byte_tpdu(uint8_t byte)
{
/* sanity check */
if (ISO7816_S_IN_TPDU!=iso_state) {
if (ISO7816_S_IN_TPDU != iso_state) {
TRACE_ERROR("Processing TPDU data in wrong ISO 7816-3 state %u\n\r", iso_state);
return;
}
if (tpdu_packet_i>=ARRAY_SIZE(tpdu_packet)) {
if (tpdu_packet_i >= ARRAY_SIZE(tpdu_packet)) {
TRACE_ERROR("TPDU data overflow\n\r");
return;
}
@@ -623,8 +720,10 @@ static void process_byte_tpdu(uint8_t byte)
/* handle TPDU byte depending on current state */
switch (tpdu_state) {
case TPDU_S_CLA:
if (0xff==byte) {
if (0xff == byte) {
TRACE_WARNING("0xff is not a valid class byte\n\r");
led_blink(LED_RED, BLINK_2F_O); /* indicate error to user */
usb_send_tpdu(SNIFF_DATA_FLAG_ERROR_MALFORMED); /* send ATR to host software using USB */
change_state(ISO7816_S_WAIT_TPDU); /* go back to TPDU state */
return;
}
@@ -633,8 +732,10 @@ static void process_byte_tpdu(uint8_t byte)
tpdu_state = TPDU_S_INS;
break;
case TPDU_S_INS:
if ((0x60==(byte&0xf0)) || (0x90==(byte&0xf0))) {
if ((0x60 == (byte & 0xf0)) || (0x90 == (byte & 0xf0))) {
TRACE_WARNING("invalid CLA 0x%02x\n\r", byte);
led_blink(LED_RED, BLINK_2F_O); /* indicate error to user */
usb_send_tpdu(SNIFF_DATA_FLAG_ERROR_MALFORMED); /* send ATR to host software using USB */
change_state(ISO7816_S_WAIT_TPDU); /* go back to TPDU state */
return;
}
@@ -658,43 +759,45 @@ static void process_byte_tpdu(uint8_t byte)
tpdu_state = TPDU_S_PROCEDURE;
break;
case TPDU_S_PROCEDURE:
if (0x60==byte) { /* wait for next procedure byte */
if (0x60 == byte) { /* wait for next procedure byte */
break;
} else if (tpdu_packet[1]==byte) { /* get all remaining data bytes */
} else if (tpdu_packet[1] == byte) { /* get all remaining data bytes */
tpdu_state = TPDU_S_DATA_REMAINING;
break;
} else if ((~tpdu_packet[1])==byte) { /* get single data byte */
} else if ((~tpdu_packet[1]) == byte) { /* get single data byte */
tpdu_state = TPDU_S_DATA_SINGLE;
break;
}
case TPDU_S_SW1:
if ((0x60==(byte&0xf0)) || (0x90==(byte&0xf0))) { /* this procedure byte is SW1 */
if ((0x60 == (byte & 0xf0)) || (0x90 == (byte & 0xf0))) { /* this procedure byte is SW1 */
tpdu_packet[tpdu_packet_i++] = byte;
tpdu_state = TPDU_S_SW2;
} else {
TRACE_WARNING("invalid SW1 0x%02x\n\r", byte);
led_blink(LED_RED, BLINK_2F_O); /* indicate error to user */
usb_send_tpdu(SNIFF_DATA_FLAG_ERROR_MALFORMED); /* send ATR to host software using USB */
change_state(ISO7816_S_WAIT_TPDU); /* go back to TPDU state */
return;
}
break;
case TPDU_S_SW2:
tpdu_packet[tpdu_packet_i++] = byte;
usb_send_tpdu(true); /* send TPDU to host software using USB */
usb_send_tpdu(0); /* send TPDU to host software using USB */
change_state(ISO7816_S_WAIT_TPDU); /* this is the end of the TPDU */
break;
case TPDU_S_DATA_SINGLE:
case TPDU_S_DATA_REMAINING:
tpdu_packet[tpdu_packet_i++] = byte;
if (0==tpdu_packet[4]) {
if (5+256<=tpdu_packet_i) {
if (0 == tpdu_packet[4]) {
if (5+256 <= tpdu_packet_i) {
tpdu_state = TPDU_S_PROCEDURE;
}
} else {
if (5+tpdu_packet[4]<=tpdu_packet_i) {
if (5+tpdu_packet[4] <= tpdu_packet_i) {
tpdu_state = TPDU_S_PROCEDURE;
}
}
if (TPDU_S_DATA_SINGLE==tpdu_state) {
if (TPDU_S_DATA_SINGLE == tpdu_state) {
tpdu_state = TPDU_S_PROCEDURE;
}
break;
@@ -706,6 +809,9 @@ static void process_byte_tpdu(uint8_t byte)
/*! Interrupt Service Routine called on USART activity */
void Sniffer_usart_isr(void)
{
/* Remaining Waiting Time (WI) counter (>16 bits) */
static volatile uint32_t wt_remaining = 9600;
/* Read channel status register */
uint32_t csr = sniff_usart.base->US_CSR;
/* Verify if there was an error */
@@ -717,10 +823,13 @@ void Sniffer_usart_isr(void)
TRACE_WARNING("USART framing error\n\r");
sniff_usart.base->US_CR |= US_CR_RSTSTA;
}
/* Verify if character has been received */
if (csr & US_CSR_RXRDY) {
/* Read communication data byte between phone and SIM */
uint8_t byte = sniff_usart.base->US_RHR;
/* Reset WT timer */
wt_remaining = wt;
/* Store sniffed data into buffer (also clear interrupt */
if (rbuf_is_full(&sniff_buffer)) {
TRACE_ERROR("USART buffer full\n\r");
@@ -728,13 +837,28 @@ void Sniffer_usart_isr(void)
rbuf_write(&sniff_buffer, byte);
}
}
/* Verify it WT timeout occurred, to detect unresponsive card */
if (csr & US_CSR_TIMEOUT) {
/* Stop timeout until next character is received */
if (wt_remaining <= (sniff_usart.base->US_RTOR & 0xffff)) {
/* Just set the flag and let the main loop handle it */
change_flags |= SNIFF_CHANGE_FLAG_TIMEOUT_WT;
/* Reset timeout value */
wt_remaining = wt;
} else {
wt_remaining -= (sniff_usart.base->US_RTOR & 0xffff); /* be sure to subtract the actual timeout since the new might not have been set and reloaded yet */
}
if (wt_remaining > 0xffff) {
sniff_usart.base->US_RTOR = 0xffff;
} else {
sniff_usart.base->US_RTOR = wt_remaining;
}
/* Stop timeout until next character is received (and clears the timeout flag) */
sniff_usart.base->US_CR |= US_CR_STTTO;
/* Just set the flag and let the main loop handle it */
change_flags |= SNIFF_CHANGE_FLAG_TIMEOUT_WT;
if (!(change_flags & SNIFF_CHANGE_FLAG_TIMEOUT_WT)) {
/* Immediately restart the counter it the WT timeout did not occur (needs the timeout flag to be cleared) */
sniff_usart.base->US_CR |= US_CR_RETTO;
}
}
}
@@ -743,19 +867,15 @@ void Sniffer_usart_isr(void)
static void Sniffer_reset_isr(const Pin* pPin)
{
/* Ensure an edge on the reset pin cause the interrupt */
if (pPin->id!=pin_rst.id || 0==(pPin->mask&pin_rst.mask)) {
if (pPin->id != pin_rst.id || 0 == (pPin->mask & pin_rst.mask)) {
TRACE_ERROR("Pin other than reset caused a interrupt\n\r");
return;
}
/* Update the ISO state according to the reset change */
/* Update the ISO state according to the reset change (reset is active low) */
if (PIO_Get(&pin_rst)) {
if (ISO7816_S_WAIT_ATR!=iso_state) {
change_state(ISO7816_S_WAIT_ATR);
}
change_flags |= SNIFF_CHANGE_FLAG_RESET_DEASSERT; /* set flag and let main loop send it */
} else {
if (ISO7816_S_RESET!=iso_state) {
change_state(ISO7816_S_RESET);
}
change_flags |= SNIFF_CHANGE_FLAG_RESET_ASSERT; /* set flag and let main loop send it */
}
}
@@ -765,14 +885,14 @@ static void Sniffer_reset_isr(const Pin* pPin)
void Sniffer_usart1_irq(void)
{
if (ID_USART1==sniff_usart.id) {
if (ID_USART1 == sniff_usart.id) {
Sniffer_usart_isr();
}
}
void Sniffer_usart0_irq(void)
{
if (ID_USART0==sniff_usart.id) {
if (ID_USART0 == sniff_usart.id) {
Sniffer_usart_isr();
}
}
@@ -825,55 +945,45 @@ void Sniffer_init(void)
ISO7816_Init(&sniff_usart, CLK_SLAVE);
/* Only receive data when sniffing */
USART_SetReceiverEnabled(sniff_usart.base, 1);
/* Enable Receiver time-out WT to detect unresponsive cards */
sniff_usart.base->US_RTOR = 9600-12; /* -12 because the timer starts at the end of the 12 ETU frame */
/* Enable Receiver time-out to detect waiting time (WT) time-out (e.g. unresponsive cards) */
sniff_usart.base->US_RTOR = wt;
/* Enable interrupt to indicate when data has been received or timeout occurred */
USART_EnableIt(sniff_usart.base, US_IER_RXRDY | US_IER_TIMEOUT);
/* Set USB priority lower than USART to not miss sniffing data (both at 0 per default) */
if (NVIC_GetPriority(IRQ_USART_SIM)>=NVIC_GetPriority(UDP_IRQn)) {
NVIC_SetPriority(UDP_IRQn, NVIC_GetPriority(IRQ_USART_SIM)+2);
if (NVIC_GetPriority(IRQ_USART_SIM) >= NVIC_GetPriority(UDP_IRQn)) {
NVIC_SetPriority(UDP_IRQn, NVIC_GetPriority(IRQ_USART_SIM) + 2);
}
/* Enable interrupt requests for the USART peripheral */
NVIC_EnableIRQ(IRQ_USART_SIM);
/* Reset state */
if (ISO7816_S_RESET!=iso_state) {
if (ISO7816_S_RESET != iso_state) {
change_state(ISO7816_S_RESET);
}
}
/*! Send card change flags over USB
* @param[in] flags change flags corresponding to SIMTRACE_MSGT_SNIFF_CHANGE
* @note Also print the TPDU over the debug console
* @param[in] flags change flags corresponding to SIMTRACE_MSGT_SNIFF_CHANGE
*/
static void usb_send_change(uint32_t flags)
{
/* Check flags */
if(0==flags) { /* no changes */
if(0 == flags) { /* no changes */
return;
}
if (flags&SNIFF_CHANGE_FLAG_TIMEOUT_WT) {
if (flags & SNIFF_CHANGE_FLAG_TIMEOUT_WT) {
printf("waiting time (WT) timeout\n\r");
}
/* Send message over USB */
struct msgb *usb_msg = usb_buf_alloc(SIMTRACE_USB_EP_CARD_DATAIN);
struct msgb *usb_msg = usb_msg_alloc_hdr(SIMTRACE_USB_EP_CARD_DATAIN, SIMTRACE_MSGC_SNIFF, SIMTRACE_MSGT_SNIFF_CHANGE);
if (!usb_msg) {
return;
}
struct simtrace_msg_hdr *usb_msg_header;
usb_msg->l1h = msgb_put(usb_msg, sizeof(*usb_msg_header));
usb_msg_header = (struct simtrace_msg_hdr *) usb_msg->l1h;
memset(usb_msg_header, 0, sizeof(*usb_msg_header));
usb_msg_header->msg_class = SIMTRACE_MSGC_SNIFF;
usb_msg_header->msg_type = SIMTRACE_MSGT_SNIFF_CHANGE;
usb_msg->l2h = usb_msg->l1h + sizeof(*usb_msg_header);
struct sniff_change *usb_sniff_change;
usb_sniff_change = (struct sniff_change *) msgb_put(usb_msg, sizeof(*usb_sniff_change));
struct sniff_change *usb_sniff_change = (struct sniff_change *) msgb_put(usb_msg, sizeof(*usb_sniff_change));
usb_sniff_change->flags = flags;
usb_msg_header->msg_len = msgb_length(usb_msg);
usb_buf_submit(usb_msg);
usb_msg_upd_len_and_submit(usb_msg);
}
/* Main (idle/busy) loop of this USB configuration */
@@ -891,6 +1001,10 @@ void Sniffer_run(void)
process_any_usb_commands(queue);
*/
/* WARNING: the signal data and flags are not synchronized. We have to hope
* the processing is fast enough to not land in the wrong state while data
* is remaining
*/
/* Handle sniffed data */
if (!rbuf_is_empty(&sniff_buffer)) { /* use if instead of while to let the main loop restart the watchdog */
uint8_t byte = rbuf_read(&sniff_buffer);
@@ -909,8 +1023,8 @@ void Sniffer_run(void)
break;
case ISO7816_S_WAIT_TPDU: /* After the ATR we expect TPDU or PPS data */
case ISO7816_S_WAIT_PPS_RSP:
if (byte == 0xff) {
if (ISO7816_S_WAIT_PPS_RSP==iso_state) {
if (0xff == byte) {
if (ISO7816_S_WAIT_PPS_RSP == iso_state) {
change_state(ISO7816_S_IN_PPS_RSP); /* Go to PPS state */
} else {
change_state(ISO7816_S_IN_PPS_REQ); /* Go to PPS state */
@@ -919,7 +1033,7 @@ void Sniffer_run(void)
break;
}
case ISO7816_S_IN_TPDU: /* More TPDU data incoming */
if (ISO7816_S_WAIT_TPDU==iso_state) {
if (ISO7816_S_WAIT_TPDU == iso_state) {
change_state(ISO7816_S_IN_TPDU);
}
process_byte_tpdu(byte);
@@ -935,20 +1049,52 @@ void Sniffer_run(void)
/* Handle flags */
if (change_flags) { /* WARNING this is not synced with the data buffer handling */
if (change_flags&SNIFF_CHANGE_FLAG_TIMEOUT_WT) {
if (change_flags & SNIFF_CHANGE_FLAG_RESET_ASSERT) {
switch (iso_state) {
case ISO7816_S_IN_ATR:
led_blink(LED_RED, BLINK_2F_O); /* indicate error to user */
usb_send_atr(SNIFF_DATA_FLAG_ERROR_INCOMPLETE); /* send incomplete ATR to host software using USB */
break;
case ISO7816_S_IN_TPDU:
led_blink(LED_RED, BLINK_2F_O); /* indicate error to user */
usb_send_tpdu(SNIFF_DATA_FLAG_ERROR_INCOMPLETE); /* send incomplete PPS to host software using USB */
break;
case ISO7816_S_IN_PPS_REQ:
case ISO7816_S_IN_PPS_RSP:
led_blink(LED_RED, BLINK_2F_O); /* indicate error to user */
usb_send_pps(SNIFF_DATA_FLAG_ERROR_INCOMPLETE); /* send incomplete TPDU to host software using USB */
break;
default:
break;
}
if (ISO7816_S_RESET != iso_state) {
change_state(ISO7816_S_RESET);
printf("reset asserted\n\r");
}
}
if (change_flags & SNIFF_CHANGE_FLAG_RESET_DEASSERT) {
if (ISO7816_S_WAIT_ATR != iso_state) {
change_state(ISO7816_S_WAIT_ATR);
printf("reset de-asserted\n\r");
}
}
if (change_flags & SNIFF_CHANGE_FLAG_TIMEOUT_WT) {
/* Use timeout to detect interrupted data transmission */
switch (iso_state) {
case ISO7816_S_IN_ATR:
usb_send_atr(false); /* send incomplete ATR to host software using USB */
led_blink(LED_RED, BLINK_2F_O); /* indicate error to user */
usb_send_atr(SNIFF_DATA_FLAG_ERROR_INCOMPLETE); /* send incomplete ATR to host software using USB */
change_state(ISO7816_S_WAIT_ATR);
break;
case ISO7816_S_IN_TPDU:
usb_send_tpdu(false); /* send incomplete PPS to host software using USB */
led_blink(LED_RED, BLINK_2F_O); /* indicate error to user */
usb_send_tpdu(SNIFF_DATA_FLAG_ERROR_INCOMPLETE); /* send incomplete PPS to host software using USB */
change_state(ISO7816_S_WAIT_TPDU);
break;
case ISO7816_S_IN_PPS_REQ:
case ISO7816_S_IN_PPS_RSP:
usb_send_pps(false); /* send incomplete TPDU to host software using USB */
led_blink(LED_RED, BLINK_2F_O); /* indicate error to user */
usb_send_pps(SNIFF_DATA_FLAG_ERROR_INCOMPLETE); /* send incomplete TPDU to host software using USB */
change_state(ISO7816_S_WAIT_TPDU);
break;
default:

View File

@@ -2,6 +2,7 @@
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2008, Atmel Corporation
* Copyright (c) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* All rights reserved.
*
@@ -61,8 +62,10 @@
//------------------------------------------------------------------------------
//
FILE* const stdin = NULL;
FILE* const stdout = NULL;
FILE* const stderr = NULL;
/* If we use NULL here, we get compiler warnings of calling stdio functions with
* NULL values. Our fputs() implementation ignores the value of those pointers anyway */
FILE* const stdout = (FILE *) 0x1;
FILE* const stderr = (FILE *) 0x2;
//------------------------------------------------------------------------------
@@ -76,8 +79,8 @@ FILE* const stderr = NULL;
//------------------------------------------------------------------------------
signed int PutChar(char *pStr, char c)
{
*pStr = c;
return 1;
*pStr = c;
return 1;
}
//------------------------------------------------------------------------------
@@ -89,15 +92,15 @@ signed int PutChar(char *pStr, char c)
//------------------------------------------------------------------------------
signed int PutString(char *pStr, const char *pSource)
{
signed int num = 0;
signed int num = 0;
while (*pSource != 0) {
while (*pSource != 0) {
*pStr++ = *pSource++;
num++;
}
*pStr++ = *pSource++;
num++;
}
return num;
return num;
}
//------------------------------------------------------------------------------
@@ -110,38 +113,38 @@ signed int PutString(char *pStr, const char *pSource)
// \param value Integer value.
//------------------------------------------------------------------------------
signed int PutUnsignedInt(
char *pStr,
char fill,
signed int width,
unsigned int value)
char *pStr,
char fill,
signed int width,
unsigned int value)
{
signed int num = 0;
signed int num = 0;
// Take current digit into account when calculating width
width--;
// Take current digit into account when calculating width
width--;
// Recursively write upper digits
if ((value / 10) > 0) {
// Recursively write upper digits
if ((value / 10) > 0) {
num = PutUnsignedInt(pStr, fill, width, value / 10);
pStr += num;
}
// Write filler characters
else {
num = PutUnsignedInt(pStr, fill, width, value / 10);
pStr += num;
}
// Write filler characters
else {
while (width > 0) {
while (width > 0) {
PutChar(pStr, fill);
pStr++;
num++;
width--;
}
}
PutChar(pStr, fill);
pStr++;
num++;
width--;
}
}
// Write lower digit
num += PutChar(pStr, (value % 10) + '0');
// Write lower digit
num += PutChar(pStr, (value % 10) + '0');
return num;
return num;
}
//------------------------------------------------------------------------------
@@ -154,69 +157,69 @@ signed int PutUnsignedInt(
// \param value Signed integer value.
//------------------------------------------------------------------------------
signed int PutSignedInt(
char *pStr,
char fill,
signed int width,
signed int value)
char *pStr,
char fill,
signed int width,
signed int value)
{
signed int num = 0;
unsigned int absolute;
signed int num = 0;
unsigned int absolute;
// Compute absolute value
if (value < 0) {
// Compute absolute value
if (value < 0) {
absolute = -value;
}
else {
absolute = -value;
}
else {
absolute = value;
}
absolute = value;
}
// Take current digit into account when calculating width
width--;
// Take current digit into account when calculating width
width--;
// Recursively write upper digits
if ((absolute / 10) > 0) {
// Recursively write upper digits
if ((absolute / 10) > 0) {
if (value < 0) {
num = PutSignedInt(pStr, fill, width, -(absolute / 10));
}
else {
if (value < 0) {
num = PutSignedInt(pStr, fill, width, -(absolute / 10));
}
else {
num = PutSignedInt(pStr, fill, width, absolute / 10);
}
pStr += num;
}
else {
num = PutSignedInt(pStr, fill, width, absolute / 10);
}
pStr += num;
}
else {
// Reserve space for sign
if (value < 0) {
// Reserve space for sign
if (value < 0) {
width--;
}
width--;
}
// Write filler characters
while (width > 0) {
// Write filler characters
while (width > 0) {
PutChar(pStr, fill);
pStr++;
num++;
width--;
}
PutChar(pStr, fill);
pStr++;
num++;
width--;
}
// Write sign
if (value < 0) {
// Write sign
if (value < 0) {
num += PutChar(pStr, '-');
pStr++;
}
}
num += PutChar(pStr, '-');
pStr++;
}
}
// Write lower digit
num += PutChar(pStr, (absolute % 10) + '0');
// Write lower digit
num += PutChar(pStr, (absolute % 10) + '0');
return num;
return num;
}
//------------------------------------------------------------------------------
@@ -230,51 +233,51 @@ signed int PutSignedInt(
// \param value Hexadecimal value.
//------------------------------------------------------------------------------
signed int PutHexa(
char *pStr,
char fill,
signed int width,
unsigned char maj,
unsigned int value)
char *pStr,
char fill,
signed int width,
unsigned char maj,
unsigned int value)
{
signed int num = 0;
signed int num = 0;
// Decrement width
width--;
// Decrement width
width--;
// Recursively output upper digits
if ((value >> 4) > 0) {
// Recursively output upper digits
if ((value >> 4) > 0) {
num += PutHexa(pStr, fill, width, maj, value >> 4);
pStr += num;
}
// Write filler chars
else {
num += PutHexa(pStr, fill, width, maj, value >> 4);
pStr += num;
}
// Write filler chars
else {
while (width > 0) {
while (width > 0) {
PutChar(pStr, fill);
pStr++;
num++;
width--;
}
}
PutChar(pStr, fill);
pStr++;
num++;
width--;
}
}
// Write current digit
if ((value & 0xF) < 10) {
// Write current digit
if ((value & 0xF) < 10) {
PutChar(pStr, (value & 0xF) + '0');
}
else if (maj) {
PutChar(pStr, (value & 0xF) + '0');
}
else if (maj) {
PutChar(pStr, (value & 0xF) - 10 + 'A');
}
else {
PutChar(pStr, (value & 0xF) - 10 + 'A');
}
else {
PutChar(pStr, (value & 0xF) - 10 + 'a');
}
num++;
PutChar(pStr, (value & 0xF) - 10 + 'a');
}
num++;
return num;
return num;
}
//------------------------------------------------------------------------------
@@ -292,91 +295,91 @@ signed int PutHexa(
//------------------------------------------------------------------------------
signed int vsnprintf(char *pStr, size_t length, const char *pFormat, va_list ap)
{
char fill;
unsigned char width;
signed int num = 0;
size_t size = 0;
char fill;
unsigned char width;
signed int num = 0;
size_t size = 0;
// Clear the string
if (pStr) {
// Clear the string
if (pStr) {
*pStr = 0;
}
*pStr = 0;
}
// Phase string
while (*pFormat != 0 && size < length) {
// Phase string
while (*pFormat != 0 && size < length) {
// Normal character
if (*pFormat != '%') {
// Normal character
if (*pFormat != '%') {
*pStr++ = *pFormat++;
size++;
}
// Escaped '%'
else if (*(pFormat+1) == '%') {
*pStr++ = *pFormat++;
size++;
}
// Escaped '%'
else if (*(pFormat+1) == '%') {
*pStr++ = '%';
pFormat += 2;
size++;
}
// Token delimiter
else {
*pStr++ = '%';
pFormat += 2;
size++;
}
// Token delimiter
else {
fill = ' ';
width = 0;
pFormat++;
fill = ' ';
width = 0;
pFormat++;
// Parse filler
if (*pFormat == '0') {
// Parse filler
if (*pFormat == '0') {
fill = '0';
pFormat++;
}
fill = '0';
pFormat++;
}
// Parse width
while ((*pFormat >= '0') && (*pFormat <= '9')) {
width = (width*10) + *pFormat-'0';
pFormat++;
}
// Parse width
while ((*pFormat >= '0') && (*pFormat <= '9')) {
width = (width*10) + *pFormat-'0';
pFormat++;
}
// Check if there is enough space
if (size + width > length) {
// Check if there is enough space
if (size + width > length) {
width = length - size;
}
// Parse type
switch (*pFormat) {
case 'd':
case 'i': num = PutSignedInt(pStr, fill, width, va_arg(ap, signed int)); break;
case 'u': num = PutUnsignedInt(pStr, fill, width, va_arg(ap, unsigned int)); break;
case 'x': num = PutHexa(pStr, fill, width, 0, va_arg(ap, unsigned int)); break;
case 'X': num = PutHexa(pStr, fill, width, 1, va_arg(ap, unsigned int)); break;
case 's': num = PutString(pStr, va_arg(ap, char *)); break;
case 'c': num = PutChar(pStr, va_arg(ap, unsigned int)); break;
default:
return EOF;
}
width = length - size;
}
// Parse type
switch (*pFormat) {
case 'd':
case 'i': num = PutSignedInt(pStr, fill, width, va_arg(ap, signed int)); break;
case 'u': num = PutUnsignedInt(pStr, fill, width, va_arg(ap, unsigned int)); break;
case 'x': num = PutHexa(pStr, fill, width, 0, va_arg(ap, unsigned int)); break;
case 'X': num = PutHexa(pStr, fill, width, 1, va_arg(ap, unsigned int)); break;
case 's': num = PutString(pStr, va_arg(ap, char *)); break;
case 'c': num = PutChar(pStr, va_arg(ap, unsigned int)); break;
default:
return EOF;
}
pFormat++;
pStr += num;
size += num;
}
}
pFormat++;
pStr += num;
size += num;
}
}
// NULL-terminated (final \0 is not counted)
if (size < length) {
// NULL-terminated (final \0 is not counted)
if (size < length) {
*pStr = 0;
}
else {
*pStr = 0;
}
else {
*(--pStr) = 0;
size--;
}
*(--pStr) = 0;
size--;
}
return size;
return size;
}
//------------------------------------------------------------------------------
@@ -390,14 +393,14 @@ signed int vsnprintf(char *pStr, size_t length, const char *pFormat, va_list ap)
//------------------------------------------------------------------------------
signed int snprintf(char *pString, size_t length, const char *pFormat, ...)
{
va_list ap;
signed int rc;
va_list ap;
signed int rc;
va_start(ap, pFormat);
rc = vsnprintf(pString, length, pFormat, ap);
va_end(ap);
va_start(ap, pFormat);
rc = vsnprintf(pString, length, pFormat, ap);
va_end(ap);
return rc;
return rc;
}
//------------------------------------------------------------------------------
@@ -410,7 +413,7 @@ signed int snprintf(char *pString, size_t length, const char *pFormat, ...)
//------------------------------------------------------------------------------
signed int vsprintf(char *pString, const char *pFormat, va_list ap)
{
return vsnprintf(pString, MAX_STRING_SIZE, pFormat, ap);
return vsnprintf(pString, MAX_STRING_SIZE, pFormat, ap);
}
//------------------------------------------------------------------------------
@@ -422,19 +425,45 @@ signed int vsprintf(char *pString, const char *pFormat, va_list ap)
//------------------------------------------------------------------------------
signed int vfprintf(FILE *pStream, const char *pFormat, va_list ap)
{
char pStr[MAX_STRING_SIZE];
char pError[] = "stdio.c: increase MAX_STRING_SIZE\n\r";
char pStr[MAX_STRING_SIZE];
char pError[] = "stdio.c: increase MAX_STRING_SIZE\n\r";
// Write formatted string in buffer
if (vsprintf(pStr, pFormat, ap) >= MAX_STRING_SIZE) {
// Write formatted string in buffer
if (vsprintf(pStr, pFormat, ap) >= MAX_STRING_SIZE) {
fputs(pError, stderr);
}
fputs(pError, stderr);
}
// Display string
return fputs(pStr, pStream);
// Display string
return fputs(pStr, pStream);
}
//------------------------------------------------------------------------------
/// Outputs a formatted string on the given stream. Format arguments are given
/// in a va_list instance.
/// \note This function is synchronous (i.e. blocks until the print completes)
/// \param pStream Output stream.
/// \param pFormat Format string
/// \param ap Argument list.
//------------------------------------------------------------------------------
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsuggest-attribute=format"
signed int vfprintf_sync(FILE *pStream, const char *pFormat, va_list ap)
{
char pStr[MAX_STRING_SIZE];
char pError[] = "stdio.c: increase MAX_STRING_SIZE\n\r";
// Write formatted string in buffer
if (vsprintf(pStr, pFormat, ap) >= MAX_STRING_SIZE) {
fputs_sync(pError, stderr);
}
// Display string
return fputs_sync(pStr, pStream);
}
#pragma GCC diagnostic pop
//------------------------------------------------------------------------------
/// Outputs a formatted string on the DBGU stream. Format arguments are given
/// in a va_list instance.
@@ -443,7 +472,19 @@ signed int vfprintf(FILE *pStream, const char *pFormat, va_list ap)
//------------------------------------------------------------------------------
signed int vprintf(const char *pFormat, va_list ap)
{
return vfprintf(stdout, pFormat, ap);
return vfprintf(stdout, pFormat, ap);
}
//------------------------------------------------------------------------------
/// Outputs a formatted string on the DBGU stream. Format arguments are given
/// in a va_list instance.
/// \note This function is synchronous (i.e. blocks until the print completes)
/// \param pFormat Format string
/// \param ap Argument list.
//------------------------------------------------------------------------------
signed int vprintf_sync(const char *pFormat, va_list ap)
{
return vfprintf_sync(stdout, pFormat, ap);
}
//------------------------------------------------------------------------------
@@ -454,15 +495,15 @@ signed int vprintf(const char *pFormat, va_list ap)
//------------------------------------------------------------------------------
signed int fprintf(FILE *pStream, const char *pFormat, ...)
{
va_list ap;
signed int result;
va_list ap;
signed int result;
// Forward call to vfprintf
va_start(ap, pFormat);
result = vfprintf(pStream, pFormat, ap);
va_end(ap);
// Forward call to vfprintf
va_start(ap, pFormat);
result = vfprintf(pStream, pFormat, ap);
va_end(ap);
return result;
return result;
}
//------------------------------------------------------------------------------
@@ -472,15 +513,34 @@ signed int fprintf(FILE *pStream, const char *pFormat, ...)
//------------------------------------------------------------------------------
signed int printf(const char *pFormat, ...)
{
va_list ap;
signed int result;
va_list ap;
signed int result;
// Forward call to vprintf
va_start(ap, pFormat);
result = vprintf(pFormat, ap);
va_end(ap);
// Forward call to vprintf
va_start(ap, pFormat);
result = vprintf(pFormat, ap);
va_end(ap);
return result;
return result;
}
//------------------------------------------------------------------------------
/// Outputs a formatted string on the DBGU stream, using a variable number of
/// arguments.
/// \note This function is synchronous (i.e. blocks until the print completes)
/// \param pFormat Format string.
//------------------------------------------------------------------------------
signed int printf_sync(const char *pFormat, ...)
{
va_list ap;
signed int result;
// Forward call to vprintf
va_start(ap, pFormat);
result = vprintf_sync(pFormat, ap);
va_end(ap);
return result;
}
//------------------------------------------------------------------------------
@@ -490,15 +550,15 @@ signed int printf(const char *pFormat, ...)
//------------------------------------------------------------------------------
signed int sprintf(char *pStr, const char *pFormat, ...)
{
va_list ap;
signed int result;
va_list ap;
signed int result;
// Forward call to vsprintf
va_start(ap, pFormat);
result = vsprintf(pStr, pFormat, ap);
va_end(ap);
// Forward call to vsprintf
va_start(ap, pFormat);
result = vsprintf(pStr, pFormat, ap);
va_end(ap);
return result;
return result;
}
//------------------------------------------------------------------------------
@@ -507,6 +567,6 @@ signed int sprintf(char *pStr, const char *pFormat, ...)
//------------------------------------------------------------------------------
signed int puts(const char *pStr)
{
return fputs(pStr, stdout);
return fputs(pStr, stdout);
}

View File

@@ -61,33 +61,33 @@
//------------------------------------------------------------------------------
void * memcpy(void *pDestination, const void *pSource, size_t num)
{
unsigned char *pByteDestination;
unsigned char *pByteSource;
unsigned int *pAlignedSource = (unsigned int *) pSource;
unsigned int *pAlignedDestination = (unsigned int *) pDestination;
unsigned char *pByteDestination;
unsigned char *pByteSource;
unsigned int *pAlignedSource = (unsigned int *) pSource;
unsigned int *pAlignedDestination = (unsigned int *) pDestination;
// If num is more than 4 bytes, and both dest. and source are aligned,
// then copy dwords
if ((((unsigned int) pAlignedDestination & 0x3) == 0)
&& (((unsigned int) pAlignedSource & 0x3) == 0)
&& (num >= 4)) {
// If num is more than 4 bytes, and both dest. and source are aligned,
// then copy dwords
if ((((unsigned int) pAlignedDestination & 0x3) == 0)
&& (((unsigned int) pAlignedSource & 0x3) == 0)
&& (num >= 4)) {
while (num >= 4) {
while (num >= 4) {
*pAlignedDestination++ = *pAlignedSource++;
num -= 4;
}
}
*pAlignedDestination++ = *pAlignedSource++;
num -= 4;
}
}
// Copy remaining bytes
pByteDestination = (unsigned char *) pAlignedDestination;
pByteSource = (unsigned char *) pAlignedSource;
while (num--) {
// Copy remaining bytes
pByteDestination = (unsigned char *) pAlignedDestination;
pByteSource = (unsigned char *) pAlignedSource;
while (num--) {
*pByteDestination++ = *pByteSource++;
}
*pByteDestination++ = *pByteSource++;
}
return pDestination;
return pDestination;
}
//------------------------------------------------------------------------------
@@ -99,23 +99,23 @@ void * memcpy(void *pDestination, const void *pSource, size_t num)
//------------------------------------------------------------------------------
void * memset(void *pBuffer, int value, size_t num)
{
unsigned char *pByteDestination;
unsigned int *pAlignedDestination = (unsigned int *) pBuffer;
unsigned int alignedValue = (value << 24) | (value << 16) | (value << 8) | value;
unsigned char *pByteDestination;
unsigned int *pAlignedDestination = (unsigned int *) pBuffer;
unsigned int alignedValue = (value << 24) | (value << 16) | (value << 8) | value;
// Set words if possible
if ((((unsigned int) pAlignedDestination & 0x3) == 0) && (num >= 4)) {
while (num >= 4) {
*pAlignedDestination++ = alignedValue;
num -= 4;
}
}
// Set remaining bytes
pByteDestination = (unsigned char *) pAlignedDestination;
while (num--) {
*pByteDestination++ = value;
}
return pBuffer;
// Set words if possible
if ((((unsigned int) pAlignedDestination & 0x3) == 0) && (num >= 4)) {
while (num >= 4) {
*pAlignedDestination++ = alignedValue;
num -= 4;
}
}
// Set remaining bytes
pByteDestination = (unsigned char *) pAlignedDestination;
while (num--) {
*pByteDestination++ = value;
}
return pBuffer;
}
//-----------------------------------------------------------------------------
@@ -126,16 +126,16 @@ void * memset(void *pBuffer, int value, size_t num)
//-----------------------------------------------------------------------------
char * strchr(const char *pString, int character)
{
char * p = (char *)pString;
char c = character & 0xFF;
char * p = (char *)pString;
char c = character & 0xFF;
while(*p != c) {
if (*p == 0) {
return 0;
}
p++;
}
return p;
while(*p != c) {
if (*p == 0) {
return 0;
}
p++;
}
return p;
}
//-----------------------------------------------------------------------------
@@ -144,12 +144,12 @@ char * strchr(const char *pString, int character)
//-----------------------------------------------------------------------------
size_t strlen(const char *pString)
{
unsigned int length = 0;
unsigned int length = 0;
while(*pString++ != 0) {
length++;
}
return length;
while(*pString++ != 0) {
length++;
}
return length;
}
@@ -161,14 +161,14 @@ size_t strlen(const char *pString)
//-----------------------------------------------------------------------------
char * strrchr(const char *pString, int character)
{
char *p = 0;
char *p = 0;
while(*pString != 0) {
if (*pString++ == character) {
p = (char*)pString;
}
}
return p;
while(*pString != 0) {
if (*pString++ == character) {
p = (char*)pString;
}
}
return p;
}
//-----------------------------------------------------------------------------
@@ -179,10 +179,10 @@ char * strrchr(const char *pString, int character)
//-----------------------------------------------------------------------------
char * strcpy(char *pDestination, const char *pSource)
{
char *pSaveDest = pDestination;
char *pSaveDest = pDestination;
for(; (*pDestination = *pSource) != 0; ++pSource, ++pDestination);
return pSaveDest;
for(; (*pDestination = *pSource) != 0; ++pSource, ++pDestination);
return pSaveDest;
}
//-----------------------------------------------------------------------------
@@ -196,22 +196,22 @@ char * strcpy(char *pDestination, const char *pSource)
//-----------------------------------------------------------------------------
int strncmp(const char *pString1, const char *pString2, size_t count)
{
int r;
int r;
while(count) {
r = *pString1 - *pString2;
if (r == 0) {
if (*pString1 == 0) {
break;
}
pString1++;
pString2++;
count--;
continue;
}
return r;
}
return 0;
while(count) {
r = *pString1 - *pString2;
if (r == 0) {
if (*pString1 == 0) {
break;
}
pString1++;
pString2++;
count--;
continue;
}
return r;
}
return 0;
}
//-----------------------------------------------------------------------------
@@ -223,17 +223,17 @@ int strncmp(const char *pString1, const char *pString2, size_t count)
//-----------------------------------------------------------------------------
char * strncpy(char *pDestination, const char *pSource, size_t count)
{
char *pSaveDest = pDestination;
char *pSaveDest = pDestination;
while (count) {
*pDestination = *pSource;
if (*pSource == 0) {
break;
}
pDestination++;
pSource++;
count--;
}
return pSaveDest;
while (count) {
*pDestination = *pSource;
if (*pSource == 0) {
break;
}
pDestination++;
pSource++;
count--;
}
return pSaveDest;
}

View File

@@ -1,23 +1,21 @@
/* SIMtrace TC (Timer / Clock) code for ETU tracking */
/* (C) 2006-2016 by Harald Welte <hwelte@hmw-consulting.de>
/* SIMtrace TC (Timer / Clock) code for ETU tracking
*
* 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.
* (C) 2006-2016 by Harald Welte <laforge@gnumonks.org>
*
* 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.
* 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.
*
* 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
* 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 "utils.h"

View File

@@ -2,6 +2,7 @@
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2009, Atmel Corporation
* Copyright (c) 2018, sysmocom -s.f.m.c. GmbH, Author: Kevin Redon <kredon@sysmocom.de>
*
* All rights reserved.
*
@@ -35,6 +36,7 @@
#include "simtrace.h"
#include "simtrace_usb.h"
#include "utils.h"
#include "USBD_HAL.h"
#include <cciddriverdescriptors.h>
#include <usb/common/dfu/usb_dfu.h>
@@ -576,11 +578,17 @@ void SIMtrace_USB_Initialize(void)
{
/* 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);
mdelay(15);
#endif
USBD_HAL_Suspend();
mdelay(20);
#ifdef PIN_USB_PULLUP
PIO_Clear(&usb_dp_pullup);
#endif
USBD_HAL_Activate();
// Get std USB driver
USBDDriver *pUsbd = USBD_GetDriver();

View File

@@ -1,3 +1,19 @@
/* 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
*/
#include "board.h"
#include "trace.h"
#include "usb_buf.h"

View File

@@ -0,0 +1,632 @@
/*
* (C) 2011 by Harald Welte <laforge@gnumonks.org>
* (C) 2011 by Sylvain Munaut <tnt@246tNt.com>
* (C) 2014 by Nils O. Selåsdal <noselasd@fiane.dyndns.org>
*
* All Rights Reserved
*
* SPDX-License-Identifier: GPL-2.0+
*
* 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 <stdbool.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include <stdio.h>
#include <inttypes.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/bit64gen.h>
/*! \addtogroup utils
* @{
* various utility routines
*
* \file utils.c */
static char namebuf[255];
/*! get human-readable string for given value
* \param[in] vs Array of value_string tuples
* \param[in] val Value to be converted
* \returns pointer to human-readable string
*
* If val is found in vs, the array's string entry is returned. Otherwise, an
* "unknown" string containing the actual value is composed in a static buffer
* that is reused across invocations.
*/
const char *get_value_string(const struct value_string *vs, uint32_t val)
{
const char *str = get_value_string_or_null(vs, val);
if (str)
return str;
snprintf(namebuf, sizeof(namebuf), "unknown 0x%"PRIx32, val);
namebuf[sizeof(namebuf) - 1] = '\0';
return namebuf;
}
/*! get human-readable string or NULL for given value
* \param[in] vs Array of value_string tuples
* \param[in] val Value to be converted
* \returns pointer to human-readable string or NULL if val is not found
*/
const char *get_value_string_or_null(const struct value_string *vs,
uint32_t val)
{
int i;
for (i = 0;; i++) {
if (vs[i].value == 0 && vs[i].str == NULL)
break;
if (vs[i].value == val)
return vs[i].str;
}
return NULL;
}
/*! get numeric value for given human-readable string
* \param[in] vs Array of value_string tuples
* \param[in] str human-readable string
* \returns numeric value (>0) or negative numer in case of error
*/
int get_string_value(const struct value_string *vs, const char *str)
{
int i;
for (i = 0;; i++) {
if (vs[i].value == 0 && vs[i].str == NULL)
break;
if (!strcasecmp(vs[i].str, str))
return vs[i].value;
}
return -EINVAL;
}
/*! Convert BCD-encoded digit into printable character
* \param[in] bcd A single BCD-encoded digit
* \returns single printable character
*/
char osmo_bcd2char(uint8_t bcd)
{
if (bcd < 0xa)
return '0' + bcd;
else
return 'A' + (bcd - 0xa);
}
/*! Convert number in ASCII to BCD value
* \param[in] c ASCII character
* \returns BCD encoded value of character
*/
uint8_t osmo_char2bcd(char c)
{
if (c >= '0' && c <= '9')
return c - 0x30;
else if (c >= 'A' && c <= 'F')
return 0xa + (c - 'A');
else if (c >= 'a' && c <= 'f')
return 0xa + (c - 'a');
else
return 0;
}
/*! Parse a string containing hexadecimal digits
* \param[in] str string containing ASCII encoded hexadecimal digits
* \param[out] b output buffer
* \param[in] max_len maximum space in output buffer
* \returns number of parsed octets, or -1 on error
*/
int osmo_hexparse(const char *str, uint8_t *b, int max_len)
{
char c;
uint8_t v;
const char *strpos;
unsigned int nibblepos = 0;
memset(b, 0x00, max_len);
for (strpos = str; (c = *strpos); strpos++) {
/* skip whitespace */
if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
continue;
/* If the buffer is too small, error out */
if (nibblepos >= (max_len << 1))
return -1;
if (c >= '0' && c <= '9')
v = c - '0';
else if (c >= 'a' && c <= 'f')
v = 10 + (c - 'a');
else if (c >= 'A' && c <= 'F')
v = 10 + (c - 'A');
else
return -1;
b[nibblepos >> 1] |= v << (nibblepos & 1 ? 0 : 4);
nibblepos ++;
}
/* In case of uneven amount of digits, the last byte is not complete
* and that's an error. */
if (nibblepos & 1)
return -1;
return nibblepos >> 1;
}
static char hexd_buff[4096];
static const char hex_chars[] = "0123456789abcdef";
static char *_osmo_hexdump(const unsigned char *buf, int len, const char *delim)
{
int i;
char *cur = hexd_buff;
hexd_buff[0] = 0;
for (i = 0; i < len; i++) {
const char *delimp = delim;
int len_remain = sizeof(hexd_buff) - (cur - hexd_buff);
if (len_remain < 3)
break;
*cur++ = hex_chars[buf[i] >> 4];
*cur++ = hex_chars[buf[i] & 0xf];
while (len_remain > 1 && *delimp) {
*cur++ = *delimp++;
len_remain--;
}
*cur = 0;
}
hexd_buff[sizeof(hexd_buff)-1] = 0;
return hexd_buff;
}
/*! Convert a sequence of unpacked bits to ASCII string
* \param[in] bits A sequence of unpacked bits
* \param[in] len Length of bits
*/
char *osmo_ubit_dump(const uint8_t *bits, unsigned int len)
{
int i;
if (len > sizeof(hexd_buff)-1)
len = sizeof(hexd_buff)-1;
memset(hexd_buff, 0, sizeof(hexd_buff));
for (i = 0; i < len; i++) {
char outch;
switch (bits[i]) {
case 0:
outch = '0';
break;
case 0xff:
outch = '?';
break;
case 1:
outch = '1';
break;
default:
outch = 'E';
break;
}
hexd_buff[i] = outch;
}
hexd_buff[sizeof(hexd_buff)-1] = 0;
return hexd_buff;
}
/*! Convert binary sequence to hexadecimal ASCII string
* \param[in] buf pointer to sequence of bytes
* \param[in] len length of buf in number of bytes
* \returns pointer to zero-terminated string
*
* This function will print a sequence of bytes as hexadecimal numbers,
* adding one space character between each byte (e.g. "1a ef d9")
*
* The maximum size of the output buffer is 4096 bytes, i.e. the maximum
* number of input bytes that can be printed in one call is 1365!
*/
char *osmo_hexdump(const unsigned char *buf, int len)
{
return _osmo_hexdump(buf, len, " ");
}
/*! Convert binary sequence to hexadecimal ASCII string
* \param[in] buf pointer to sequence of bytes
* \param[in] len length of buf in number of bytes
* \returns pointer to zero-terminated string
*
* This function will print a sequence of bytes as hexadecimal numbers,
* without any space character between each byte (e.g. "1aefd9")
*
* The maximum size of the output buffer is 4096 bytes, i.e. the maximum
* number of input bytes that can be printed in one call is 2048!
*/
char *osmo_hexdump_nospc(const unsigned char *buf, int len)
{
return _osmo_hexdump(buf, len, "");
}
/* Compat with previous typo to preserve abi */
char *osmo_osmo_hexdump_nospc(const unsigned char *buf, int len)
#if defined(__MACH__) && defined(__APPLE__)
;
#else
__attribute__((weak, alias("osmo_hexdump_nospc")));
#endif
#include <ctype.h>
/*! Convert an entire string to lower case
* \param[out] out output string, caller-allocated
* \param[in] in input string
*/
void osmo_str2lower(char *out, const char *in)
{
unsigned int i;
for (i = 0; i < strlen(in); i++)
out[i] = tolower((const unsigned char)in[i]);
out[strlen(in)] = '\0';
}
/*! Convert an entire string to upper case
* \param[out] out output string, caller-allocated
* \param[in] in input string
*/
void osmo_str2upper(char *out, const char *in)
{
unsigned int i;
for (i = 0; i < strlen(in); i++)
out[i] = toupper((const unsigned char)in[i]);
out[strlen(in)] = '\0';
}
/*! Wishful thinking to generate a constant time compare
* \param[in] exp Expected data
* \param[in] rel Comparison value
* \param[in] count Number of bytes to compare
* \returns 1 in case \a exp equals \a rel; zero otherwise
*
* Compare count bytes of exp to rel. Return 0 if they are identical, 1
* otherwise. Do not return a mismatch on the first mismatching byte,
* but always compare all bytes, regardless. The idea is that the amount of
* matching bytes cannot be inferred from the time the comparison took. */
int osmo_constant_time_cmp(const uint8_t *exp, const uint8_t *rel, const int count)
{
int x = 0, i;
for (i = 0; i < count; ++i)
x |= exp[i] ^ rel[i];
/* if x is zero, all data was identical */
return x? 1 : 0;
}
/*! Generic retrieval of 1..8 bytes as big-endian uint64_t
* \param[in] data Input data as byte-array
* \param[in] data_len Length of \a data in octets
* \returns uint64_t of \a data interpreted as big-endian
*
* This is like osmo_load64be_ext, except that if data_len is less than
* sizeof(uint64_t), the data is interpreted as the least significant bytes
* (osmo_load64be_ext loads them as the most significant bytes into the
* returned uint64_t). In this way, any integer size up to 64 bits can be
* decoded conveniently by using sizeof(), without the need to call specific
* numbered functions (osmo_load16, 32, ...). */
uint64_t osmo_decode_big_endian(const uint8_t *data, size_t data_len)
{
uint64_t value = 0;
while (data_len > 0) {
value = (value << 8) + *data;
data += 1;
data_len -= 1;
}
return value;
}
/*! Generic big-endian encoding of big endian number up to 64bit
* \param[in] value unsigned integer value to be stored
* \param[in] data_len number of octets
* \returns static buffer containing big-endian stored value
*
* This is like osmo_store64be_ext, except that this returns a static buffer of
* the result (for convenience, but not threadsafe). If data_len is less than
* sizeof(uint64_t), only the least significant bytes of value are encoded. */
uint8_t *osmo_encode_big_endian(uint64_t value, size_t data_len)
{
static uint8_t buf[sizeof(uint64_t)];
OSMO_ASSERT(data_len <= ARRAY_SIZE(buf));
osmo_store64be_ext(value, buf, data_len);
return buf;
}
/*! Copy a C-string into a sized buffer
* \param[in] src source string
* \param[out] dst destination string
* \param[in] siz size of the \a dst buffer
* \returns length of \a src
*
* Copy at most \a siz bytes from \a src to \a dst, ensuring that the result is
* NUL terminated. The NUL character is included in \a siz, i.e. passing the
* actual sizeof(*dst) is correct.
*/
size_t osmo_strlcpy(char *dst, const char *src, size_t siz)
{
size_t ret = src ? strlen(src) : 0;
if (siz) {
size_t len = (ret >= siz) ? siz - 1 : ret;
if (src)
memcpy(dst, src, len);
dst[len] = '\0';
}
return ret;
}
/*! Validate that a given string is a hex string within given size limits.
* Note that each hex digit amounts to a nibble, so if checking for a hex
* string to result in N bytes, pass amount of digits as 2*N.
* \param str A nul-terminated string to validate, or NULL.
* \param min_digits least permitted amount of digits.
* \param max_digits most permitted amount of digits.
* \param require_even if true, require an even amount of digits.
* \returns true when the hex_str contains only hexadecimal digits (no
* whitespace) and matches the requested length; also true
* when min_digits <= 0 and str is NULL.
*/
bool osmo_is_hexstr(const char *str, int min_digits, int max_digits,
bool require_even)
{
int len;
/* Use unsigned char * to avoid a compiler warning of
* "error: array subscript has type 'char' [-Werror=char-subscripts]" */
const unsigned char *pos = (const unsigned char*)str;
if (!pos)
return min_digits < 1;
for (len = 0; *pos && len < max_digits; len++, pos++)
if (!isxdigit(*pos))
return false;
if (len < min_digits)
return false;
/* With not too many digits, we should have reached *str == nul */
if (*pos)
return false;
if (require_even && (len & 1))
return false;
return true;
}
/*! Determine if a given identifier is valid, i.e. doesn't contain illegal chars
* \param[in] str String to validate
* \param[in] sep_chars Permitted separation characters between identifiers.
* \returns true in case \a str contains only valid identifiers and sep_chars, false otherwise
*/
bool osmo_separated_identifiers_valid(const char *str, const char *sep_chars)
{
/* characters that are illegal in names */
static const char illegal_chars[] = "., {}[]()<>|~\\^`'\"?=;/+*&%$#!";
unsigned int i;
size_t len;
/* an empty string is not a valid identifier */
if (!str || (len = strlen(str)) == 0)
return false;
for (i = 0; i < len; i++) {
if (sep_chars && strchr(sep_chars, str[i]))
continue;
/* check for 7-bit ASCII */
if (str[i] & 0x80)
return false;
if (!isprint((int)str[i]))
return false;
/* check for some explicit reserved control characters */
if (strchr(illegal_chars, str[i]))
return false;
}
return true;
}
/*! Determine if a given identifier is valid, i.e. doesn't contain illegal chars
* \param[in] str String to validate
* \returns true in case \a str contains valid identifier, false otherwise
*/
bool osmo_identifier_valid(const char *str)
{
return osmo_separated_identifiers_valid(str, NULL);
}
/*! Return the string with all non-printable characters escaped.
* \param[in] str A string that may contain any characters.
* \param[in] len Pass -1 to print until nul char, or >= 0 to force a length.
* \param[inout] buf string buffer to write escaped characters to.
* \param[in] bufsize size of \a buf.
* \returns buf containing an escaped representation, possibly truncated, or str itself.
*/
const char *osmo_escape_str_buf(const char *str, int in_len, char *buf, size_t bufsize)
{
int in_pos = 0;
int next_unprintable = 0;
int out_pos = 0;
char *out = buf;
/* -1 to leave space for a final \0 */
int out_len = bufsize-1;
if (!str)
return "(null)";
if (in_len < 0)
in_len = strlen(str);
while (in_pos < in_len) {
for (next_unprintable = in_pos;
next_unprintable < in_len && isprint((int)str[next_unprintable])
&& str[next_unprintable] != '"'
&& str[next_unprintable] != '\\';
next_unprintable++);
if (next_unprintable == in_len
&& in_pos == 0)
return str;
while (in_pos < next_unprintable && out_pos < out_len)
out[out_pos++] = str[in_pos++];
if (out_pos == out_len || in_pos == in_len)
goto done;
switch (str[next_unprintable]) {
#define BACKSLASH_CASE(c, repr) \
case c: \
if (out_pos > out_len-2) \
goto done; \
out[out_pos++] = '\\'; \
out[out_pos++] = repr; \
break
BACKSLASH_CASE('\n', 'n');
BACKSLASH_CASE('\r', 'r');
BACKSLASH_CASE('\t', 't');
BACKSLASH_CASE('\0', '0');
BACKSLASH_CASE('\a', 'a');
BACKSLASH_CASE('\b', 'b');
BACKSLASH_CASE('\v', 'v');
BACKSLASH_CASE('\f', 'f');
BACKSLASH_CASE('\\', '\\');
BACKSLASH_CASE('"', '"');
#undef BACKSLASH_CASE
default:
out_pos += snprintf(&out[out_pos], out_len - out_pos, "\\%u", (unsigned char)str[in_pos]);
if (out_pos > out_len) {
out_pos = out_len;
goto done;
}
break;
}
in_pos ++;
}
done:
out[out_pos] = '\0';
return out;
}
/*! Return the string with all non-printable characters escaped.
* Call osmo_escape_str_buf() with a static buffer.
* \param[in] str A string that may contain any characters.
* \param[in] len Pass -1 to print until nul char, or >= 0 to force a length.
* \returns buf containing an escaped representation, possibly truncated, or str itself.
*/
const char *osmo_escape_str(const char *str, int in_len)
{
return osmo_escape_str_buf(str, in_len, namebuf, sizeof(namebuf));
}
/*! Like osmo_escape_str(), but returns double-quotes around a string, or "NULL" for a NULL string.
* This allows passing any char* value and get its C representation as string.
* \param[in] str A string that may contain any characters.
* \param[in] len Pass -1 to print until nul char, or >= 0 to force a length.
* \returns buf containing an escaped representation, possibly truncated, or str itself.
*/
const char *osmo_quote_str_buf(const char *str, int in_len, char *buf, size_t bufsize)
{
const char *res;
int l;
if (!str)
return "NULL";
if (bufsize < 3)
return "<buf-too-small>";
buf[0] = '"';
res = osmo_escape_str_buf(str, in_len, buf + 1, bufsize - 2);
/* if osmo_escape_str_buf() returned the str itself, we need to copy it to buf to be able to
* quote it. */
if (res == str) {
/* max_len = bufsize - two quotes - nul term */
int max_len = bufsize - 2 - 1;
if (in_len >= 0)
max_len = OSMO_MIN(in_len, max_len);
/* It is not allowed to pass unterminated strings into osmo_strlcpy() :/ */
strncpy(buf + 1, str, max_len);
buf[1 + max_len] = '\0';
}
l = strlen(buf);
buf[l] = '"';
buf[l+1] = '\0'; /* both osmo_escape_str_buf() and max_len above ensure room for '\0' */
return buf;
}
const char *osmo_quote_str(const char *str, int in_len)
{
return osmo_quote_str_buf(str, in_len, namebuf, sizeof(namebuf));
}
/*! perform an integer square root operation on unsigned 32bit integer.
* This implementation is taken from "Hacker's Delight" Figure 11-1 "Integer square root, Newton's
* method", which can also be found at http://www.hackersdelight.org/hdcodetxt/isqrt.c.txt */
uint32_t osmo_isqrt32(uint32_t x)
{
uint32_t x1;
int s, g0, g1;
if (x <= 1)
return x;
s = 1;
x1 = x - 1;
if (x1 > 0xffff) {
s = s + 8;
x1 = x1 >> 16;
}
if (x1 > 0xff) {
s = s + 4;
x1 = x1 >> 8;
}
if (x1 > 0xf) {
s = s + 2;
x1 = x1 >> 4;
}
if (x1 > 0x3) {
s = s + 1;
}
g0 = 1 << s; /* g0 = 2**s */
g1 = (g0 + (x >> s)) >> 1; /* g1 = (g0 + x/g0)/2 */
/* converges after four to five divisions for arguments up to 16,785,407 */
while (g1 < g0) {
g0 = g1;
g1 = (g0 + (x/g0)) >> 1;
}
return g0;
}
/*! @} */

View File

@@ -65,6 +65,11 @@ void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx)
printf("uart_enable(uart_chan=%u, %s)\n", uart_chan, rts);
}
void card_emu_uart_interrupt(uint8_t uart_chan)
{
printf("uart_interrupt(uart_chan=%u)\n", uart_chan);
}
void tc_etu_set_wtime(uint8_t tc_chan, uint16_t wtime)
{
printf("tc_etu_set_wtime(tc_chan=%u, wtime=%u)\n", tc_chan, wtime);
@@ -120,6 +125,8 @@ static void io_start_card(struct card_handle *ch)
/* release from reset and verify th ATR */
card_emu_io_statechg(ch, CARD_IO_RST, 0);
/* simulate waiting time before ATR expired */
tc_etu_wtime_expired(ch);
verify_atr(ch);
}

View File

@@ -1,7 +1,9 @@
LDFLAGS=`pkg-config --libs libusb-1.0 libosmocore` -losmocore
CFLAGS=-Wall -g
all: simtrace2-remsim simtrace2-remsim-usb2udp simtrace2-list simtrace2-sniff
APPS=simtrace2-remsim simtrace2-remsim-usb2udp simtrace2-list simtrace2-sniff
all: $(APPS)
simtrace2-remsim: simtrace2-remsim.o apdu_dispatch.o simtrace2-discovery.o libusb_util.o
$(CC) -o $@ $^ $(LDFLAGS) -losmosim
@@ -19,4 +21,8 @@ simtrace2-sniff: simtrace2-sniff.o simtrace2-discovery.o libusb_util.o
$(CC) $(CFLAGS) `pkg-config --cflags libusb-1.0 libosmocore` -o $@ -c $^
clean:
@rm -f simtrace2-remsim simtrace2-remsim-usb2udp simtrace2-list *.o
@rm -f *.o $(APPS)
install: $(APPS)
mkdir -p $(DESTDIR)/usr/bin
cp $(APPS) $(DESTDIR)/usr/bin/

View File

@@ -2,20 +2,20 @@
*
* (C) 2016 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 version 2
* as published by the Free Software Foundation
* 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.
* 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
* 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 <stdlib.h>
#include <string.h>

View File

@@ -1,3 +1,21 @@
/* apdu_dispatch - State machine to determine Rx/Tx phases of APDU
*
* (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#pragma once
#include <stdint.h>

View File

@@ -1,3 +1,21 @@
/* libisb utilities
*
* (C) 2010-2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
@@ -232,34 +250,39 @@ libusb_device_handle *usb_open_claim_interface(libusb_context *ctx,
(strlen(ifm->path) && !strcmp(path, ifm->path))) {
rc = libusb_open(*dev, &usb_devh);
if (rc < 0) {
perror("Cannot open device");
fprintf(stderr, "Cannot open device: %s\n", libusb_error_name(rc));
usb_devh = NULL;
break;
}
rc = libusb_get_configuration(usb_devh, &config);
if (rc < 0) {
perror("Cannot get current configuration");
fprintf(stderr, "Cannot get current configuration: %s\n", libusb_error_name(rc));
libusb_close(usb_devh);
usb_devh = NULL;
break;
}
if (config != ifm->configuration) {
rc = libusb_set_configuration(usb_devh, ifm->configuration);
if (rc < 0) {
perror("Cannot set configuration");
fprintf(stderr, "Cannot set configuration: %s\n", libusb_error_name(rc));
libusb_close(usb_devh);
usb_devh = NULL;
break;
}
}
rc = libusb_claim_interface(usb_devh, ifm->interface);
if (rc < 0) {
perror("Cannot claim interface");
fprintf(stderr, "Cannot claim interface: %s\n", libusb_error_name(rc));
libusb_close(usb_devh);
usb_devh = NULL;
break;
}
rc = libusb_set_interface_alt_setting(usb_devh, ifm->interface, ifm->altsetting);
if (rc < 0) {
perror("Cannot set interface altsetting");
fprintf(stderr, "Cannot set interface altsetting: %s\n", libusb_error_name(rc));
libusb_release_interface(usb_devh, ifm->interface);
libusb_close(usb_devh);
usb_devh = NULL;
break;
}
}

View File

@@ -1,3 +1,21 @@
/* libisb utilities
*
* (C) 2010-2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#pragma once
#include <libusb.h>

View File

@@ -1,3 +1,22 @@
/* simtrace2-discovery - host PC library to scan for matching USB
* devices
*
* (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdint.h>
#include <libusb.h>

View File

@@ -1,3 +1,22 @@
/* simtrace2-discovery - host PC library to scan for matching USB
* devices
*
* (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#pragma once
#include <stdint.h>

View File

@@ -1,21 +1,22 @@
/* simtrace2-remsim - main program for the host PC
/* simtrace2-remsim - main program for the host PC to provide a remote SIM
* using the SIMtrace 2 firmware in card emulation mode
*
* (C) 2010-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2016 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 version 2
* as published by the Free Software Foundation
* 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.
* 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
* 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 <errno.h>
#include <unistd.h>
#include <stdio.h>
@@ -172,16 +173,11 @@ static struct simtrace_msg_hdr *st_push_hdr(struct msgb *msg, uint8_t msg_class,
int st_slot_tx_msg(struct st_slot *slot, struct msgb *msg,
uint8_t msg_class, uint8_t msg_type)
{
struct simtrace_msg_hdr *sh = (struct simtrace_msg_hdr *) msg->data;
sh->slot_nr = slot->slot_nr;
st_push_hdr(msg, msg_class, msg_type, slot->slot_nr);
return st_transp_tx_msg(slot->transp, msg);
}
/***********************************************************************
* Card Emulation protocol
***********************************************************************/
@@ -540,7 +536,7 @@ static void run_mainloop(struct cardem_inst *ci)
/* read data from SIMtrace2 device (local or via USB) */
if (transp->udp_fd < 0) {
rc = libusb_bulk_transfer(transp->usb_devh, transp->usb_ep.in,
buf, sizeof(buf), &xfer_len, 100000);
buf, sizeof(buf), &xfer_len, 100);
if (rc < 0 && rc != LIBUSB_ERROR_TIMEOUT &&
rc != LIBUSB_ERROR_INTERRUPTED &&
rc != LIBUSB_ERROR_IO) {
@@ -557,7 +553,7 @@ static void run_mainloop(struct cardem_inst *ci)
}
/* dispatch any incoming data */
if (xfer_len > 0) {
printf("URB: %s\n", osmo_hexdump(buf, rc));
printf("URB: %s\n", osmo_hexdump(buf, xfer_len));
process_usb_msg(ci, buf, xfer_len);
msg_count++;
byte_count += xfer_len;

View File

@@ -1,7 +1,13 @@
/* simtrace2-sniff - main program for the host PC to communicate with the SIMtrace 2 firmware in sniffer mode */
/* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation
/* simtrace2-sniff - main program for the host PC to communicate with the
* SIMtrace 2 firmware in sniffer mode
*
* (C) 2016 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
@@ -10,12 +16,8 @@
*
* 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
*
* (C) 2010-2017 by Harald Welte <hwelte@hmw-consulting.de>
* (C) 2018 by Kevin Redon <kredon@sysmocom.de>
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
@@ -63,7 +65,7 @@ struct st_transport {
/* global GSMTAP instance */
static struct gsmtap_inst *g_gti;
static int gsmtap_send_sim(const uint8_t *apdu, unsigned int len)
static int gsmtap_send_sim(uint8_t sub_type, const uint8_t *data, unsigned int len)
{
struct gsmtap_hdr *gh;
unsigned int gross_len = len + sizeof(*gh);
@@ -78,8 +80,9 @@ static int gsmtap_send_sim(const uint8_t *apdu, unsigned int len)
gh->version = GSMTAP_VERSION;
gh->hdr_len = sizeof(*gh)/4;
gh->type = GSMTAP_TYPE_SIM;
gh->sub_type = sub_type;
memcpy(buf + sizeof(*gh), apdu, len);
memcpy(buf + sizeof(*gh), data, len);
rc = write(gsmtap_inst_fd(g_gti), buf, gross_len);
if (rc < 0) {
@@ -92,31 +95,80 @@ static int gsmtap_send_sim(const uint8_t *apdu, unsigned int len)
return 0;
}
const struct value_string change_flags[] = {
{
.value = SNIFF_CHANGE_FLAG_CARD_INSERT,
.str = "card inserted",
},
{
.value = SNIFF_CHANGE_FLAG_CARD_EJECT,
.str = "card ejected",
},
{
.value = SNIFF_CHANGE_FLAG_RESET_ASSERT,
.str = "reset asserted",
},
{
.value = SNIFF_CHANGE_FLAG_RESET_DEASSERT,
.str = "reset de-asserted",
},
{
.value = SNIFF_CHANGE_FLAG_TIMEOUT_WT,
.str = "data transfer timeout",
},
{
.value = 0,
.str = NULL,
},
};
const struct value_string data_flags[] = {
{
.value = SNIFF_DATA_FLAG_ERROR_INCOMPLETE,
.str = "incomplete",
},
{
.value = SNIFF_DATA_FLAG_ERROR_MALFORMED,
.str = "malformed",
},
{
.value = SNIFF_DATA_FLAG_ERROR_CHECKSUM,
.str = "checksum error",
},
{
.value = 0,
.str = NULL,
},
};
static void print_flags(const struct value_string* flag_meanings, uint32_t nb_flags, uint32_t flags) {
uint32_t i;
for (i = 0; i < nb_flags; i++) {
if (flags & flag_meanings[i].value) {
printf(flag_meanings[i].str);
flags &= ~flag_meanings[i].value;
if (flags) {
printf(", ");
}
}
}
}
static int process_change(const uint8_t *buf, int len)
{
/* check if there is enough data for the structure */
if (len<sizeof(struct sniff_change)) {
if (len < sizeof(struct sniff_change)) {
return -1;
}
struct sniff_change *change = (struct sniff_change *)buf;
printf("Card state change: ");
if (change->flags&SNIFF_CHANGE_FLAG_CARD_INSERT) {
printf("card inserted ");
if (change->flags) {
print_flags(change_flags, ARRAY_SIZE(change_flags), change->flags);
printf("\n");
} else {
printf("no changes\n");
}
if (change->flags&SNIFF_CHANGE_FLAG_CARD_EJECT) {
printf("card ejected ");
}
if (change->flags&SNIFF_CHANGE_FLAG_RESET_HOLD) {
printf("reset hold ");
}
if (change->flags&SNIFF_CHANGE_FLAG_RESET_RELEASE) {
printf("reset release ");
}
if (change->flags&SNIFF_CHANGE_FLAG_TIMEOUT_WT) {
printf("data transfer timeout ");
}
printf("\n");
return 0;
}
@@ -139,70 +191,64 @@ static int process_fidi(const uint8_t *buf, int len)
return 0;
}
static int process_atr(const uint8_t *buf, int len)
static int process_data(enum simtrace_msg_type_sniff type, const uint8_t *buf, int len)
{
/* check if there is enough data for the structure */
if (len<sizeof(struct sniff_data)) {
if (len < sizeof(struct sniff_data)) {
return -1;
}
struct sniff_data *atr = (struct sniff_data *)buf;
struct sniff_data *data = (struct sniff_data *)buf;
/* check if the data is available */
if (len<sizeof(struct sniff_data)+atr->length) {
if (len < sizeof(struct sniff_data) + data->length) {
return -2;
}
printf("ATR%s: ", atr->complete ? "" : " (incomplete)");
for (uint16_t i=0; i<atr->length; i++) {
printf("%02x ", atr->data[i]);
}
printf("\n");
return 0;
}
static int process_pps(const uint8_t *buf, int len)
{
/* check if there is enough data for the structure */
if (len<sizeof(struct sniff_data)) {
return -1;
}
struct sniff_data *pps = (struct sniff_data *)buf;
/* check if the data is available */
if (len<sizeof(struct sniff_data)+pps->length) {
return -2;
/* check type */
if (type != SIMTRACE_MSGT_SNIFF_ATR && type != SIMTRACE_MSGT_SNIFF_PPS && type != SIMTRACE_MSGT_SNIFF_TPDU) {
return -3;
}
printf("PPS%s: ", pps->complete ? "" : " (incomplete) ");
for (uint16_t i=0; i<pps->length; i++) {
printf("%02x ", pps->data[i]);
/* Print message */
switch (type) {
case SIMTRACE_MSGT_SNIFF_ATR:
printf("ATR");
break;
case SIMTRACE_MSGT_SNIFF_PPS:
printf("PPS");
break;
case SIMTRACE_MSGT_SNIFF_TPDU:
printf("TPDU");
break;
default:
printf("???");
break;
}
printf("\n");
return 0;
}
static int process_tpdu(const uint8_t *buf, int len)
{
/* check if there is enough data for the structure */
if (len<sizeof(struct sniff_data)) {
return -1;
if (data->flags) {
printf(" (");
print_flags(data_flags, ARRAY_SIZE(data_flags), data->flags);
printf(")");
}
struct sniff_data *tpdu = (struct sniff_data *)buf;
/* check if the data is available */
if (len<sizeof(struct sniff_data)+tpdu->length) {
return -2;
}
/* print TPDU */
printf("TPDU%s: ", tpdu->complete ? "" : " (incomplete)");
for (uint16_t i=0; i<tpdu->length; i++) {
printf("%02x ", tpdu->data[i]);
printf(": ");
uint16_t i;
for (i = 0; i < data->length; i++) {
printf("%02x ", data->data[i]);
}
printf("\n");
/* send TPDU (now considered as APDU) to GSMTAP */
gsmtap_send_sim(tpdu->data, tpdu->length);
/* Send message as GSNTAP */
switch (type) {
case SIMTRACE_MSGT_SNIFF_ATR:
gsmtap_send_sim(GSMTAP_SIM_ATR, data->data, data->length);
break;
case SIMTRACE_MSGT_SNIFF_TPDU:
/* TPDU is now considered as APDU since SIMtrace sends complete TPDU */
gsmtap_send_sim(GSMTAP_SIM_APDU, data->data, data->length);
break;
default:
break;
}
return 0;
}
@@ -210,19 +256,19 @@ static int process_tpdu(const uint8_t *buf, int len)
static int process_usb_msg(const uint8_t *buf, int len)
{
/* check if enough data for the header is present */
if (len<sizeof(struct simtrace_msg_hdr)) {
if (len < sizeof(struct simtrace_msg_hdr)) {
return 0;
}
/* check if message is complete */
struct simtrace_msg_hdr *msg_hdr = (struct simtrace_msg_hdr *)buf;
if (len<msg_hdr->msg_len) {
if (len < msg_hdr->msg_len) {
return 0;
}
//printf("msg: %s\n", osmo_hexdump(buf, msg_hdr->msg_len));
/* check for message class */
if (SIMTRACE_MSGC_SNIFF!=msg_hdr->msg_class) { /* we only care about sniffing messages */
if (SIMTRACE_MSGC_SNIFF != msg_hdr->msg_class) { /* we only care about sniffing messages */
return msg_hdr->msg_len; /* discard non-sniffing messaged */
}
@@ -237,13 +283,9 @@ static int process_usb_msg(const uint8_t *buf, int len)
process_fidi(buf, len);
break;
case SIMTRACE_MSGT_SNIFF_ATR:
process_atr(buf, len);
break;
case SIMTRACE_MSGT_SNIFF_PPS:
process_pps(buf, len);
break;
case SIMTRACE_MSGT_SNIFF_TPDU:
process_tpdu(buf, len);
process_data(msg_hdr->msg_type, buf, len);
break;
default:
printf("unknown SIMtrace msg type 0x%02x\n", msg_hdr->msg_type);
@@ -260,7 +302,7 @@ static void run_mainloop()
{
int rc;
uint8_t buf[16*256];
unsigned int buf_i = 0;
unsigned int i, buf_i = 0;
int xfer_len;
printf("Entering main loop\n");
@@ -279,13 +321,16 @@ static void run_mainloop()
if (xfer_len > 0) {
//printf("URB: %s\n", osmo_hexdump(&buf[buf_i], xfer_len));
buf_i += xfer_len;
if (buf_i>=sizeof(buf)) {
if (buf_i >= sizeof(buf)) {
perror("preventing USB buffer overflow");
return;
}
int processed = process_usb_msg(buf, buf_i);
if (processed>0 && processed<=buf_i) {
for (unsigned int i=processed; i<buf_i; i++) {
int processed;
while ((processed = process_usb_msg(buf, buf_i)) > 0) {
if (processed > buf_i) {
break;
}
for (i = processed; i < buf_i; i++) {
buf[i-processed] = buf[i];
}
buf_i -= processed;
@@ -351,7 +396,7 @@ static void signal_handler(int signal)
int main(int argc, char **argv)
{
int rc, ret;
int i, rc, ret;
print_welcome();
/* Parse arguments */
@@ -414,7 +459,7 @@ int main(int argc, char **argv)
/* Only keep USB matching arguments */
struct usb_interface_match ifm_filtered[ARRAY_SIZE(ifm_scan)];
int num_filtered = 0;
for (unsigned int i = 0; i < num_interfaces; i++) {
for (i = 0; i < num_interfaces; i++) {
if (vendor_id>=0 && vendor_id!=ifm_scan[i].vendor) {
continue;
}
@@ -438,7 +483,7 @@ int main(int argc, char **argv)
if (1!=num_filtered) {
perror("No individual matching USB devices found");
printf("Available USB devices:\n");
for (unsigned int i = 0; i < num_interfaces; i++) {
for (i = 0; i < num_interfaces; i++) {
printf("\t%04x:%04x Addr=%u, Path=%s, Cfg=%u, Intf=%u, Alt=%u: %d/%d/%d ",
ifm_scan[i].vendor, ifm_scan[i].product, ifm_scan[i].addr, ifm_scan[i].path,
ifm_scan[i].configuration, ifm_scan[i].interface, ifm_scan[i].altsetting,

View File

@@ -1,3 +1,21 @@
/* simtrace2_usb - host PC application to list found SIMtrace 2 USB devices
*
* (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

View File

@@ -2,20 +2,20 @@
*
* (C) 2010-2016 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 version 2
* as published by the Free Software Foundation
* 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.
* 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
* 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 <errno.h>
#include <unistd.h>
#include <stdio.h>